import 'package:json_annotation/json_annotation.dart';

/// Created by Haoyi on 2021/7/28
///

part "account_profile.g.dart";

class AccountRole {
  static const normal = 0;
  static const tester = 10;
  static const machine = 100;
}

// 这里没有使用genericArgumentFactories是外部构造方法都需要单独提供解析器。
// 这样做的好处是可以flatten到同级数据
@JsonSerializable()
class AccountProfile {
  static const String uidField = "uid";
  static const String nicknameField = "nickname";
  static const String countryField = "country";
  static const String bestScoreField = "score";
  static const String avatarField = "avatar";
  static const String versionField = "ver";
  static const String updateAtField = "upt";
  static const String dirtyField = "dirty";
  static const String roleField = "role";

  static final _generalFieldSet = {
    uidField,
    nicknameField,
    countryField,
    bestScoreField,
    avatarField,
    versionField,
    updateAtField,
    dirtyField,
    roleField
  };

  @JsonKey(name: uidField, defaultValue: "")
  final String uid;

  @JsonKey(name: nicknameField, defaultValue: "")
  final String nickname;

  @JsonKey(name: countryField, defaultValue: "")
  final String countryCode;

  @JsonKey(name: avatarField, defaultValue: "")
  final String avatar;

  @JsonKey(name: versionField, defaultValue: "")
  final String version;

  @JsonKey(name: dirtyField, defaultValue: false)
  final bool dirty;

  @JsonKey(name: updateAtField, defaultValue: 0)
  final int updateAt;

  @JsonKey(name: roleField, defaultValue: 0)
  final int role;

  @JsonKey(ignore: true)
  final Map<String, dynamic> userData;

  const AccountProfile._({this.uid = "",
    this.nickname = "",
    this.countryCode = "",
    this.avatar = "avatar_1",
    this.version = "",
    this.dirty = false,
    this.role = AccountRole.normal,
    this.userData = const <String, dynamic>{},
    this.updateAt = 0});

  static const AccountProfile empty = AccountProfile._();

  AccountProfile({this.uid = "",
    this.nickname = "",
    this.countryCode = "",
    this.avatar = "avatar_1",
    this.version = "",
    this.dirty = false,
    this.role = AccountRole.normal,
    Map<String, dynamic> userData = const <String, dynamic>{},
    this.updateAt = 0}) : userData = Map.from(userData);


  factory AccountProfile.fromJson(Map<String, dynamic> json) =>
      _$AccountProfileFromJson(json)
        ..userData.addAll(_validateUserData(json, direct: false));

  Map<String, dynamic> toJson() =>
      _$AccountProfileToJson(this)
        ..addAll(_validateUserData(userData));

  static Map<String, dynamic> _validateUserData(Map<String, dynamic> data, {bool direct = true}) {
    return (direct ? data : Map.from(data))
      ..removeWhere((key, value) => _generalFieldSet.contains(key));
  }

  AccountProfile copyWith({String? nickname,
    String? countryCode,
    String? avatar,
    String? version,
    bool? dirty,
    int? role,
    Map<String, dynamic>? userData,
    bool mergeUserData = true}) {
    final changedUserData = <String, dynamic>{if (mergeUserData) ...this.userData};
    if (userData != null) {
      changedUserData.addAll(userData);
    }
    return AccountProfile(
        uid: uid,
        nickname: nickname ?? this.nickname,
        countryCode: countryCode ?? this.countryCode,
        avatar: avatar ?? this.avatar,
        version: version ?? this.version,
        role: role ?? this.role,
        userData: changedUserData,
        dirty: dirty ?? this.dirty);
  }

  AccountProfile merge(Map<String, dynamic> replaceJson) {
    return AccountProfile.fromJson(toJson()
      ..addAll(replaceJson));
  }

  @override
  String toString() {
    return 'AccountProfile{nickname: $nickname, countryCode: $countryCode}';
  }
}
