import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'error_lexicon.dart';

class DioClient {
  static final DioClient _instance = DioClient._internal();
  late Dio _dio;
  final FlutterSecureStorage _storage = const FlutterSecureStorage();

  factory DioClient() {
    return _instance;
  }

  DioClient._internal() {
    // 백엔드 글로벌 prefix(/api) 와 일치
    final baseUrl = dotenv.maybeGet('API_URL') ?? 'http://localhost:3000/api';

    _dio = Dio(BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 15),
    ));

    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          // Token Storage 정책: SecureStorage 에서 JWT 읽어 헤더에 부착
          final token = await _storage.read(key: 'jwt_token');
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        onResponse: (response, handler) {
          final payload = response.data;

          if (payload is Map<String, dynamic> && payload.containsKey('success')) {
            if (payload['success'] == true) {
              // Global Response Wrapper: 데이터 Unwrap
              response.data = payload['data'];
              return handler.next(response);
            } else {
              // HTTP 200 OK 하에서의 비즈니스 실패 로직
              final errorCode = payload['error']?['code'] ?? 'BIZ_001';
              return handler.reject(
                DioException(
                  requestOptions: response.requestOptions,
                  error: ErrorLexicon.getMessage(errorCode),
                  type: DioExceptionType.badResponse,
                ),
              );
            }
          }
          return handler.next(response);
        },
        onError: (DioException e, handler) {
          String errorCode = 'SYS_001';

          if (e.response != null && e.response?.data is Map<String, dynamic>) {
            final payload = e.response!.data as Map<String, dynamic>;

            // 1. 서버에서 표준 에러 객체를 보낸 경우
            if (payload['error'] != null && payload['error']['code'] != null) {
              errorCode = payload['error']['code'];
            } else {
              // 2. 서버 에러 객체가 없는 경우 HTTP 상태 코드 기반 매핑
              final statusCode = e.response?.statusCode;
              if (statusCode == 401) {
                errorCode = 'AUTH_001';
              } else if (statusCode == 403) {
                errorCode = 'AUTH_003';
              } else if (statusCode == 400 || statusCode == 422) {
                errorCode = 'VAL_001';
              } else if (statusCode == 404) {
                errorCode = 'RES_001';
              }
            }
          } else if (e.type == DioExceptionType.connectionTimeout ||
              e.type == DioExceptionType.receiveTimeout) {
            errorCode = 'SYS_001';
          }

          final errorMessage = ErrorLexicon.getMessage(errorCode);

          // User-Friendly Error UI를 위해 에러 메시지 덮어쓰기
          final customError = e.copyWith(error: errorMessage);
          return handler.next(customError);
        },
      ),
    );
  }

  Dio get dio => _dio;
}
