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

import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:nomo/app/api/router/api_router.dart';
import 'package:nomo/app/data/sp/ix_sp.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:play_install_referrer/play_install_referrer.dart';

import '../../config/translations/localization_service.dart';
import '../../config/translations/strings_enum.dart';
import '../../pigeons/core_api.g.dart';
import '../../utils/device_manager.dart';
import '../../utils/file_cache_manager.dart';
import '../../utils/log/logger.dart';
import '../../utils/network_helper.dart';
import '../api/core/api_core.dart';
import '../components/country_restricted_overlay.dart';
import '../components/ix_snackbar.dart';
import '../constants/api_domains.dart';
import '../constants/configs.dart';
import '../constants/enums.dart';
import '../constants/errors.dart';
import '../constants/platforms.dart';
import '../data/models/api_exception.dart';
import '../data/models/failure.dart';
import '../data/models/fingerprint.dart';
import '../data/models/launch/groups.dart';
import '../data/models/launch/launch.dart';

class ApiController extends GetxService {
  final TAG = 'ApiController';

  // 记录是否已经显示禁用弹窗
  bool isShowDisabled = false;

  //是否是游客
  final _isGuest = false.obs;
  bool get isGuest => _isGuest.value;
  set isGuest(bool value) => _isGuest.value = value;

  //全部节点列表
  final _nodesList = <LocationList>[].obs;
  List<LocationList> get nodesList => _nodesList.value;
  set nodesList(List<LocationList> value) => _nodesList.value = value;

  //初始化fingerprint
  Fingerprint fp = Fingerprint.empty();

  Future<Fingerprint> initFingerprint() async {
    // 读取app发布渠道
    if (Platform.isIOS) {
      fp.channel = 'apple';
    } else if (Platform.isAndroid) {
      try {
        final channel = await CoreApi().getChannel();
        fp.channel = channel ?? 'unknown';
      } catch (e) {
        log(TAG, 'read app channel error: $e');
        fp.channel = 'unknown';
      }
    }
    try {
      final advertisingId = await CoreApi().getAdvertisingId();
      fp.googleId = advertisingId ?? '';
    } catch (e) {
      log(TAG, 'read app googleId error: $e');
      fp.googleId = '';
    }
    // 读取应用信息
    final info = await PackageInfo.fromPlatform();
    fp.appVersionCode = int.tryParse(info.buildNumber) ?? 0;
    fp.appVersionName = info.version;
    // 读取设备信息
    final deviceInfo = DeviceInfoPlugin();
    if (Platform.isIOS) {
      fp.platform = Platforms.iOS;
      final iosOsInfo = await deviceInfo.iosInfo;
      fp.deviceModel = iosOsInfo.model;
      fp.deviceOs = iosOsInfo.systemVersion;
      fp.deviceBrand = iosOsInfo.utsname.machine;
    } else if (Platform.isAndroid) {
      fp.platform = Platforms.android;
      final androidOsInfo = await deviceInfo.androidInfo;
      fp.deviceModel = androidOsInfo.model;
      fp.deviceOs = androidOsInfo.version.release;
      fp.deviceBrand = androidOsInfo.brand;
      fp.androidId = androidOsInfo.id;
    }
    //获取设备尺寸
    fp.deviceHeight = Get.height.toInt();
    fp.deviceWidth = Get.width.toInt();

    // 读取设备ID
    fp.deviceId = DeviceManager.getCacheDeviceId();

    try {
      ReferrerDetails referrerDetails =
          await PlayInstallReferrer.installReferrer;
      fp.refer = referrerDetails.installReferrer ?? '';
    } catch (e) {
      log(TAG, 'get install referrer error: $e');
    }
    fp.isNewInstall = IXSP.getIsNewInstall();
    await updateFingerprintData();
    return fp;
  }

  // 更新部分数据
  Future<void> updateFingerprintData() async {
    fp.lang = IXSP.getCurrentLocal().languageCode;
    fp.phoneCountryIso = LocalizationService.getSystemCountry();
    fp.isVpn = await CoreApi().isConnected() ?? false;
    if (!fp.isVpn) {
      fp.isConnectedVpn = false;
    }
    try {
      final simInfo = await CoreApi().getSimInfo();
      // 解析sim
      final sim = jsonDecode(simInfo ?? '{}');
      fp.simReady = sim['simReady'];
      fp.carrierName = sim['carrierName'];
      fp.mcc = sim['mcc'];
      fp.mnc = sim['mnc'];
      fp.countryIso = sim['countryIso'];
      fp.networkCarrierName = sim['networkCarrierName'];
      fp.networkMcc = sim['networkMcc'];
      fp.networkMnc = sim['networkMnc'];
      fp.networkCountryIso = sim['networkCountryIso'];
    } catch (e) {
      log(TAG, 'read app sim error: $e');
    }
  }

  Future<void> initData(Launch? launch) async {
    // 初始化是否第一次安装
    IXSP.setIsNewInstall(false);
    fp.userUuid = '';
    fp.isNewInstall = false;
    await initLaunch(launch);
  }

  Future<void> initLaunch(Launch? launch) async {
    try {
      if (launch != null) {
        // 初始化用户状态
        isGuest = launch.userConfig?.memberLevel == MemberLevel.guest.level;

        // 设置路由和节点
        nodesList = launch.groups?.normal?.list ?? [];

        // 设置资源url
        if (launch.appConfig?.assetUrls != null &&
            launch.appConfig!.assetUrls!.isNotEmpty) {
          Configs.assetUrl = launch.appConfig!.assetUrls![0];
        }

        // 设置官网url
        if (launch.appConfig?.websiteUrl != null &&
            launch.appConfig!.websiteUrl!.isNotEmpty) {
          Configs.websiteUrl = launch.appConfig!.websiteUrl!;
        }

        // 下载ips和domains文件
        readIpDomain();
      }
    } catch (e) {
      log(TAG, 'initLaunch error: $e');
    }
  }

  // 发送分析事件, 后续可以发送到firebase
  Future<void> sendAnalytics(FirebaseEvent event) async {
    try {} catch (e) {
      log('sendAnalytics error: $e');
    }
  }

  Future<Launch> launch({bool isCache = false}) async {
    sendAnalytics(isCache ? FirebaseEvent.launchCache : FirebaseEvent.launch);
    while (true) {
      try {
        ApiCore().setbaseUrl(ApiDomains.instance.getApiUrl());
        final request = fp.toJson();
        if (IXSP.getDisconnectDomains().isNotEmpty) {
          final disconnectDomainList = IXSP
              .getDisconnectDomains()
              .map((e) => e.toJson())
              .toList();
          request['disconnectDomainList'] = disconnectDomainList;
        }
        final result = await ApiCore().launch(request);

        if (!result.success) {
          throw Failure(
            code: result.errorCode ?? '',
            message: result.errorMessage ?? '',
          );
        }
        sendAnalytics(
          isCache
              ? FirebaseEvent.launchCacheSuccess
              : FirebaseEvent.launchSuccess,
        );
        if (IXSP.getDisconnectDomains().isNotEmpty) {
          IXSP.clearDisconnectDomains();
        }
        // 重置禁用状态
        IXSP.setLastIsRegionDisabled(false);
        IXSP.setLastIsUserDisabled(false);

        final launchData = Launch.fromJson(result.data);

        // 设置扩展数据
        fp.exData = launchData.exData;

        // 更新URL列表
        await ApiDomains.instance.updateFromLaunch(launchData);

        // 保存Launch数据
        await IXSP.saveLaunch(launchData);

        // 初始化Launch
        await initData(launchData);

        return launchData;
      } on ApiException catch (e) {
        final url = await ApiDomains.instance.getNextApiUrl();
        log(TAG, 'Launch request failed for URL $url: $e');
        if (url.isEmpty) {
          rethrow;
        }
        ApiCore().setbaseUrl(url);
      } on Failure catch (_) {
        rethrow;
      } on DioException catch (e) {
        if (e.response?.statusCode == Errors.eRegionNotAvailable ||
            e.response?.statusCode == Errors.eUserDisabled ||
            e.response?.statusCode == Errors.eTokenExpired) {
          rethrow;
        } else {
          if (await NetworkHelper.instance.isNetworkAvailable()) {
            final url = await ApiDomains.instance.getNextApiUrl();
            log(TAG, 'Launch request failed for URL $url: $e');
            if (url.isEmpty) {
              rethrow;
            }
            ApiCore().setbaseUrl(url);
          } else {
            rethrow;
          }
        }
      } catch (e) {
        final url = await ApiDomains.instance.getNextApiUrl();
        log(TAG, 'Launch request failed for URL $url: $e');
        if (url.isEmpty) {
          rethrow;
        }
        ApiCore().setbaseUrl(url);
      }
    }
  }

  Future<void> asyncHandleLaunch() async {
    try {
      final data = await launch(isCache: true);
      final isVpnRunning = await CoreApi().isConnected() ?? false;
      if (!isVpnRunning) {
        await checkUpdate();
        switch (MemberLevel.fromLevel(data.userConfig?.memberLevel)) {
          case MemberLevel.guest:
            //游客禁用，必须登录
            if (data.appConfig?.visitorDisabled ?? true) {
            } else {
              //允许游客访问，如果不存在Main，则跳转Main
            }
            break;
          default:
            log('login user, default not handle');
            break;
        }
      }
    } catch (e, s) {
      if (IXSP.getLastIsUserDisabled()) {
        if (!isShowDisabled) {
          Get.offAll(
            () => CountryRestrictedOverlay(
              type: RestrictedType.user,
              onPressed: () async {
                // 清除LaunchData
                await IXSP.clearLaunchData();
                // 清除禁用状态
                IXSP.setLastIsUserDisabled(false);
                // 发送事件
              },
            ),
            transition: Transition.fadeIn,
          );
        }
        return;
      } else if (IXSP.getLastIsRegionDisabled()) {
        if (!isShowDisabled) {
          Get.offAll(
            () => const CountryRestrictedOverlay(type: RestrictedType.region),
            transition: Transition.fadeIn,
          );
        }
        return;
      } else if (IXSP.getLastIsDeviceDisabled()) {
        if (!isShowDisabled) {
          Get.offAll(
            () => const CountryRestrictedOverlay(type: RestrictedType.device),
            transition: Transition.fadeIn,
          );
        }
        return;
      }
      final isVpnRunning = await CoreApi().isConnected() ?? false;
      if (!isVpnRunning) {
        await checkUpdate();
      }
      handleSnackBarError(e, s);
    }
  }

  void handleSnackBarError(dynamic error, StackTrace stackTrace) {
    if (error is ApiException) {
      IXSnackBar.showIXErrorSnackBar(
        title: Strings.error.tr,
        message: error.message,
      );
    } else if (error is Failure) {
      IXSnackBar.showIXErrorSnackBar(
        title: Strings.error.tr,
        message: error.message ?? Strings.unknownError.tr,
      );
    } else if (error is DioException) {
      switch (error.type) {
        case DioExceptionType.connectionError:
        case DioExceptionType.connectionTimeout:
        case DioExceptionType.receiveTimeout:
        case DioExceptionType.sendTimeout:
          IXSnackBar.showIXErrorSnackBar(
            title: Strings.error.tr,
            message: Strings.unableToConnectNetwork.tr,
          );
          break;
        default:
          IXSnackBar.showIXErrorSnackBar(
            title: Strings.error.tr,
            message: Strings.unableToConnectServer.tr,
          );
      }
    } else {
      IXSnackBar.showIXErrorSnackBar(
        title: Strings.error.tr,
        message: Strings.unknownError.tr,
      );
    }
  }

  Future<void> readIpDomain() async {
    try {
      final fileCacheManager = FileCacheManager();
      final launch = IXSP.getLaunch();
      if (launch != null && launch.appConfig?.skipGeo != null) {
        // 读取文件并计算MD5
        if (launch.appConfig?.skipGeo?.ipsUrl != null &&
            launch.appConfig!.skipGeo!.ipsUrl!.isNotEmpty) {
          final remoteUrl =
              '${Configs.assetUrl}/${launch.appConfig?.skipGeo?.ipsUrl}';
          await fileCacheManager.getFileContent(
            remoteUrl: remoteUrl,
            fileName: 'ips.txt',
            expectedMd5: launch.appConfig?.skipGeo?.ipsMd5 ?? '',
            onProgress: (progress) {
              log(
                TAG,
                'Downloading IPs: ${(progress * 100).toStringAsFixed(2)}%',
              );
            },
          );
        }
        if (launch.appConfig?.skipGeo?.domainsUrl != null &&
            launch.appConfig!.skipGeo!.domainsUrl!.isNotEmpty) {
          final remoteUrl =
              '${Configs.assetUrl}/${launch.appConfig?.skipGeo?.domainsUrl}';
          await fileCacheManager.getFileContent(
            remoteUrl: remoteUrl,
            fileName: 'domains.txt',
            expectedMd5: launch.appConfig?.skipGeo?.domainsMd5 ?? '',
            onProgress: (progress) {
              log(
                TAG,
                'Downloading Domains: ${(progress * 100).toStringAsFixed(2)}%',
              );
            },
          );
        }
      }
    } catch (e) {
      log(TAG, 'readIpsDomain error: $e');
    }
  }

  // 更新检查 - 智能时间控制版本
  Future<bool> checkUpdate({bool isClickCheck = false}) async {
    try {
      final upgrade = IXSP.getUpgrade();
      var hasUpdate = false;
      var hasForceUpdate = false;

      if (upgrade != null) {
        if (upgrade.upgradeType == 1) {
          hasUpdate = true;
        }
        if (upgrade.forced == true) {
          hasForceUpdate = true;
        }
      }

      if (hasUpdate) {
        if (hasForceUpdate) {}
      }
      return hasUpdate;
    } catch (e) {
      log(TAG, 'checkUpdate error: $e');
    }
    return false;
  }

  Future<Launch> getDispatchInfo(
    int locationId,
    String locationCode, {
    CancelToken? cancelToken,
  }) async {
    while (true) {
      try {
        ApiRouter().setbaseUrl(ApiDomains.instance.getRouterUrl());
        final request = fp.toJson();
        if (IXSP.getDisconnectDomains().isNotEmpty) {
          final disconnectDomainList = IXSP
              .getDisconnectDomains()
              .map((e) => e.toJson())
              .toList();
          request['disconnectDomainList'] = disconnectDomainList;
        }
        request['locationId'] = locationId;
        request['locationCode'] = locationCode;
        final result = await ApiRouter().getDispatchInfo(
          request,
          cancelToken: cancelToken,
        );

        if (!result.success) {
          throw Failure(
            code: result.errorCode ?? '',
            message: result.errorMessage ?? '',
          );
        }
        if (IXSP.getDisconnectDomains().isNotEmpty) {
          IXSP.clearDisconnectDomains();
        }
        // 重置禁用状态
        IXSP.setLastIsRegionDisabled(false);
        IXSP.setLastIsUserDisabled(false);

        final launchData = Launch.fromJson(result.data);

        // 更新URL列表
        await ApiDomains.instance.updateFromLaunch(launchData);

        // 保存app配置
        await IXSP.saveAppConfig(launchData.appConfig!);
        // 保存vpn配置
        // await IXSP.saveVpnConfig(launchData.vpnConfig!);

        return launchData;
      } on ApiException catch (_) {
        rethrow;
      } on Failure catch (_) {
        rethrow;
      } on DioException catch (e) {
        if (e.response?.statusCode == Errors.eRegionNotAvailable ||
            e.response?.statusCode == Errors.eUserDisabled ||
            e.response?.statusCode == Errors.eTokenExpired) {
          rethrow;
        } else {
          if (await NetworkHelper.instance.isNetworkAvailable()) {
            final url = await ApiDomains.instance.getNextRouterUrl();
            log(TAG, 'Launch request failed for URL $url: $e');
            if (url.isEmpty) {
              rethrow;
            }
            ApiRouter().setbaseUrl(url);
          } else {
            rethrow;
          }
        }
      } catch (e) {
        final url = await ApiDomains.instance.getNextRouterUrl();
        log(TAG, 'Launch request failed for URL $url: $e');
        if (url.isEmpty) {
          rethrow;
        }
        ApiRouter().setbaseUrl(url);
      }
    }
  }
}
