import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:recording_tool/core/network/api_exception.dart';
import 'package:recording_tool/core/network/api_response.dart';
import 'package:recording_tool/core/network/http_method.dart';

typedef JsonParser<T> = T Function(dynamic json);

class ApiClient {
  const ApiClient(this._dio);

  final Dio _dio;

  Future<T> request<T>(
    String path, {
    HttpMethod method = HttpMethod.get,
    Map<String, dynamic>? queryParameters,
    Object? data,
    Map<String, dynamic>? headers,
    JsonParser<T>? parser,
    bool wrapResponse = true,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
  }) async {
    try {
      final response = await _dio.request<dynamic>(
        path,
        queryParameters: queryParameters,
        data: data,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        options: Options(method: method.value, headers: headers),
      );

      final raw = _decodeIfNeeded(response.data);
      if (!wrapResponse) {
        return _parseData<T>(raw, parser);
      }

      final payload = raw is Map ? Map<String, dynamic>.from(raw) : null;
      if (payload == null ||
          !(payload.containsKey('code') || payload.containsKey('message'))) {
        return _parseData<T>(raw, parser);
      }

      // 先按 {code,message,data} 解包，再用业务 parser 解析 data，
      // 避免把 Map 直接强转成业务模型。
      final wrapped = ApiResponse<dynamic>.fromJson(payload);
      if (!wrapped.isSuccess) {
        throw ApiException(
          code: wrapped.code,
          statusCode: response.statusCode,
          message: wrapped.message.isEmpty ? '请求失败' : wrapped.message,
          details: raw,
        );
      }

      if (wrapped.data == null) {
        if (null is T) return null as T;
        throw ApiException(
          code: wrapped.code,
          statusCode: response.statusCode,
          message: '响应 data 为空',
          details: raw,
        );
      }

      return _parseData<T>(wrapped.data, parser);
    } on DioException catch (error) {
      throw _mapDioException(error);
    }
  }

  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    JsonParser<T>? parser,
    bool wrapResponse = true,
  }) {
    return request<T>(
      path,
      method: HttpMethod.get,
      queryParameters: queryParameters,
      parser: parser,
      wrapResponse: wrapResponse,
    );
  }

  Future<T> post<T>(
    String path, {
    Object? data,
    JsonParser<T>? parser,
    bool wrapResponse = true,
  }) {
    return request<T>(
      path,
      method: HttpMethod.post,
      data: data,
      parser: parser,
      wrapResponse: wrapResponse,
    );
  }

  dynamic _decodeIfNeeded(dynamic data) {
    if (data is String) {
      try {
        return jsonDecode(data);
      } catch (_) {
        return data;
      }
    }
    return data;
  }

  T _parseData<T>(dynamic data, JsonParser<T>? parser) {
    if (parser != null) return parser(data);
    return data as T;
  }

  ApiException _mapDioException(DioException error) {
    final statusCode = error.response?.statusCode;
    final message = switch (error.type) {
      DioExceptionType.connectionTimeout => '网络连接超时',
      DioExceptionType.transformTimeout => '网络请求处理超时',
      DioExceptionType.sendTimeout => '请求发送超时',
      DioExceptionType.receiveTimeout => '响应接收超时',
      DioExceptionType.badCertificate => '证书校验失败',
      DioExceptionType.badResponse => '服务器响应异常',
      DioExceptionType.cancel => '请求已取消',
      DioExceptionType.connectionError => '网络连接不可用',
      DioExceptionType.unknown => '网络请求失败',
    };

    return ApiException(
      message: message,
      statusCode: statusCode,
      details: error,
    );
  }
}
