import 'package:dio/dio.dart';
import 'api_exception.dart';
import 'api_response.dart';
import 'mock_interceptor.dart';

class ApiClient {
  late final Dio _dio;
  String? _token;
  final String baseUrl;
  final bool useMock;

  ApiClient({required this.baseUrl, this.useMock = false}) {
    _dio = Dio(BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 15),
      headers: {'Content-Type': 'application/json'},
    ));

    _dio.interceptors.add(MockInterceptor(enabled: useMock));

    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        if (_token != null) {
          options.headers['Authorization'] = 'Bearer $_token';
        }
        handler.next(options);
      },
      onResponse: (response, handler) {
        final body = response.data;
        if (body is Map<String, dynamic>) {
          final code = body['code'] as int? ?? -1;
          if (code != 0) {
            handler.reject(DioException(
              requestOptions: response.requestOptions,
              response: response,
              error: ApiException(
                code: code,
                message: body['message'] as String? ?? '未知错误',
              ),
            ));
            return;
          }
        }
        handler.next(response);
      },
      onError: (error, handler) {
        if (error.type == DioExceptionType.connectionTimeout ||
            error.type == DioExceptionType.receiveTimeout) {
          handler.next(DioException(
            requestOptions: error.requestOptions,
            error: const NetworkException('网络连接超时'),
          ));
          return;
        }
        handler.next(error);
      },
    ));
  }

  void setToken(String? token) => _token = token;

  Future<ApiResponse<T>> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    T Function(dynamic json)? fromJsonT,
  }) async {
    final response = await _dio.get(path, queryParameters: queryParameters);
    return ApiResponse.fromJson(response.data, fromJsonT);
  }

  Future<ApiResponse<T>> post<T>(
    String path, {
    dynamic data,
    T Function(dynamic json)? fromJsonT,
  }) async {
    final response = await _dio.post(path, data: data);
    return ApiResponse.fromJson(response.data, fromJsonT);
  }

  Future<ApiResponse<T>> put<T>(
    String path, {
    dynamic data,
    T Function(dynamic json)? fromJsonT,
  }) async {
    final response = await _dio.put(path, data: data);
    return ApiResponse.fromJson(response.data, fromJsonT);
  }

  Future<ApiResponse<T>> delete<T>(
    String path, {
    T Function(dynamic json)? fromJsonT,
  }) async {
    final response = await _dio.delete(path);
    return ApiResponse.fromJson(response.data, fromJsonT);
  }
}
