import 'dart:async';

import 'package:dio/dio.dart';
import '../config/api_config.dart';
import '../services/storage_service.dart';
import '../core/exceptions/app_exception.dart';
import '../core/utils/app_logger.dart';

/// API响应
class ApiResponse<T> {
  final int code;
  final String message;
  final dynamic data;
  final String? error;
  final String? correlationId;

  ApiResponse({
    required this.code,
    required this.message,
    this.data,
    this.error,
    this.correlationId,
  });

  factory ApiResponse.fromJson(Map<String, dynamic> json) {
    return ApiResponse<T>(
      code: json['code'] as int? ?? 0,
      message: json['msg'] as String? ?? '',
      data: json['data'],
      error: json['error'] as String?,
      correlationId: json['correlation_id'] as String?,
    );
  }

  bool get isSuccess => code == 0;

  bool get isContinue => code == 203;
}

/// API服务
class ApiService {
  late Dio _dio;
  static ApiService? _instance;
  bool _isRefreshing = false;
  final List<Completer<void>> _refreshSubscribers = [];
  bool _initialized = false;

  /// 获取 token 的回调
  Future<String?> Function()? getTokenCallback;

  /// 刷新 token 的回调
  Future<void> Function()? refreshTokenCallback;

  /// 清除认证数据的回调
  Future<void> Function()? clearAuthCallback;

  ApiService._() {
    _dio = Dio(
      BaseOptions(
        baseUrl: ApiConfig.defaultBaseUrl,
        connectTimeout: const Duration(seconds: ApiConfig.connectTimeout),
        receiveTimeout: const Duration(seconds: ApiConfig.receiveTimeout),
        sendTimeout: const Duration(seconds: ApiConfig.sendTimeout),
        headers: {'Content-Type': 'application/json'},
      ),
    );

    _dio.interceptors.add(_requestInterceptor());
    _dio.interceptors.add(_responseInterceptor());
    _dio.interceptors.add(_errorInterceptor());
  }

  /// 是否正在刷新token
  bool get isRefreshing => _isRefreshing;

  /// 暴露 Dio 实例（用于二进制下载等不走 _parseResponse 的场景）
  Dio get dio => _dio;

  /// 获取单例
  static ApiService get instance {
    _instance ??= ApiService._();
    return _instance!;
  }

  /// 设置认证回调
  /// 由 AuthProvider 在初始化时调用
  static void setAuthCallbacks({
    required Future<String?> Function() getToken,
    required Future<void> Function() refreshToken,
    required Future<void> Function() clearAuth,
  }) {
    final service = instance;
    service.getTokenCallback = getToken;
    service.refreshTokenCallback = refreshToken;
    service.clearAuthCallback = clearAuth;
  }

  /// 初始化API服务（设置正确的baseUrl）
  Future<void> init() async {
    if (_initialized) return;

    final baseUrl = await ApiConfig.baseUrl;
    _dio.options.baseUrl = baseUrl;
    _initialized = true;
  }

  /// 动态设置 API baseUrl
  Future<void> setBaseUrl(String baseUrl) async {
    _dio.options.baseUrl = baseUrl;
    AppLogger.d('ApiService baseUrl 已更新为: $baseUrl');
  }

  /// 请求拦截器
  Interceptor _requestInterceptor() {
    return InterceptorsWrapper(
      onRequest: (options, handler) async {
        // 从回调获取 Token
        if (getTokenCallback != null) {
          final token = await getTokenCallback!();
          if (token != null && token.isNotEmpty) {
            options.headers['Authorization'] = 'Bearer $token';
          }
        }
        // 附加 X-Cr-Client-Id，服务端据此过滤 SSE 自身事件
        try {
          final clientId = await StorageService.instance.getOrCreateClientId();
          options.headers['X-Cr-Client-Id'] = clientId;
        } catch (_) {}
        return handler.next(options);
      },
    );
  }

  /// 响应拦截器
  Interceptor _responseInterceptor() {
    return InterceptorsWrapper(
      onResponse: (response, handler) {
        AppLogger.d(
          'API Response: ${response.statusCode} - ${response.requestOptions.uri}',
        );

        // 检查 JSON 响应中的 code 字段
        if (response.data is Map<String, dynamic>) {
          final data = response.data as Map<String, dynamic>;
          final code = data['code'] as int?;
          AppLogger.d('_responseInterceptor -> JSON code: $code');
          if (code == 401) {
            // HTTP 200 但 JSON code 是 401，需要处理未授权
            final isNoAuth =
                response.requestOptions.extra['noAuth'] as bool? ?? false;
            AppLogger.d('_responseInterceptor -> isNoAuth: $isNoAuth');
            if (!isNoAuth) {
              // 直接在响应拦截器中处理 401
              AppLogger.d('_responseInterceptor -> 触发 401 处理');
              // 异步处理，不阻塞响应
              _handle401InResponse(response.requestOptions);
            }
          }
        }
        return handler.next(response);
      },
    );
  }

  /// 在响应拦截器中处理 401 错误
  Future<void> _handle401InResponse(RequestOptions requestOptions) async {
    final path = requestOptions.path;
    if (path.contains('/session/token/refresh')) {
      return;
    }

    if (_isRefreshing) {
      return;
    }

    _isRefreshing = true;
    try {
      AppLogger.d('_handle401InResponse -> 开始刷新 token');
      if (refreshTokenCallback != null) {
        await refreshTokenCallback!();
      }
      AppLogger.d('_handle401InResponse -> token 刷新完成');
    } catch (e) {
      AppLogger.d('_handle401InResponse -> 刷新失败: $e');
      if (clearAuthCallback != null) {
        await clearAuthCallback!();
      }
    } finally {
      _isRefreshing = false;
    }
  }

  /// 错误拦截器
  Interceptor _errorInterceptor() {
    return InterceptorsWrapper(
      onError: (error, handler) async {
        AppLogger.d("_errorInterceptor -> 获取files列表: response");
        AppLogger.d('API Error: ${error.requestOptions.uri} - ${error.message}');

        // 检查是否是 401 错误（HTTP 401 或 JSON code: 401）
        final silent404 =
            error.requestOptions.extra['silent404'] as bool? ?? false;
        if (silent404 && error.response?.statusCode == 404) {
          return handler.next(error);
        }

        bool is401Error = error.response?.statusCode == 401;
        if (!is401Error && error.response?.data is Map<String, dynamic>) {
          final data = error.response!.data as Map<String, dynamic>;
          is401Error = data['code'] == 401;
        }

        if (is401Error) {
          final isNoAuth =
              error.requestOptions.extra['noAuth'] as bool? ?? false;
          if (!isNoAuth) {
            // 不是noAuth请求，需要刷新token
            final response = await _handle401Error(error, handler);
            if (response != null) {
              return handler.resolve(response);
            }
          }
        }

        // 处理错误
        if (error.response == null) {
          // 网络错误
          throw NetworkException(
            '网络连接失败，请检查网络设置',
            code: error.response?.statusCode,
          );
        }

        final statusCode = error.response?.statusCode;
        final responseData = error.response?.data;

        AppLogger.d('Error Response Data: $responseData');

        if (responseData is Map<String, dynamic>) {
          final response = ApiResponse.fromJson(responseData);
          throw ServerException(response.message, code: response.code);
        }

        throw ServerException(
          responseData?.toString() ?? '请求失败',
          code: statusCode,
        );
      },
    );
  }

  /// 处理401错误，尝试刷新token
  Future<Response?> _handle401Error(
    DioException error,
    ErrorInterceptorHandler handler,
  ) async {
    // 检查是否需要跳过token检查（如刷新token请求本身）
    final path = error.requestOptions.path;
    if (path.contains('/session/token/refresh')) {
      // 刷新token的请求也失败了，直接返回错误
      return null;
    }

    // 如果正在刷新token，等待刷新完成后再重试
    if (_isRefreshing) {
      final completer = Completer<void>();
      _refreshSubscribers.add(completer);

      // 等待刷新完成
      await completer.future;

      // 刷新完成后，移除旧的 Authorization header，让拦截器重新添加新 token
      error.requestOptions.headers.remove('Authorization');

      // 重试请求（拦截器会自动添加新 token）
      return await _dio.fetch(error.requestOptions);
    }

    // 开始刷新token
    _isRefreshing = true;

    try {
      // 调用回调刷新 token
      if (refreshTokenCallback != null) {
        await refreshTokenCallback!();
      }

      _isRefreshing = false;

      // 通知所有等待的请求可以重试了
      for (final subscriber in _refreshSubscribers) {
        if (!subscriber.isCompleted) {
          subscriber.complete();
        }
      }
      _refreshSubscribers.clear();

      // 重试当前请求：移除旧 header，让拦截器重新添加新 token
      error.requestOptions.headers.remove('Authorization');
      return await _dio.fetch(error.requestOptions);
    } catch (e) {
      AppLogger.d('Refresh token failed: $e');
      _isRefreshing = false;

      // 刷新失败，清除认证数据
      if (clearAuthCallback != null) {
        await clearAuthCallback!();
      }

      // 通知所有等待的请求
      for (final subscriber in _refreshSubscribers) {
        if (!subscriber.isCompleted) {
          subscriber.completeError(e);
        }
      }
      _refreshSubscribers.clear();

      // 返回null，让原始错误继续传播
      return null;
    }
  }

  /// GET请求 , 如果是分享请求, 则不进入 _parseResponse
  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    bool noAuth = false,
    bool isNoData = false,
    bool silent404 = false,
    Map<String, dynamic>? headers,
  }) async {
    final response = await _dio.get<T>(
      path,
      queryParameters: queryParameters,
      options: Options(
        extra: {'noAuth': noAuth, 'silent404': silent404},
        headers: headers,
      ),
    );
    // 如果是分享请求, 则不进入 _parseResponse
    if (isNoData) {
      return response.data as T;
    }
    return _parseResponse<T>(response);
  }

  /// POST请求
  Future<T> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    bool noAuth = false,
    Map<String, dynamic>? headers,
    bool isNoData = false,
  }) async {
    AppLogger.d('API POST Request: $path');
    AppLogger.d('Request Data: $data');

    final response = await _dio.post<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: Options(extra: {'noAuth': noAuth}, headers: headers),
    );

    AppLogger.d('Response Data: ${response.data}');
    
    var isActivEmail = 0;
    if (response.statusCode == 200 && response.data is Map) {
      final tmp = Map<String, dynamic>.from(response.data as Map);
      final code = tmp['code'];
      if (code is int) {
        isActivEmail = code;
      }
    }

    if (isNoData || isActivEmail == 203) {
      return response.data as T;
    }

    return _parseResponse<T>(response);
  }

  /// POST请求（带上传进度）
  Future<T> postWithProgress<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    bool noAuth = false,
    Map<String, dynamic>? headers,
    ProgressCallback? onSendProgress,
  }) async {
    AppLogger.d('API POST Request with progress: $path');

    final response = await _dio.post<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: Options(extra: {'noAuth': noAuth}, headers: headers),
      onSendProgress: onSendProgress,
    );

    AppLogger.d('Response Data: ${response.data}');

    return _parseResponse<T>(response);
  }

  /// PUT请求
  Future<T> put<T>(
    String path, {
    dynamic data,
    bool noAuth = false,
    bool isNoData = false,
  }) async {
    final response = await _dio.put<T>(
      path,
      data: data,
      options: Options(extra: {'noAuth': noAuth}),
    );
    // 当请求的接口为创建分享时, 逻辑上不适合走到 _parseResponse -> ApiResponse.fromJson 直接返回结果即可
    if (isNoData) {
      return response.data as T;
    }
    return _parseResponse<T>(response);
  }

  /// PATCH请求
  Future<T> patch<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    bool noAuth = false,
  }) async {
    final response = await _dio.patch<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: Options(extra: {'noAuth': noAuth}),
    );
    return _parseResponse<T>(response);
  }

  /// DELETE请求
  Future<T> delete<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    bool noAuth = false,
  }) async {
    final response = await _dio.delete<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: Options(extra: {'noAuth': noAuth}),
    );
    return _parseResponse<T>(response);
  }

  /// 解析响应
  T _parseResponse<T>(Response response) {
    final data = response.data;
    if (data is Map<String, dynamic>) {
      final apiResponse = ApiResponse<dynamic>.fromJson(data);
      if (!apiResponse.isSuccess && !apiResponse.isContinue) {
        throw ServerException(apiResponse.message, code: apiResponse.code);
      }
      final payload = apiResponse.data;
      if (payload is T) {
        return payload;
      }
      if (data is T) {
        return data as T;
      }
      return payload as T;
    }
    return data as T;
  }
}
