import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../../../core/config/environment.dart';
import '../../../core/constants/app_constants.dart';
import 'interceptors/auth_interceptor.dart';
import 'interceptors/error_interceptor.dart';
import 'interceptors/logging_interceptor.dart';
import 'interceptors/response_interceptor.dart';

/// API 클라이언트 클래스
class ApiClient {
  late final Dio _dio;
  
  static ApiClient? _instance;
  
  factory ApiClient() {
    _instance ??= ApiClient._internal();
    return _instance!;
  }
  
  ApiClient._internal() {
    try {
      if (Environment.enableLogging && kDebugMode) {
        debugPrint('[ApiClient] 초기화 시작');
      }
      _dio = Dio(_baseOptions);
      if (Environment.enableLogging && kDebugMode) {
        debugPrint('[ApiClient] Dio 인스턴스 생성 완료');
        debugPrint('[ApiClient] Base URL: ${_dio.options.baseUrl}');
        debugPrint('[ApiClient] Connect Timeout: ${_dio.options.connectTimeout}');
        debugPrint('[ApiClient] Receive Timeout: ${_dio.options.receiveTimeout}');
      }
      _setupInterceptors();
      if (Environment.enableLogging && kDebugMode) {
        debugPrint('[ApiClient] 인터셉터 설정 완료');
      }
    } catch (e, stackTrace) {
      if (kDebugMode) {
        debugPrint('[ApiClient] ⚠️ 에러 발생: $e');
        debugPrint('[ApiClient] Stack trace: $stackTrace');
      }
      // 기본값으로 초기화
      _dio = Dio(BaseOptions(
        baseUrl: 'http://43.201.34.104:8080/api/v1',
        connectTimeout: AppConstants.apiConnectTimeout,
        receiveTimeout: AppConstants.apiReceiveTimeout,
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      ));
      _setupInterceptors();
      if (kDebugMode) {
        debugPrint('[ApiClient] 기본값으로 초기화 완료');
      }
    }
  }
  
  /// Dio 인스턴스 getter
  Dio get dio => _dio;
  
  /// 기본 옵션 설정
  BaseOptions get _baseOptions {
    try {
      return BaseOptions(
        baseUrl: Environment.apiBaseUrl,
        connectTimeout: Duration(milliseconds: Environment.apiTimeout),
        receiveTimeout: Duration(milliseconds: Environment.apiTimeout),
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
        validateStatus: (status) {
          return status != null && status < 500;
        },
      );
    } catch (e) {
      // Environment가 초기화되지 않은 경우 기본값 사용
      return BaseOptions(
        baseUrl: 'http://43.201.34.104:8080/api/v1',
        connectTimeout: AppConstants.apiConnectTimeout,
        receiveTimeout: AppConstants.apiReceiveTimeout,
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
        validateStatus: (status) {
          return status != null && status < 500;
        },
      );
    }
  }
  
  /// 인터셉터 설정
  void _setupInterceptors() {
    _dio.interceptors.clear();
    
    // 로깅 인터셉터 (개발 환경에서만) - 가장 먼저 추가하여 모든 요청/응답을 로깅
    try {
      if (Environment.enableLogging && kDebugMode) {
        _dio.interceptors.add(LoggingInterceptor());
      }
    } catch (e) {
      // Environment 접근 실패 시 디버그 모드에서만 로깅 활성화
      if (kDebugMode) {
        _dio.interceptors.add(LoggingInterceptor());
      }
    }
    
    // 인증 인터셉터 - 요청에 토큰 추가 및 401 처리
    _dio.interceptors.add(AuthInterceptor(_dio));
    
    // 응답 정규화 인터셉터 - 성공 응답을 일관된 형식으로 변환
    _dio.interceptors.add(ResponseInterceptor());
    
    // 에러 처리 인터셉터 - 마지막에 추가하여 모든 에러를 캐치
    _dio.interceptors.add(ErrorInterceptor());
  }
  
  /// 토큰 업데이트
  void updateAuthToken(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }
  
  /// 토큰 제거
  void removeAuthToken() {
    _dio.options.headers.remove('Authorization');
  }
  
  /// GET 요청
  Future<Response<T>> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) {
    return _dio.get<T>(
      path,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onReceiveProgress: onReceiveProgress,
    );
  }
  
  /// POST 요청
  Future<Response<T>> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) {
    if (Environment.enableLogging && kDebugMode) {
      debugPrint('[ApiClient] POST 요청 시작: $path');
      debugPrint('[ApiClient] 요청 데이터: $data');
    }
    
    return _dio.post<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    ).then((response) {
      if (Environment.enableLogging && kDebugMode) {
        debugPrint('[ApiClient] POST 응답 수신: ${response.statusCode}');
      }
      return response;
    }).catchError((error) {
      if (Environment.enableLogging && kDebugMode) {
        debugPrint('[ApiClient] POST 에러 발생: $error');
        if (error is DioException) {
          debugPrint('[ApiClient] DioException 타입: ${error.type}');
          debugPrint('[ApiClient] DioException 메시지: ${error.message}');
          debugPrint('[ApiClient] DioException 에러: ${error.error}');
        }
      }
      throw error;
    });
  }
  
  /// PUT 요청
  Future<Response<T>> put<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) {
    return _dio.put<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }
  
  /// PATCH 요청
  Future<Response<T>> patch<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) {
    return _dio.patch<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }
  
  /// DELETE 요청
  Future<Response<T>> delete<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) {
    return _dio.delete<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    );
  }
  
  /// 파일 업로드
  Future<Response<T>> uploadFile<T>(
    String path, {
    required String filePath,
    required String fileFieldName,
    Map<String, dynamic>? additionalData,
    ProgressCallback? onSendProgress,
    CancelToken? cancelToken,
  }) async {
    final fileName = filePath.split('/').last;
    final formData = FormData.fromMap({
      fileFieldName: await MultipartFile.fromFile(
        filePath,
        filename: fileName,
      ),
      ...?additionalData,
    });
    
    return _dio.post<T>(
      path,
      data: formData,
      options: Options(
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      ),
      onSendProgress: onSendProgress,
      cancelToken: cancelToken,
    );
  }
  
  /// 파일 다운로드
  Future<Response> downloadFile(
    String path, {
    required String savePath,
    ProgressCallback? onReceiveProgress,
    CancelToken? cancelToken,
    Map<String, dynamic>? queryParameters,
  }) {
    return _dio.download(
      path,
      savePath,
      queryParameters: queryParameters,
      onReceiveProgress: onReceiveProgress,
      cancelToken: cancelToken,
      options: Options(
        responseType: ResponseType.bytes,
        followRedirects: false,
      ),
    );
  }
}