import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:get/get.dart' as getx;
import '../../../config/translations/strings_enum.dart';
import '../../../utils/log/logger.dart';
import '../../components/country_restricted_overlay.dart';
import '../../data/models/api_result.dart';

enum DomainType {
  api, // 普通API域名
  log, // 日志上传域名
  file, // 文件上传域名
}

/// HTTP请求方法
enum RequestMethod { get, post, put, delete, patch }

/// 重试状态类
class _RetryState {
  int currentRetry = 0;
  bool isRetrying = false;

  void reset() {
    currentRetry = 0;
    isRetrying = false;
  }
}

/// API封装类
abstract class BaseApi {
  final CancelToken _cancelToken = CancelToken();

  late final Dio dio;

  // 不同类型域名的最大重试次数
  static const Map<DomainType, int> _maxRetries = {
    DomainType.api: 0, // API域名最多重试3次
    DomainType.log: 0, // 日志上传最多重试1次
    DomainType.file: 0, // 文件上传最多重试1次
  };

  // 当前重试状态
  final Map<DomainType, _RetryState> _retryStates = {
    DomainType.api: _RetryState(),
    DomainType.log: _RetryState(),
    DomainType.file: _RetryState(),
  };

  String _baseUrl = '';
  Map<String, String> _hostIpMap = {}; // 需要绑定的 host -> ip
  var _proxy = ''; // 代理配置

  /// 设置API基础请求URL
  void setbaseUrl(String value, {bool? useProxy}) {
    try {
      // 参数验证
      if (value.isEmpty) {
        return;
      }

      // 解析URL和IP
      final urlConfig = _parseUrlConfig(value);
      if (urlConfig == null) {
        return;
      }

      final url = urlConfig['url']!;
      final ip = urlConfig['ip']!;

      // 验证URL格式
      if (!_isValidUrl(url)) {
        return;
      }

      if (ip.isNotEmpty) {
        // 验证IP格式
        if (!_isValidIp(ip)) {
          return;
        }
        // 解析URL获取host
        final uri = Uri.parse(url);
        if (dio.options.baseUrl == url && _hostIpMap[uri.host] == ip) {
          return;
        }
        _hostIpMap = {uri.host: ip};
        _baseUrl = value;
      } else {
        _hostIpMap = {};
        _baseUrl = url;
      }

      if (dio.options.baseUrl == url) {
        return;
      }
      dio.options.baseUrl = url;

      // 更新HttpClient
      _updateHttpClient();
    } catch (e) {
      log('BaseApi', 'setBaseUrl: $e');
    }
  }

  /// 获取API基础请求URL
  String get baseUrl => _baseUrl;

  /// 设置HTTP代理
  ///
  /// [proxy]为代理规则，如：PROXY 127.0.0.1:11029
  void setProxy(String proxy) {
    if (proxy.isNotEmpty) {
      _proxy = proxy;
      _updateHttpClient();
    }
  }

  void _updateHttpClient() {
    dio.httpClientAdapter = IOHttpClientAdapter(
      createHttpClient: () {
        final client = HttpClient();
        // client.findProxy = (uri) => proxy;
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;

        // 设置其他属性
        client.autoUncompress = true;

        // 设置用户代理
        client.userAgent = 'Nomo/1.0';

        // 设置连接工厂
        client.connectionFactory = (Uri uri, String? host, int? port) async {
          final resolvedHost = host ?? _hostIpMap[uri.host] ?? uri.host;
          final actualPort = port ?? uri.port;
          if (uri.scheme == 'https') {
            // 使用SecureSocket.connect建立真正的SSL连接
            return SecureSocket.startConnect(
              resolvedHost,
              actualPort,
              onBadCertificate: (X509Certificate cert) {
                return true; // 接受所有证书
              },
            );
          } else {
            // 对于HTTP，返回普通Socket连接
            return Socket.startConnect(resolvedHost, actualPort);
          }
        };

        client.findProxy = (uri) {
          if (_proxy.isNotEmpty) {
            return _proxy;
          }
          return 'DIRECT'; // 不使用代理
        };
        return client;
      },
    );
  }

  /// 解析URL配置字符串
  /// 格式: "https://www.google.com:443|ip=54.236.5.237"
  Map<String, String>? _parseUrlConfig(String value) {
    try {
      final parts = value.split('|ip=');
      if (parts.length != 2) {
        return {'url': value, 'ip': ""};
      }

      final url = parts[0].trim();
      final ip = parts[1].trim();

      if (url.isEmpty || ip.isEmpty) {
        return null;
      }

      return {'url': url, 'ip': ip};
    } catch (e) {
      return null;
    }
  }

  /// 验证URL格式
  bool _isValidUrl(String url) {
    try {
      final uri = Uri.parse(url);
      return uri.hasScheme && uri.hasAuthority;
    } catch (e) {
      return false;
    }
  }

  /// 验证IP地址格式
  bool _isValidIp(String ip) {
    try {
      final parts = ip.split('.');
      if (parts.length != 4) return false;

      for (final part in parts) {
        final num = int.tryParse(part);
        if (num == null || num < 0 || num > 255) {
          return false;
        }
      }
      return true;
    } catch (e) {
      return false;
    }
  }

  /// 重置HTTP代理
  void resetProxy() {
    _proxy = '';
    _updateHttpClient();
  }

  /// 获取默认Header
  Map<String, dynamic>? getDefaultHeader() {
    return null;
  }

  /// 获取默认Query
  Map<String, dynamic>? getDefaultQuery() {
    return null;
  }

  /// 加密数据
  dynamic encrypt(dynamic input) {
    return input;
  }

  /// 解密数据
  dynamic decrypt(dynamic input) {
    return input;
  }

  /// 反序列化API返回结果
  ApiResult getApiResult(Map<String, dynamic> map) {
    return ApiResult(
      success: map['success'] ?? false,
      data: map['data'],
      errorCode: map['errorCode'],
      errorMessage: map['errorMessage'],
    );
  }

  // /// 更新基础URL
  // void updateBaseUrl(String baseUrl) {
  //   dio.options.baseUrl = baseUrl;
  //   log('BaseApi', 'Base URL updated to: $baseUrl');
  // }

  /// 判断是否应该重试错误
  bool _shouldRetryError(DioException error, DomainType domainType) {
    final retryState = _retryStates[domainType]!;

    // 检查重试次数
    if (retryState.currentRetry >= (_maxRetries[domainType] ?? 3)) {
      return false;
    }

    // 网络错误、超时错误、服务器错误（5xx）都应该重试
    return checkDioException(error);
  }

  bool checkDioException(DioException error) {
    return error.type == DioExceptionType.connectionTimeout ||
        error.type == DioExceptionType.sendTimeout ||
        error.type == DioExceptionType.receiveTimeout ||
        error.type == DioExceptionType.connectionError ||
        (error.response != null &&
            error.response!.statusCode != null &&
            error.response!.statusCode! >= 500 &&
            error.response!.statusCode! < 600) ||
        (error.response != null &&
            error.response!.statusCode != null &&
            error.response!.statusCode! == 404);
  }

  /// 原始请求方法
  Future<ApiResult> rawRequest(
    RequestMethod method,
    String path, {
    dynamic data,
    Map<String, dynamic>? header,
    Map<String, dynamic>? query,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api, //  默认使用API域名
  }) async {
    final retryState = _retryStates[domainType]!;
    log('BaseApi', 'Request: $method ${dio.options.baseUrl}$path');
    try {
      // 重置重试状态
      if (!retryState.isRetrying) {
        retryState.currentRetry = 0;
      }

      // 合并默认Header和传入的Header
      final headers = {...?getDefaultHeader(), ...?header};

      // 合并默认Query和传入的Query
      final queries = {...?getDefaultQuery(), ...?query};

      // 设置请求选项
      final requestOptions = options ?? Options();
      requestOptions.headers = headers;

      // 根据请求方法发送请求
      Response response;

      switch (method) {
        case RequestMethod.get:
          response = await dio.get(
            path,
            queryParameters: queries,
            options: requestOptions,
            cancelToken: cancelToken,
          );
          break;
        case RequestMethod.post:
          response = await dio.post(
            path,
            data: data,
            queryParameters: queries,
            options: requestOptions,
            cancelToken: cancelToken,
          );
          break;
        case RequestMethod.put:
          response = await dio.put(
            path,
            data: data,
            queryParameters: queries,
            options: requestOptions,
            cancelToken: cancelToken,
          );
          break;
        case RequestMethod.delete:
          response = await dio.delete(
            path,
            data: data,
            queryParameters: queries,
            options: requestOptions,
            cancelToken: cancelToken,
          );
          break;
        case RequestMethod.patch:
          response = await dio.patch(
            path,
            data: data,
            queryParameters: queries,
            options: requestOptions,
            cancelToken: cancelToken,
          );
          break;
      }
      // 重置重试状态
      retryState.reset();

      // 先处理特殊状态码，不进行解密
      if (response.statusCode == 204) {
        getx.Get.offAll(
          () => const CountryRestrictedOverlay(),
          transition: getx.Transition.fadeIn,
        );
        return getApiResult({
          'success': false,
          'data': null,
          'errorCode': "${response.statusCode}",
          'errorMessage': Strings.regionRestricted.tr,
        });
      }

      // 正常状态码才进行解密
      if (response.statusCode == 200) {
        return getApiResult(decrypt(response.data));
      }

      // 其他状态码返回原始数据
      return getApiResult(response.data);
    } on DioException catch (e) {
      // 检查是否应该重试
      if (_shouldRetryError(e, domainType)) {
        retryState.isRetrying = true;
        retryState.currentRetry++;

        log(
          'BaseApi',
          'Request failed (${domainType.name}). Retrying (${retryState.currentRetry}/${_maxRetries[domainType]})...',
        );

        // 重试请求
        return rawRequest(
          method,
          path,
          data: data,
          header: header,
          query: query,
          options: options,
          cancelToken: cancelToken,
          domainType: domainType,
        );
      }

      // 重置重试状态
      retryState.reset();
      rethrow;
    } catch (e) {
      // 重置重试状态
      retryState.reset();
      rethrow;
    }
  }

  /// GET请求
  Future<dynamic> get(
    String path, {
    Map<String, dynamic>? query,
    Map<String, dynamic>? header,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api,
  }) async {
    return rawRequest(
      RequestMethod.get,
      path,
      query: query,
      header: header,
      options: options,
      cancelToken: cancelToken,
      domainType: domainType,
    );
  }

  /// POST请求
  Future<ApiResult> post(
    String path, {
    dynamic data,
    Map<String, dynamic>? query,
    Map<String, dynamic>? header,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api,
  }) async {
    // 加密数据
    final encryptedData = encrypt(data);

    return rawRequest(
      RequestMethod.post,
      path,
      data: encryptedData,
      query: query,
      header: header,
      options: options,
      cancelToken: cancelToken,
      domainType: domainType,
    );
  }

  /// PUT请求
  Future<dynamic> put(
    String path, {
    dynamic data,
    Map<String, dynamic>? query,
    Map<String, dynamic>? header,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api,
  }) async {
    // 加密数据
    final encryptedData = encrypt(data);

    return rawRequest(
      RequestMethod.put,
      path,
      data: encryptedData,
      query: query,
      header: header,
      options: options,
      cancelToken: cancelToken,
      domainType: domainType,
    );
  }

  /// DELETE请求
  Future<dynamic> delete(
    String path, {
    dynamic data,
    Map<String, dynamic>? query,
    Map<String, dynamic>? header,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api,
  }) async {
    // 加密数据
    final encryptedData = encrypt(data);

    return rawRequest(
      RequestMethod.delete,
      path,
      data: encryptedData,
      query: query,
      header: header,
      options: options,
      cancelToken: cancelToken,
      domainType: domainType,
    );
  }

  /// PATCH请求
  Future<dynamic> patch(
    String path, {
    dynamic data,
    Map<String, dynamic>? query,
    Map<String, dynamic>? header,
    Options? options,
    CancelToken? cancelToken,
    DomainType domainType = DomainType.api,
  }) async {
    // 加密数据
    final encryptedData = encrypt(data);

    return rawRequest(
      RequestMethod.patch,
      path,
      data: encryptedData,
      query: query,
      header: header,
      options: options,
      cancelToken: cancelToken,
      domainType: domainType,
    );
  }

  /// 取消所有未返回的请求
  void cancelRequests() {
    _cancelToken.cancel("cancelled");
  }
}
