import 'dart:convert';
import 'dart:io';

import 'package:auto_route/auto_route.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:eitc_erm_dental_flutter/app_router.gr.dart';
import 'package:eitc_erm_dental_flutter/dialog/app_update_dialog.dart';
import 'package:eitc_erm_dental_flutter/entity/file_prefix_info.dart';
import 'package:eitc_erm_dental_flutter/entity/version_info.dart';
import 'package:eitc_erm_dental_flutter/exts.dart';
import 'package:eitc_erm_dental_flutter/generated/l10n.dart';
import 'package:eitc_erm_dental_flutter/http/api_service.dart';
import 'package:eitc_erm_dental_flutter/http/http.dart';
import 'package:eitc_erm_dental_flutter/main.dart';
import 'package:eitc_erm_dental_flutter/sp_util.dart';
import 'package:eitc_erm_dental_flutter/vm/global_view_model.dart';
import 'package:encrypt/encrypt.dart' as encrpyt;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:logger/logger.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pointycastle/asymmetric/pkcs1.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
import 'package:pointycastle/pointycastle.dart';

import 'global.dart';

///国际化
S getS() => S.of(navigatorKey.currentState!.context);

late Logger logger;

///初始化日志
Future<dynamic> initLog() async {
  LogOutput? output;
  //android版有文件日志
  if (Platform.isAndroid) {
    Directory? dir = await getDownloadsDirectory();
    if (dir != null) {
      dir = Directory("${dir.path}/logs");
      if (!await dir.exists()) {
        await dir.create(recursive: true);
      }
      output = kDebugMode
          ? MultiOutput([ConsoleOutput(), AdvancedFileOutput(path: dir.path)])
          : ConsoleOutput();
    }
  } else {
    output = ConsoleOutput();
  }
  logger = Logger(
      printer: PrettyPrinter(
          methodCount: 5, dateTimeFormat: DateTimeFormat.dateAndTime),
      output: output);
}

void logd(
  dynamic message, {
  DateTime? time,
  Object? error,
  StackTrace? stackTrace,
}) {
  logger.d(message,
      time: time ?? DateTime.now(), error: error, stackTrace: stackTrace);
}

void logi(
  dynamic message, {
  DateTime? time,
  Object? error,
  StackTrace? stackTrace,
}) {
  logger.i(message,
      time: time ?? DateTime.now(), error: error, stackTrace: stackTrace);
}

void loge(
  dynamic message, {
  DateTime? time,
  Object? error,
  StackTrace? stackTrace,
}) {
  logger.e(message,
      time: time ?? DateTime.now(), error: error, stackTrace: stackTrace);
}

void logw(
  dynamic message, {
  DateTime? time,
  Object? error,
  StackTrace? stackTrace,
}) {
  logger.w(message,
      time: time ?? DateTime.now(), error: error, stackTrace: stackTrace);
}

void logf(
  dynamic message, {
  DateTime? time,
  Object? error,
  StackTrace? stackTrace,
}) {
  logger.f(message,
      time: time ?? DateTime.now(), error: error, stackTrace: stackTrace);
}

///显示toast
void showToast(
    {required String text,
    Duration duration = const Duration(seconds: 1, milliseconds: 500)}) {
  BotToast.showText(text: text, duration: duration);
}

///显示删除提示框
Future<T?> showDeleteAlertDialog<T>(BuildContext context, String hint) {
  return showDialog(
      context: context,
      builder: (ctx) => AlertDialog(
            title: Text(getS().hint),
            content: Text(hint),
            actions: [
              TextButton(
                  onPressed: () => {Navigator.pop(context)},
                  child: Text(getS().cancel)),
              TextButton(
                  onPressed: () => {Navigator.pop(context, true)},
                  child: Text(getS().confirm)),
            ],
          ));
}

///是否有存储权限
Future<bool> hasStoragePermission() async {
  if (Platform.isAndroid) {
    AndroidDeviceInfo info = await DeviceInfoPlugin().androidInfo;
    //小于32用READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限
    if (info.version.sdkInt <= 32) {
      return await Permission.storage.isGranted;
    }
    //33及以上使用READ_MEDIA_IMAGES和READ_MEDIA_VIDEO权限
    return await Permission.photos.isGranted &&
        await Permission.videos.isGranted;
  } else if (Platform.isIOS) {
    return await Permission.photos.isGranted;
  }
  return true;
}

///请求存储权限
Future<bool> requestStoreagePermission() async {
  if (await hasStoragePermission()) {
    return true;
  }
  if (await SpUtil.hasStoragePermissionRequested()) {
    return false;
  }
  bool bo = false;
  if (Platform.isAndroid) {
    AndroidDeviceInfo info = await DeviceInfoPlugin().androidInfo;
    if (info.version.sdkInt <= 32) {
      bo = await Permission.storage.request().isGranted;
    } else {
      Map<Permission, PermissionStatus> result = await [
        Permission.photos,
        Permission.videos,
      ].request();
      bo = result[Permission.photos]!.isGranted &&
          result[Permission.videos]!.isGranted;
    }
  } else if (Platform.isIOS) {
    bo = await Permission.photos.request().isGranted;
  }

  await SpUtil.setStoragePermissionRequested(true);
  return bo;
}

///是否有定位权限
Future<bool> hasLocationPremission() {
  return Permission.locationWhenInUse.isGranted;
}

///开启屏幕旋转
void screenEnableRotate() {
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.landscapeLeft,
    DeviceOrientation.landscapeRight,
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]);
}

///关闭屏幕旋转
void screenDisableRotate() {
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
}

///牙齿区域左上
const String toothAreaLeftTop = "lt";

///牙齿区域左下
const String toothAreaLeftBottom = "lb";

///牙齿区域右上
const String toothAreaRightTop = "rt";

///牙齿区域右下
const String toothAreaRightBottom = "rb";

///牙齿区域翻译
String toothAreaTranslate(String area) {
  switch (area) {
    case toothAreaLeftTop:
      return getS().leftTopArea;
    case toothAreaLeftBottom:
      return getS().leftBototmArea;
    case toothAreaRightTop:
      return getS().rightTopArea;
    case toothAreaRightBottom:
      return getS().rightBottomArea;
    default:
      return getS().unselected;
  }
}

String makeFilePrefix(
    {required String name,
    required String idCard,
    required String mobile,
    required String area,
    required String wifi,
    required int time,
    required String userId}) {
  FilePrefixInfo info = FilePrefixInfo(
      name: name,
      idCard: idCard,
      mobile: mobile,
      time: time,
      area: area,
      wifi: wifi,
      userId: userId);
  String encode = info.encode();
  if (encode.isEmpty) {
    return "";
  }
  return "${encode}_";
}

///解码base64
String decodeBase64(String encode) {
  Uint8List list = base64.decode(encode);
  return String.fromCharCodes(list);
}

///编码base64
String encodeBase64(String str) {
  return base64.encode(utf8.encode(str));
}

///验证身份证
bool validIdCard(String str) {
  //18位
  return RegExp(
              r'^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$')
          .hasMatch(str) ||
      //15位
      RegExp(r'[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$')
          .hasMatch(str);
}

///验证手机号
bool validMobile(String str) {
  return RegExp(r'1[3-9]\d{9}$').hasMatch(str);
}

///设置全屏
void setFullScreen(bool isFullScreen) {
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
      overlays: isFullScreen ? [] : [SystemUiOverlay.top]);
}

///读取WIFI名称
Future<String?> getWifiName() async {
  //是否有权限
  bool hasLocationPermission = await hasLocationPremission();
  if (!hasLocationPermission) {
    if (await SpUtil.hasLocationPermissionRequested()) {
      logd("读取wifi名称没有位置权限且已经请求过位置权限");
      return null;
    }
    if (navigatorKey.currentState!.mounted) {
      logd("弹窗提示要请求位置权限");
      await showDialog(
          context: navigatorKey.currentState!.context,
          builder: (ctx) {
            return AlertDialog(
              title: Text(getS().hint),
              content: Text(getS().requestLocationHint),
              actions: [
                TextButton(
                    onPressed: () =>
                        Navigator.of(navigatorKey.currentState!.context).pop(),
                    child: Text(getS().confirm))
              ],
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(15.r)),
            );
          });
      logd("请求位置权限");
      PermissionStatus status = await Permission.locationWhenInUse.request();
      await SpUtil.setLocationPermissionRequested(true);
      hasLocationPermission = status == PermissionStatus.granted;
    }
  }
  if (!hasLocationPermission) {
    logd("读取wifi名称没有位置权限");
    return null;
  }
  NetworkInfo networkInfo = NetworkInfo();
  String? name = await networkInfo.getWifiName();
  if (name == null) {
    logd("读取wifi名称返回null");
    return null;
  }
  logd("读取wifi名称=$name");
  //android返回的wifi名称里带双引号
  if (name.contains('"')) {
    name = name.replaceAll(RegExp(r'"'), "");
  }
  return name;
}

///获取设备型号,根据wifi名字获取,如果wifi名字为空就返回null
Future<String?> getDeviceModel() async {
  String? wifiName = await getWifiName();
  if (wifiName.isNullOrEmpty) {
    return null;
  }
  return wifiName!.replaceAll(deviceWifiPrefix, "");
}

///是否是设备WIFI,用来判断是否连接了设备
Future<bool> isDeviceWifi() async {
  String? name = await getWifiName();
  //没有读取到wifi名称就默认是外网
  if (name.isNullOrEmpty) {
    return false;
  }
  return SynchronousFuture(name!.startsWith(deviceWifiPrefix));
}

///检查是否外网WIFI
///
/// [isShowToast] 是否弹提示
Future<bool> checkInternetWifi([bool isShowToast = true]) async {
  if (await isDeviceWifi()) {
    if (isShowToast) {
      showToast(text: getS().pleaseConnectInternetWifi);
    }
    return false;
  }
  return true;
}

///检查是否已登录
///
/// [toLogin] 是否跳转登录页面
/// [cancelable] 登录页面是否可以取消,如果可以取消,则只push登录页面,否则将replace掉所有其他页面
bool checkLogin(BuildContext context,
    {bool toLogin = true, bool cancelable = true}) {
  if (hasToken) {
    return true;
  }
  if (toLogin && context.mounted) {
    if (cancelable) {
      context.pushRoute(LoginRoute(cancelable: cancelable));
    } else {
      popAllRoutes(context);
      context.pushRoute(LoginRoute(cancelable: false));
    }
  }
  return false;
}

///前往用户协议
void gotoUserAgreement(BuildContext context, {bool checkWifi = true}) async {
  if (checkWifi) {
    if (!await checkInternetWifi()) {
      return;
    }
  }
  if (!context.mounted) {
    return;
  }
  context.pushRoute(WebviewRoute(
      url: "",
      title: getS().userAgreement,
      htmlFuture: ApiService(Http.instance.dio).getUserAgreement()));
}

///前往隐私协议
void gotoPrivacyPolicy(BuildContext context, {bool checkWifi = true}) async {
  if (checkWifi) {
    if (!await checkInternetWifi()) {
      return;
    }
  }
  if (!context.mounted) {
    return;
  }
  context.pushRoute(WebviewRoute(
      url: "",
      title: getS().privacyPolicy,
      htmlFuture: ApiService(Http.instance.dio).getPrivacyPolicy()));
}

///前往权限说明
void gotoPermissionDesc(BuildContext context, {bool checkWifi = true}) async {
  if (checkWifi) {
    if (!await checkInternetWifi()) {
      return;
    }
  }
  if (!context.mounted) {
    return;
  }
  context.pushRoute(WebviewRoute(
      url: "",
      title: getS().permissionDescription,
      htmlFuture: ApiService(Http.instance.dio)
          .getPermissionDescription(Platform.isIOS ? "ios" : "android")));
}

///给身份证加星号
String setIdCardStar(String idCard) {
  if (idCard.length <= 6) {
    return idCard;
  }
  return "${idCard.substring(0, 3).padRight(idCard.length - 3, "*")}${idCard.substring(idCard.length - 3)}";
}

///设置已选择的咨询人ID
Future<bool> setSelectedPatientId(int id) async {
  bool bo = await SpUtil.setSelectedPatientId(id);
  if (bo) {
    selectedPatientId = id;
  }
  return bo;
}

///从身份证中获取性别,0男性,1女性,-1错误
int getGenderFromIdCard(String idCard) {
  if (!(idCard.length == 15 || idCard.length == 18)) {
    return -1;
  }
  try {
    //15位身份证最后3位奇数男性,偶数女性
    //18位身份证第17位奇数男性,偶数女性
    int sex = int.parse(
        idCard.length == 15 ? idCard.substring(12) : idCard.substring(16, 17));
    return sex.isOdd ? 0 : 1;
  } catch (e) {
    loge("从身份证中解析性别异常", error: e);
  }
  return -1;
}

///从身份证中获取年龄,-1错误
int getAgeFromIdCard(String idCard) {
  if (!(idCard.length == 15 || idCard.length == 18)) {
    return -1;
  }
  try {
    int year, month, day;
    //18位身份证
    if (idCard.length == 18) {
      year = int.parse(idCard.substring(6, 10));
      month = int.parse(idCard.substring(10, 12));
      day = int.parse(idCard.substring(12, 14));
    }
    //15位身份证
    else {
      //6,7位表示出生年份后两位
      String str = idCard.substring(6, 8);
      int a = int.parse(str);
      int nowYear = DateTime.now().year;
      int thousandYear = int.parse("${"$nowYear".substring(0, 2)}00");
      //如果身份证年份后两位比现在大,就把现在的千年减去100再加上后两位
      if (a > nowYear - thousandYear) {
        year = thousandYear - 100 + a;
      }
      //否则就用现在的千年加上后两位
      else {
        year = thousandYear + a;
      }
      month = int.parse(idCard.substring(8, 10));
      day = int.parse(idCard.substring(10, 12));
    }
    //生日
    DateTime birth = DateTime(year, month, day);
    //年龄
    int age = (DateTime.now().difference(birth).inDays / 365.0).floor();
    //logd("从身份证中获取年龄,year=$year,month=$month,day=$day,age=$age");
    return age;
  } catch (e) {
    loge("从身份证中获取年龄异常", error: e);
  }
  return -1;
}

final _key = encrpyt.Key.fromUtf8("1234567890123456");
final _iv = encrpyt.IV.fromUtf8("1234567890123456");

final _encrypter = encrpyt.Encrypter(
    encrpyt.AES(_key, mode: encrpyt.AESMode.cbc, padding: "PKCS7"));

///AES加密,返回base64
String aesEncrypt(String str) {
  if (str.isEmpty) {
    return "";
  }
  var encrypted = _encrypter.encrypt(str, iv: _iv);
  return encrypted.base64;
}

///AES解密,使用base64
String aesDecrypt(String str) {
  if (str.isEmpty) {
    return "";
  }
  var encrptyed = encrpyt.Encrypted.from64(str);
  return _encrypter.decrypt(encrptyed, iv: _iv);
}

///合并字节数组
Uint8List concatenateBytes(List<Uint8List> byteList) {
  int totalLength = byteList.fold(0, (sum, bytes) => sum + bytes.length);
  Uint8List result = Uint8List(totalLength);
  int offset = 0;

  for (var bytes in byteList) {
    result.setRange(offset, offset + bytes.length, bytes);
    offset += bytes.length;
  }

  return result;
}

///RSA加密,返回BASE64字符串,仅支持PKCS1编码
///
/// [keyBitLength] 密钥长度,应为512,1024,2048,4096中的一个,默认512
String rsaEncrypt(String pubKey, String content, {int keyBitLength = 512}) {
  try {
    final cipher = PKCS1Encoding(RSAEngine())
      ..init(
          true,
          PublicKeyParameter<RSAPublicKey>(
              encrpyt.RSAKeyParser().parse(pubKey) as RSAPublicKey));

    final utf8Bytes = Uint8List.fromList(utf8.encode(content));
    final inputLen = utf8Bytes.length;
    int offLen = 0;
    int i = 0;
    List<Uint8List> bops = [];

    int size = (keyBitLength / 8 - 11).toInt();
    while (inputLen - offLen > 0) {
      final chunkSize = (inputLen - offLen > size) ? size : inputLen - offLen;
      final cache = cipher.process(
          Uint8List.sublistView(utf8Bytes, offLen, offLen + chunkSize));
      bops.add(cache);
      i++;
      offLen = size * i;
    }

    final encryptedData = concatenateBytes(bops);
    final base64Encoded = base64Encode(encryptedData);

    return base64Encoded;
  } catch (e) {
    loge("RSA加密异常", error: e);
    return "";
  }
}

///RSA解密,输入BASE64,仅支持PKCS1编码
///
/// [keyBitLength] 密钥长度,应为512,1024,2048,4096中的一个,默认512
String rsaDecrypt(String priKey, String content, {int keyBitLength = 512}) {
  try {
    final cipher = PKCS1Encoding(RSAEngine());
    cipher.init(
        false,
        PrivateKeyParameter<RSAPrivateKey>(
            encrpyt.RSAKeyParser().parse(priKey) as RSAPrivateKey));

    final encryptedBytes = base64Decode(content);
    final inputLen = encryptedBytes.length;
    int offLen = 0;
    int i = 0;

    List<Uint8List> byteList = [];

    int size = keyBitLength ~/ 8;
    while (inputLen - offLen > 0) {
      final int chunkSize =
          (inputLen - offLen > size) ? size : inputLen - offLen;
      final cache = cipher.process(
          Uint8List.sublistView(encryptedBytes, offLen, offLen + chunkSize));
      byteList.add(cache);
      i++;
      offLen = size * i;
    }

    final byteArray = concatenateBytes(byteList);
    return utf8.decode(byteArray);
  } catch (e) {
    loge("RSA解密异常", error: e);
    return '';
  }
}

///检查新版本
///
/// 返回true表示有新版本,false没有新版本
Future<bool> checkNewVersion(BuildContext context, WidgetRef ref) async {
  VersionInfo? info = await ref
      .read(checkNewVersionProvider.notifier)
      .checkNewVersion(Platform.isIOS ? "ios" : "android");
  if (info == null || info.code.isNullOrEmpty) {
    logd("检查更新,服务器返回信息为null,或code为空");
    return false;
  }
  PackageInfo packageInfo = await PackageInfo.fromPlatform();
  logd(
      "检查更新,当前version=${packageInfo.version},当前code=${packageInfo.buildNumber},服务器version=${info.version},服务器code=${info.code}");
  int versionCode = 0;
  int serverCode = 0;
  try {
    versionCode = int.parse(packageInfo.buildNumber);
    serverCode = int.parse(info.code ?? "0");
  } catch (e) {
    loge("检查更新转换版本号异常", error: e);
  }
  //ios的version和code都需要比较,因为对于同一版本，ios发布时会自动提升code
  //不同版本又会从pubspec.yaml里填写的code重新计算
  if (Platform.isIOS) {
    if (info.version.isNullOrEmpty) {
      logd("ios比较版本,服务器version为空");
      return false;
    }
    //把服务器的版本号转为数字数组
    List<int> serverVersionNums = info.version!.split(".").map((e) {
      try {
        return int.parse(e);
      } catch (e) {
        loge("转换服务器版本字符到异常", error: e);
      }
      return 0;
    }).toList();
    //把本地的版本号转为数字数组
    List<int> currentVersionNums = packageInfo.version.split(".").map((e) {
      try {
        return int.parse(e);
      } catch (e) {
        loge("转换本地版本字符到异常", error: e);
      }
      return 0;
    }).toList();
    //如果本地长度小于服务器长度，则补齐本地数组
    if (currentVersionNums.length < serverVersionNums.length) {
      currentVersionNums.addAll(List.filled(
          serverVersionNums.length - currentVersionNums.length, -1));
    }
    //从左到右比较数字大小，只要服务器有一个大于本地的就认为需要升级
    bool needUpdate = false;
    bool sameVersion = true;
    for (int i = 0; i < serverVersionNums.length; i++) {
      if (serverVersionNums[i] != currentVersionNums[i]) {
        sameVersion = false;
      }
      if (serverVersionNums[i] > currentVersionNums[i]) {
        needUpdate = true;
        break;
      }
    }
    //如果版本号都一致，就判断code的大小
    if (!needUpdate && sameVersion && serverCode > versionCode) {
      needUpdate = true;
    }
    return needUpdate;
  }
  //其他的只需要判断code
  else {
    if (versionCode >= serverCode) {
      return false;
    }
  }
  if (context.mounted) {
    showDialog(
        context: context,
        builder: (ctx) {
          return AppUpdateDialog(
              version: info.version!,
              content: info.content ?? "",
              url: info.downloadUrl ?? "",
              isForce: info.mandatoryUpdate == "1");
        });
  }
  return true;
}

///登出清空数据
Future<dynamic> logoutClearData() async {
  updateToken("");
  await SpUtil.setUserId("");
  await SpUtil.setUserName("");
  await SpUtil.setToken("");
  await setSelectedPatientId(-1);
}

///弹出所有路由
void popAllRoutes(BuildContext context) {
  AutoRouter.of(context).popUntil((_) => false);
}

///app名字
String get appName =>
    switch (appFlavor) { flavorHst => getS().appNameHst, _ => getS().appName };

///退出APP
void exitApp() async {
  await SystemNavigator.pop();
  //exit(0);
}

///微信是否安装
///
/// [toast] 是否显示提示,默认true
Future<bool> isWxInstalled({bool toast = true}) async {
  bool bo = await fluwx.isWeChatInstalled;
  if (!bo && toast) {
    showToast(text: getS().wxNotInstalledHint);
  }
  return bo;
}
