import 'dart:convert';

import 'package:fis_common/event/event_type.dart';
import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_ui/values.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:flutter/foundation.dart';
import 'package:flyinsono/architecture/define.dart';
import 'package:flyinsono/architecture/router/mobile/names.dart';
import 'package:flyinsono/architecture/services/entity/default_entry_setting.dart';
import 'package:flyinsono/architecture/services/modules/default_entry_configuration.dart';
import 'package:flyinsono/architecture/services/notification/local_notification_service.dart';
import 'package:flyinsono/architecture/states/heartbeat/login_heartbeat.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/architecture/states/types.dart';
import 'package:flyinsono/architecture/values/features.dart';
import 'package:flyinsono/global.dart';
import 'package:flyinsono/managers/interfaces/server_config.dart';
import 'package:flyinsono/notifications/notifications.dart';
import 'package:flyinsono/architecture/services/notification/mobile_schedule_notification_service.dart';
import 'package:flyinsono/rpc.dart';
import 'package:fis_measure/process/workspace/rpc_bridge.dart';
import 'package:get/get.dart';
import '../../router/router.dart';

/// 用户状态
///
/// 全局状态默认只应对外暴露getter属性
///
/// 需要状态变更应该由状态持有者操作
class UserState extends StateModuleBase {
  final onAssociatedFeatureChange =
      FEventHandler<List<AssociatedFeatureInfoDTO>>();
  String _token = '';
  String _openid = '';
  String _code = '';
  String? _account;
  String? _password;
  bool _isAutoLogin = false;
  bool _isAgreeClause = false;
  String? _departmentCode;
  String? _rootOrganizationCode;
  bool _canBatchExport = false;
  Rx<String> _organizationName = ''.obs;
  Rx<String> _fullName = ''.obs;
  Rx<String> _userName = ''.obs;
  Rx<String> _displayName = ''.obs;
  String? _phone;
  String? _email;
  String _signature = '';
  String? _language;
  bool _enableReportLabel = false;
  final _avatar = ''.obs;

  RxBool _isPrincipal = false.obs;
  RxInt _featuresLength = 0.obs;
  RxList<String> _features = RxList<String>();
  final RxList<AssociatedFeatureInfoDTO> _associatedFeatures = RxList();
  ServerSettingResult? _serverSetting;
  LoginHeartbeat? _loginHeartbeat;
  RxInt _deviceLiveMaxCount = 1.obs;

  int _imageType = 0;
  int _videoType = 0;

  /* 
   * ! important: 需要持久化的属性一定要在acceptPersistenceJson和toPersistenceJson中设置
   */

  /// 登录令牌
  String get token => _token;

  /// 微信小程序openid
  String get openid => _openid;

  /// 用户编号
  String get code => _code;

  /// 登录账号
  String? get account => _account;

  /// 登录密码
  String? get password => _password;

  ///用户手机号码
  String? get phone => _phone;

  ///用户邮箱账号
  String? get email => _email;

  /// 用户签名
  String get signature => _signature;

  /// 报告标签弹框是否自动弹出
  bool get enableReportLabel => _enableReportLabel;

  /// 当前语言
  String? get language => _language;

  /// 是否记住密码
  bool get isAutoLogin => _isAutoLogin;

  ///是否同意条款
  bool get isAgreeClause => _isAgreeClause;

  /// 头像
  String get avatar => _avatar.value;
  set avatar(String value) => _avatar.value = value;

  /// 权限集合
  List<String> get features => _features;

  ///当前账号第三方关联平台信息
  List<AssociatedFeatureInfoDTO> get associatedFeatures => _associatedFeatures;

  /// 当前部门code
  String? get departmentCode => _departmentCode;

  /// 当前机构code
  String? get rootOrganizationCode => _rootOrganizationCode;

  /// 当前机构名称
  String get rootOrganizationName => _organizationName.value;
  set rootOrganizationName(String value) => _organizationName.value = value;

  /// 是否已登录
  bool get isLogin => token.isNotEmpty;

  /// 真实姓名
  String? get fullName => _fullName.value;

  /// 账号姓名
  String? get userName => _userName.value;

  /// 外显名称
  String get displayName => _displayName.value;

  /// 是否机构负责人
  bool get isPrincipal => _isPrincipal.value;

  /// 当前权限长度
  int get featuresLength => _featuresLength.value;

  /// 是否拥有批量导出权限
  bool get canBatchExportData => _canBatchExport;

  ///会诊心跳
  int? get liveConsultationRateSeconds =>
      _serverSetting?.liveConsultationRateSeconds;

  /// 超声直播同屏最大数量
  int get deviceLiveMaxCount => _deviceLiveMaxCount.value;
  set deviceLiveMaxCount(int val) => _deviceLiveMaxCount.updateValue(val);

  int get imageType => _imageType;
  int get videoType => _videoType;

  ///设置用户 Token
  void setToken(String token) {
    _token = token;
    logger.i("UserState set token:" + token);
    try {
      RPCBridge.ins.setToken(token);
    } catch (e) {
      print(e);
    }
  }

  ///设置用户 Token
  void setExportImageFormat(int imageType, int videoType) {
    _imageType = imageType;
    _videoType = videoType;
    logger.i(
        "UserState set ExportImageFormat:imageType-{$imageType}  videoType-$videoType");
  }

  /// 设置用户openid
  void setOpenid(String openid) {
    _openid = openid;
    logger.i("UserState set openid:" + openid);
  }

  ///设置特殊的批量导出权限
  void setBatchExportRight(bool batchExport) {
    _canBatchExport = batchExport;
  }

  @override
  Future<void> acceptPersistenceJson(Map<String, dynamic> map) async {
    // key对应值不为空时，给相应字段赋值
    map.pickPersistentProp('token', (x) => setToken(x));
    map.pickPersistentProp('openid', (x) => _openid = x);
    map.pickPersistentProp('code', (x) => _code = x);
    map.pickPersistentProp('isPrincipal', (x) => _isPrincipal.value = x);
    map.pickPersistentProp('batchExportPermission', (x) => _canBatchExport = x);
    map.pickPersistentProp('imageType', (x) => _imageType = x);
    map.pickPersistentProp('videoType', (x) => _videoType = x);
    map.pickPersistentProp(
      'features',
      (x) => _setFeatures((x as List).cast<String>()),
    );
    map.pickPersistentProps({
      'isAutoLogin': (x) => _isAutoLogin = x,
      'password': (x) => _password = x,
      'account': (x) => _account = x,
      'fullName': (x) => _fullName.value = x,
      'avatar': (x) => _avatar.value = x,
      'displayName': (x) => _displayName.value = x,
      'signature': (x) => _signature = x,
      'enableReportLabel': (x) => _enableReportLabel = x,
      'language': (x) => _language = x,
      'deviceLiveMaxCount': (x) => deviceLiveMaxCount = x,
      'isAgreeClause': (x) => _isAgreeClause = x,
    });
  }

  @override
  Map<String, dynamic> toPersistenceJson() {
    return {
      "token": token,
      "openid": openid,
      "code": code,
      "isPrincipal": isPrincipal,
      "password": password,
      "account": account,
      "isAutoLogin": isAutoLogin,
      "fullName": fullName,
      "features": features,
      "avatar": avatar,
      "batchExportPermission": canBatchExportData,
      "signature": signature,
      "enableReportLabel": enableReportLabel,
      "displayName": displayName,
      "language": language,
      "deviceLiveMaxCount": deviceLiveMaxCount,
      "isAgreeClause": isAgreeClause,
      "imageType": imageType,
      "videoType": videoType,
    };
  }
}

/// 用户状态持有者
///
/// 仅状态持有者有直接操作状态的权限
extension UserStateHost on UserState {
  /// 是否有指定权限
  ///
  /// [key] 权限Key
  bool hasFeature(String key) => features.contains(key);

  /// 是否有机构管理员的权限
  bool? hasOrgFeature() {
    List<String> orgFeature = [
      FeatureKeys.OrgInfo,
      FeatureKeys.OrgPersonnel,
      FeatureKeys.OrgDevices,
      FeatureKeys.OrgEntries,
      FeatureKeys.OrgReportTemplate,
    ];
    for (String i in features) {
      if (orgFeature.contains(i)) {
        return true;
      }
    }
    return null;
  }

  /// 处理用户信息同步更新
  ///
  /// [isPrincipal] 是否机构负责人
  Future<void> handleUserSyncUpdate(UserDTO userDTO) async {
    this._fullName.value = userDTO.fullName ?? '';
    this._userName.value = userDTO.userName ?? '';
    this._displayName.value = userDTO.displayName ?? '';
    this._departmentCode = userDTO.departmentCode;
    this._rootOrganizationCode = userDTO.rootOrganizationCode;
    this._organizationName.value = userDTO.rootOrganizationName ?? '';

    this._email = userDTO.email;
    this._phone = userDTO.phone ?? '';
    this._signature = userDTO.signature ?? '';
    this._enableReportLabel = userDTO.enableReportLabel;
    this._language = userDTO.language ?? 'zh';
    this.avatar = userDTO.headImageUrl ?? '';
    this._code = userDTO.userCode ?? '';

    await _fetchFeatures();
    this._isPrincipal.value = userDTO.isDirector;
    await Store.persistent();

    /// 词条 数据初始化
    try {
      final defaultThesaurus = await rpc.report.getDefaultThesaurusContentAsync(
        GetDefaultThesaurusContentRequest(
          token: Store.user.token,
          languageCode: i18nBook.locale.toCodeString('-'),
        ),
      );
      if (defaultThesaurus.baseInfo!.thesaurusCode!.isNotEmpty)
        await savedefaultThesaurus(defaultThesaurus.baseInfo!.thesaurusCode!);
      else
        return;
    } catch (e) {
      // logger.e("defaultThesaurus fetch features error.", e);
    }
  }

  /// 处理用户微信登录
  /// [name] 用户名
  /// [hospital] 医院
  Future<void> handleWechatLogin(
      String name, String hospital, String userId) async {
    this._fullName.value = name;
    this._userName.value = name;
    this._displayName.value = name;
    this._code = userId;
    this.rootOrganizationName = hospital;
    await Store.persistent();
  }

  /// 处理登出事件
  Future<void> handelLogOut() async {
    try {
      if (_token.isNotEmpty) {
        await rpc.login.loginOutAsync(TokenRequest(
          token: _token,
        ));
      }
    } catch (e) {
      logger.e('UserState handelLogOut ex:', e);
    }
    setToken('');
    _clearFeatures();
    this._featuresLength.value = 0;
    await Store.persistent();
    if (FPlatform.isWindows || FPlatform.isMacOS) {
      try {
        await rpc.platform.onMainWindowLogout();
      } catch (e) {
        logger.e('UserStateHost handelLogOut ex', e);
      }
    }
    notificationCenter.stop();
    _loginHeartbeat?.stop();
    _loginHeartbeat = null;
  }

  /// 初始化词条数据
  Future<void> savedefaultThesaurus(String defaultThesaurus) async {
    /// 默认词条持久化缓存服务
    late final DefaultEntryService defaultEntryService =
        Get.find<DefaultEntryService>();

    DefaultEntrySetting defaultEntrySetting = DefaultEntrySetting.ins;

    final getThesaurusItemsAsync = await rpc.report.getThesaurusItemsAsync(
      GetThesaurusItemsRequest(
        token: Store.user.token,
        thesaurusCode: defaultThesaurus,
      ),
    );
    if (getThesaurusItemsAsync.isEmpty)
      return;
    else {
      defaultEntrySetting.setDefaultEntry(jsonEncode(getThesaurusItemsAsync));
      defaultEntryService.save();
    }
  }

  /// 处理登录事件
  Future<void> handleLogOn({
    required String token,
    required String code,
    bool isAutoLogin = false,
    bool isAgreeClause = false,
    String? account,
    String? password,
  }) async {
    this._code = code;
    setToken(token);
    this._isAutoLogin = isAutoLogin;
    this._isAgreeClause = isAgreeClause;
    this._account = account;
    this._password = password;
    await _fetchFeatures();

    await Store.persistent();
  }

  /// 处理科研版获取权限的事件
  Future<void> handleSetAuth() async {
    await _fetchFeatures();
    await Store.persistent();
  }

  /// 处理注册成功之后事件
  Future<void> handleRegistrationEvent({
    required String account,
    String? password,
  }) async {
    this._account = account;
    this._password = password;
    await Store.persistent();
  }

  void _clearFeatures() => _features = RxList<String>();
  void _setFeatures(Iterable<String> arr) =>
      _features.value = List.unmodifiable(arr);

  Future<void> _fetchFeatures() async {
    _clearFeatures();
    try {
      final items = await rpc.user.getUserFeatureListAsync(
        TokenRequest(token: token),
      );
      final featureKeys = items
          .where((e) => e.uniqueCode != null && e.uniqueCode!.isNotEmpty)
          .map((e) => e.uniqueCode!);
      _setFeatures(featureKeys);
      this._featuresLength.value = featureKeys.length;
    } catch (e) {
      logger.e("UserState fetch features error.", e);
    }
  }

  /// 更新服务配置
  Future<void> updateServerSetting() async {
    try {
      var serverConfigManager = Get.find<IServerConfigManager>();
      final result = await serverConfigManager.getAllServerConfig();
      _serverSetting = result;
    } catch (e) {
      logger.e('UserStateHost updateServerSetting ex', e);
    }
  }

  /// 处理登录后
  Future<void> handleAfterLogOn() async {
    try {
      await _fetchAssociatedFeatures();
      await initNotificationConfig();

      // 开启登录心跳
      _startLoginHeartbeat();

      /// 开启消息中心后，更新移动端系统通知
      _updateMobileLocalNotification();

      /// 处理移动端打开应用携带的payload
      _loadLaunchPayload();
    } catch (e) {
      logger.e('Handle user state after logon error', e);
    }
  }

  ///初始化通知中心
  Future<void> initNotificationConfig({WSType type = WSType.Main}) async {
    await updateServerSetting();
    Global.unlistenWsConnection();
    _updateNotificationHost(type: type);
    // 开启消息中心
    notificationCenter.start();
    Global.listenWsConnection();
  }

  /// 更新通知中心连接地址
  void _updateNotificationHost({WSType type = WSType.Main}) {
    final notificationUrl = _serverSetting?.notificationUrl ?? '';
    final host =
        StringFormatter.format(notificationUrl, [Store.user.token, type.index]);

    /// Debug 用的 host
    /// 可搭配 http://git.ius.plus:88/gavin.chen/mock_websocket_server 使用
    var mockHost = ''; //'ws://127.0.0.1:8765';
    if (kDebugMode && mockHost.isNotEmpty) {
      notificationCenter.setHost(mockHost);
    } else {
      notificationCenter.setHost(host);
    }
  }

  void _startLoginHeartbeat() {
    if (_loginHeartbeat == null) {
      final rateSeconds = _serverSetting?.heartRateSeconds ?? 30;
      final interval = rateSeconds * 1000 - 500; // 设置500ms的buffer，防止超时请求
      _loginHeartbeat = LoginHeartbeat(token: token, interval: interval);
    }
    _loginHeartbeat!.start();
  }

  /// 更新移动端系统通知订阅
  void _updateMobileLocalNotification() {
    if (!kIsMobile) return;

    /// 页面配置项
    final mobileScheduleNotificationService =
        Get.find<MobileScheduleNotificationService>();
    mobileScheduleNotificationService.updateNotificationService();
  }

  /// 获取移动端应用启动参数
  void _loadLaunchPayload() {
    if (!kIsMobile) return;

    final localNotificationService = Get.find<LocalNotificationService>();
    localNotificationService.loadLaunchPayload(method: (payload) {
      switch (payload.type) {
        case PayloadType.common:
          break;
        case PayloadType.consultation:
          _openConsultationDetail(payload.message);
          break;
        default:
          break;
      }
    });
  }

  /// 移动端进入会诊详情页
  void _openConsultationDetail(String consultationCode) async {
    if (!kIsMobile) return;

    try {
      await router.to(MobileRouteNames.RealTimeRemedical.ConsultationDetail,
          parameters: {
            'consultationCode': consultationCode,
          });
    } catch (e) {
      logger.e("openEditInit exception:", e);
      printError(info: e.toString());
    }
  }

  ///获取当前账号下第三方平台相关联信息
  Future<void> _fetchAssociatedFeatures() async {
    GetAssociatedAccountInfoResult associatedAccountInfos =
        GetAssociatedAccountInfoResult();
    try {
      associatedAccountInfos = await rpc.login.getAssociatedAccountInfoAsync(
          GetAssociatedAccountInfoRequest(token: Store.user.token));
    } catch (e) {
      logger.e("_fetchAssociatedFeatures ex", e);
    }

    List<AssociatedFeatureInfoDTO> accountInfoList = [];
    if (associatedAccountInfos.isSuccess) {
      accountInfoList = associatedAccountInfos.accountInfoList ?? [];
      _associatedFeatures.value = accountInfoList;
      onAssociatedFeatureChange.emit(this, accountInfoList);
    } else {
      _associatedFeatures.value = [];
      onAssociatedFeatureChange.emit(this, accountInfoList);
    }
  }
}
