import 'dart:convert';

import 'package:fis_jsonrpc/rpc.dart';
import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:platform_device_id/platform_device_id.dart';
import 'package:vitalapp/consts/devices.dart';
import 'package:vitalapp/global.dart';
import 'package:vitalapp/managers/interfaces/application.dart';
import 'package:vitalapp/rpc.dart';
import 'package:vitalapp/store/store.dart';
import 'package:vnote_device_plugin/consts/types.dart';
import 'package:vitalapp/architecture/storage/text_storage.dart';
import 'package:vitalapp/managers/interfaces/models/device.dart';
import 'package:fis_common/logger/logger.dart';

import 'interfaces/device.dart';
import 'interfaces/system_setting.dart';

class DeviceManager extends IDeviceManager {
  final _typeConvertMap = <String, String>{
    "Temp": DeviceTypes.TEMP,
    "Weight": DeviceTypes.WEIGHT,
    "SpO2": DeviceTypes.SPO2,
    "NIBP": DeviceTypes.NIBP,
    "GLU": DeviceTypes.SUGAR,
    "Urine": DeviceTypes.URINE,
    "ICReader": DeviceTypes.IC_READER,
    "ECG": DeviceTypes.HEART,
    "TwelveHeart": DeviceTypes.TWELVEHEART,
    "WHB": DeviceTypes.WAIST,
  };
  final _storage = TextStorage(fileName: "devices.cfg");
  final _deviceStorage = TextStorage(fileName: "devices.setting.cfg");
  List<DeviceModel>? _cacheList;

  @override
  Future<List<String>> getAccessTypes() async {
    List<String> settingTypes = [];
    if (kIsOnline) {
      settingTypes =
          await Get.find<ISystemSettingManager>().getEnableDeviceKeysAsync();
      _deviceStorage.save(jsonEncode(settingTypes));
    } else {
      String? settingTypesString = await _deviceStorage.read();
      settingTypes =
          jsonDecode(settingTypesString ?? '').cast<String>().toList();
    }

    final types = settingTypes
        .map((e) => _typeConvertMap[e])
        .where((e) => e != null)
        .map((e) => e!)
        .toList();
    return types;
  }

  Future<List<String>> getCacheAccessTypes() async {
    List<String> settingTypes = [];
    String? settingTypesString = await _deviceStorage.read();
    settingTypes = jsonDecode(settingTypesString ?? '').cast<String>().toList();

    final types = settingTypes
        .map((e) => _typeConvertMap[e])
        .where((e) => e != null)
        .map((e) => e!)
        .toList();
    return types;
  }

  @override
  Future<void> addDevice(DeviceModel model) async {
    final source = await getDeviceList();
    final list = List<DeviceModel>.from(source);

    list.removeWhere((e) => e.type == model.type);
    list.add(model);

    saveDeviceList(list);
  }

  @override
  Future<void> removeDeviceByType(String type) async {
    final source = await getDeviceList();
    final list = List<DeviceModel>.from(source);

    list.removeWhere((e) => e.type == type);

    saveDeviceList(list);
  }

  @override
  Future<List<DeviceModel>> getDeviceList() async {
    if (_cacheList != null) return _cacheList!;

    final jsonText = await _storage.read();
    if (jsonText == null) {
      _cacheList = [];
    } else {
      final List<dynamic> mapList = jsonDecode(jsonText);
      _cacheList = mapList.map((e) => DeviceModel.fromJson(e)).toList();
    }
    return _cacheList!;
  }

  @override
  Future<void> saveDeviceList(List<DeviceModel> deviceList) async {
    _cacheList = deviceList;
    final jsonText = jsonEncode(deviceList);
    await _storage.save(jsonText);
  }

  @override
  Future<void> reportTablet() async {
    try {
      final appManager = Get.find<IApplicationManager>();

      // TODO: 考虑到登录因素过多，暂时不限制
      // final localAccount = await appManager.getProperty("account");
      // if (Store.user.account == localAccount) {
      //   return;
      // }

      final androidId = await PlatformDeviceId.getDeviceId;
      // TODO: 太长了
      // final deviceId =
      //     "2${const Uuid().v5(Uuid.NAMESPACE_OID, androidId).replaceAll("-", "")}";
      final deviceId = androidId ?? "";
      final androidInfo = await PlatformDeviceId.deviceInfoPlugin.androidInfo;
      final osVersion = "Android ${androidInfo.version.release}";
      PackageInfo packageInfo = await PackageInfo.fromPlatform();

      final request = ReportingDeviceInfoRequest(
        token: Store.user.token,
        serialNumber: deviceId,
        model: androidInfo.model,
        softwareVersion: packageInfo.version,
        oSVersion: osVersion,
      );
      final result = await rpc.device.reportingDeviceInfoAsync(request);
      if (result) {
        await appManager.setProperties({
          "account": Store.user.account,
          "deviceId": deviceId,
        });
      }
      logger.i("DeviceManager reportTablet result: $result.");
    } catch (e) {
      logger.e("DeviceManager reportTablet error", e);
    }
  }

  Future<bool> reportAddDevice(DeviceModel model) async {
    try {
      if (kIsOnline) {
        final deviceId = await PlatformDeviceId.getDeviceId;
        final deviceKey4Server = DeviceConsts.transType2ServerKey(model.type);
        final request = CreatePeripheralDeviceRequest(
          token: Store.user.token,
          deviceCode: deviceId,
          enable: true,
          key: deviceKey4Server,
          name: model.productName,
        );
        final result = await rpc.device.createPeripheralDeviceAsync(request);
        return result;
      } else {
        //
        return true;
      }
    } catch (e) {
      return false;
    }
  }
}
