import 'dart:developer' as developer;
import 'dart:io' show Platform, SocketException;

import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import '../../providers/app_provider.dart'
    show backendLangFromLocale, localeProvider;
import '../../providers/node_provider.dart';
import '../config/app_config.dart';
import 'api_response.dart';

/// 解析统一响应里的业务 [code]（部分接口会返回字符串格式的 code）
int _parseApiCode(dynamic value) {
  if (value == null) {
    return 0;
  }
  if (value is int) {
    return value;
  }
  if (value is String) {
    return int.tryParse(value) ?? 0;
  }
  if (value is num) {
    return value.toInt();
  }
  return 0;
}

/// Token 存储 Key（与 auth_repository.dart 保持一致）
const _kAccessToken = 'auth_token';

/// 故障转移重试计数 key，挂在 RequestOptions.extra 上随请求流转。
/// 每次 failover 重试 +1，达到当前节点池大小后停止，避免无限循环。
const _kRetryCountKey = '_nodeRetryCount';

/// Token 内存缓存 — 避免每次 HTTP 请求都读 iOS Keychain
/// 由 auth_repository 的 _saveSession/_clearSession 维护一致性
String? _cachedToken;

/// 供 auth_repository 在登录/登出时更新缓存
void updateCachedToken(String? token) => _cachedToken = token;

/// 会话过期标志 — Dio 拦截器检测到 4000 时置 true，由路由监听并触发登出
final sessionExpiredProvider = StateProvider<bool>((ref) => false);

/// 版本过期标志 — Dio 拦截器检测到 4099 时置 true，由 HomeScreen 监听并触发更新弹窗
final versionOutdatedProvider = StateProvider<bool>((ref) => false);

/// Dio 单例 Provider
final dioClientProvider = Provider<Dio>((ref) {
  // 从 NodeProvider 获取当前 API Host（可能为空，回退到编译时默认值）
  final nodeState = ref.read(nodeProvider);
  // Debug/Profile：始终以 env_debug + AppConfig 为准，避免本地节点缓存（旧 apitest 等）覆盖编译时环境
  final initialBaseUrl = AppConfig.isDebug
      ? AppConfig.effectiveApiBaseUrl
      : (nodeState.currentNode?.normalizedApiHost ??
          AppConfig.effectiveApiBaseUrl);

  final dio = Dio(
    BaseOptions(
      baseUrl: initialBaseUrl,
      connectTimeout: const Duration(milliseconds: AppConfig.connectTimeoutMs),
      receiveTimeout: const Duration(milliseconds: AppConfig.receiveTimeoutMs),
      headers: {'Content-Type': 'application/json'},
    ),
  );

  // Release：节点切换时更新 baseUrl；Debug 固定走 env_debug，不跟节点池
  if (!AppConfig.isDebug) {
    ref.listen(nodeProvider, (prev, next) {
      final newHost = next.currentNode?.normalizedApiHost;
      if (newHost != null && dio.options.baseUrl != newHost) {
        developer.log(
          'Dio baseUrl switched: ${dio.options.baseUrl} → $newHost',
          name: 'Node',
        );
        dio.options.baseUrl = newHost;
      }
    });
  }

  // ── 拦截器：Token 注入 ──────────────────────────────
  dio.interceptors.add(
    InterceptorsWrapper(
      onRequest: (options, handler) async {
        // 优先用内存缓存；无缓存时才读 Keychain（仅首次或缓存失效时）
        String? token = _cachedToken;
        if (token == null) {
          token = await const FlutterSecureStorage().read(key: _kAccessToken);
          _cachedToken = token; // 写入缓存，后续请求直接用
        }
        if (token != null && token.isNotEmpty) {
          options.headers['x-auth-token'] = token;
        }
        options.headers['x-app-version'] = AppConfig.appVersion;
        options.headers['x-app-platform'] = Platform.isIOS ? '1' : '0';
        options.headers['lang'] = _resolveLang(ref);
        handler.next(options);
      },
      onResponse: (response, handler) async {
        // 打印接口返回的原始内容
        developer.log(
          '${response.requestOptions.method} ${response.requestOptions.uri}\n'
          'Response: ${response.data}',
          name: 'API',
        );
        // 解包统一响应格式 { code, data, message }
        final body = response.data;
        if (body is Map<String, dynamic>) {
          final code = _parseApiCode(body['code']);
          if (code != 0) {
            // 4000 = 登录已过期：只触发一次，避免并发请求重复弹窗
            // 先检查 token 是否还在：若已被清除说明用户主动退出，跳过过期弹窗
            if (code == 4000 && !ref.read(sessionExpiredProvider)) {
              final existingToken = _cachedToken;
              if (existingToken != null && existingToken.isNotEmpty) {
                _cachedToken = null; // 清除内存缓存
                await const FlutterSecureStorage().delete(key: _kAccessToken);
                ref.read(sessionExpiredProvider.notifier).state = true;
              }
            }
            // 4099 = 版本过低：触发更新弹窗，只触发一次
            if (code == 4099 && !ref.read(versionOutdatedProvider)) {
              ref.read(versionOutdatedProvider.notifier).state = true;
            }
            handler.reject(
              DioException(
                requestOptions: response.requestOptions,
                error: ApiException(
                  code: code,
                  message: body['message']?.toString() ??
                      body['msg']?.toString() ??
                      'Unknown error',
                ),
                type: DioExceptionType.badResponse,
                response: response,
              ),
            );
            return;
          }
        }
        // 请求成功 → 重置失败计数
        ref.read(nodeProvider.notifier).reportSuccess();
        handler.next(response);
      },
      onError: (error, handler) async {
        // 打印错误响应内容
        developer.log(
          '${error.requestOptions.method} ${error.requestOptions.uri}\n'
          'Error [${error.response?.statusCode}]: ${error.response?.data}',
          name: 'API',
        );

        // 401 = HTTP 未授权 → 清除 Token 并触发登出（防重复）
        final isHttp401 = error.response?.statusCode == 401;
        if (isHttp401 && !ref.read(sessionExpiredProvider)) {
          _cachedToken = null; // 清除内存缓存
          await const FlutterSecureStorage().delete(key: _kAccessToken);
          ref.read(sessionExpiredProvider.notifier).state = true;
          handler.next(error);
          return;
        }

        // ── 故障转移：网络级错误触发，硬错误立即切节点 ─────
        if (_isNetworkError(error)) {
          final retryCount =
              (error.requestOptions.extra[_kRetryCountKey] as int?) ?? 0;
          // 上限 = 当前节点池大小，最多挨个试一遍后放弃
          final maxRetries = ref.read(nodeProvider).nodes.length;

          if (retryCount < maxRetries) {
            // DNS / connect / timeout = 硬网络错误，第一次就切；5xx 仍走累积阈值
            final isHard = _isHardNetworkError(error);
            final switched = ref
                .read(nodeProvider.notifier)
                .reportFailure(immediate: isHard);
            if (switched) {
              try {
                final opts = error.requestOptions;
                opts.baseUrl = dio.options.baseUrl; // 已被 listen 更新
                opts.extra[_kRetryCountKey] = retryCount + 1;
                final response = await dio.fetch(opts);
                handler.resolve(response);
                return;
              } catch (_) {
                // 重试链路最终失败，透传原始错误（递归 onError 已尝试更多节点）
              }
            }
          }
        }

        // ── 错误归一化：所有恢复尝试都失败后，把原始 SocketException /
        //    "Failed host lookup" 之类的技术错误替换成多语言友好文案，
        //    避免 UI 直接 toast 出底层 dart 错误。
        if (_isNetworkError(error) && error.error is! ApiException) {
          handler.next(_normalizeNetworkError(ref, error));
          return;
        }

        handler.next(error);
      },
    ),
  );

  // ── 拦截器：日志（仅 Debug）──────────────────────────
  if (AppConfig.isDebug) {
    dio.interceptors.add(
      PrettyDioLogger(
        requestHeader: true,
        requestBody: true,
        responseBody: false,
        error: true,
        compact: true,
      ),
    );
  }

  return dio;
});

/// 判断是否为网络级错误（值得故障转移重试的）
bool _isNetworkError(DioException error) {
  switch (error.type) {
    case DioExceptionType.connectionTimeout:
    case DioExceptionType.sendTimeout:
    case DioExceptionType.receiveTimeout:
    case DioExceptionType.connectionError:
      return true;
    case DioExceptionType.badResponse:
      // 5xx 服务端错误也视为网络级故障
      final code = error.response?.statusCode ?? 0;
      return code >= 500;
    default:
      // unknown 里通常是 SocketException("Failed host lookup") 等 DNS 失败
      final inner = error.error;
      if (inner is SocketException) return true;
      return false;
  }
}

/// 判断是否为"硬"网络错误：DNS 失败、连不上、超时类。
/// 这类错误几乎可以判定当前节点不可用，应当立即 failover，
/// 而不是累积到 failoverThreshold 才切（首屏会等满 N 次超时）。
bool _isHardNetworkError(DioException error) {
  switch (error.type) {
    case DioExceptionType.connectionTimeout:
    case DioExceptionType.sendTimeout:
    case DioExceptionType.receiveTimeout:
    case DioExceptionType.connectionError:
      return true;
    case DioExceptionType.unknown:
      return error.error is SocketException;
    default:
      return false;
  }
}

/// 网络错误归一化错误码（与后端 4xxx 业务码隔离，避开 401/4000 等已用值）
const int _kErrCodeNetwork = -1001;
const int _kErrCodeTimeout = -1002;
const int _kErrCodeServer5xx = -1500;

/// 把底层 DioException 包装成带本地化文案的 ApiException，
/// UI 直接 toast `e.message` 即可，不再暴露 "Failed host lookup" 之类的技术细节。
DioException _normalizeNetworkError(Ref ref, DioException error) {
  final lang = _resolveLang(ref);
  final int code;
  final String message;
  switch (error.type) {
    case DioExceptionType.connectionTimeout:
    case DioExceptionType.sendTimeout:
    case DioExceptionType.receiveTimeout:
      code = _kErrCodeTimeout;
      message = _localizedTimeout(lang);
    case DioExceptionType.badResponse:
      code = _kErrCodeServer5xx;
      message = _localizedServerError(lang);
    default:
      code = _kErrCodeNetwork;
      message = _localizedNetworkError(lang);
  }
  return DioException(
    requestOptions: error.requestOptions,
    error: ApiException(code: code, message: message),
    type: error.type,
    response: error.response,
    stackTrace: error.stackTrace,
  );
}

/// 多语言文案：与 ARB 中 errNetworkError / errTimeout / errServiceUnavailable 对齐
String _localizedNetworkError(String lang) {
  switch (lang) {
    case 'en_US':
      return 'Network error, please check your connection and retry';
    case 'ja_JP':
      return 'ネットワークエラーです。接続を確認して再試行してください';
    case 'ko_KR':
      return '네트워크 오류, 연결을 확인 후 다시 시도하세요';
    case 'zh_HK':
      return '網絡連接異常，請檢查網絡設置後重試';
    default:
      return '网络连接异常，请检查网络设置后重试';
  }
}

String _localizedTimeout(String lang) {
  switch (lang) {
    case 'en_US':
      return 'Request timed out, please retry';
    case 'ja_JP':
      return 'リクエストがタイムアウトしました。再試行してください';
    case 'ko_KR':
      return '요청 시간 초과, 다시 시도하세요';
    case 'zh_HK':
      return '請求超時，請重試';
    default:
      return '请求超时，请重试';
  }
}

String _localizedServerError(String lang) {
  switch (lang) {
    case 'en_US':
      return 'Service temporarily unavailable, please retry later';
    case 'ja_JP':
      return 'サービスが一時的に利用できません。しばらくしてから再試行してください';
    case 'ko_KR':
      return '서비스를 일시적으로 사용할 수 없습니다. 잠시 후 다시 시도하세요';
    case 'zh_HK':
      return '服務暫時不可用，請稍後重試';
    default:
      return '服务暂不可用，请稍后重试';
  }
}

/// 与当前 `localeProvider` 一致的后端 lang（避免仅读 prefs 与 MaterialApp.locale 不同步）
String _resolveLang(Ref ref) {
  return backendLangFromLocale(ref.read(localeProvider));
}

/// 安全存储 Provider（供其他模块使用）
final secureStorageProvider = Provider<FlutterSecureStorage>(
  (_) => const FlutterSecureStorage(),
);
