import 'package:dio/dio.dart';
import '../../configs/api_paths.dart';
import '../../configs/constants.dart';
import '../../base/app_navigator.dart';
import '../../services/logout_service.dart';
import '../dio_http_service.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import '../../services/token_refresh_service.dart';

class AuthInterceptor extends Interceptor {
  bool _isHandlingAuth = false;
  static const _kAuthHandledKey = '__auth_handled__';
  
  // Danh sách các path không cần refresh token khi gặp lỗi auth
  static final List<String> _skipRefreshTokenPaths = [
    APIPaths.getUserInfo,
    APIPaths.login,
    APIPaths.refreshToken,
    APIPaths.logout,
    'assets',
  ];

  @override
  Future<void> onResponse(Response response, ResponseInterceptorHandler handler) async {
    final data = response.data;
    
    if (_isTokenInvalid(data)) {
      response.requestOptions.extra[_kAuthHandledKey] = true;
      // Kiểm tra xem path này có cần skip refresh token không
      if (_shouldSkipRefreshToken(response.requestOptions.path) || response.requestOptions.method == 'GET') {
        handler.reject(
          DioException(
            requestOptions: response.requestOptions
            ..extra['mapped_error'] = ErrorCodes.tokenInvalidMessage,
            response: response,
            type: DioExceptionType.badResponse,
            error: 'ERR_AUTH_TOKEN_INVALID',
            message: ErrorCodes.tokenInvalidMessage,
          ),
        );
        return;
      }
      
      await _handleAuthError(data);
      handler.reject(
        DioException(
          requestOptions: response.requestOptions
          ..extra['mapped_error'] = ErrorCodes.tokenInvalidMessage,
        response: response,
          type: DioExceptionType.badResponse,
          error: 'ERR_AUTH_TOKEN_INVALID',
          message: ErrorCodes.tokenInvalidMessage,
        ),
      );
      return;
    }
    handler.next(response);
  }

  @override
  Future<void> onError(DioException err, ErrorInterceptorHandler handler) async {
    final alreadyHandled = err.requestOptions.extra[_kAuthHandledKey] == true;
    final data = err.response?.data;
    final statusCode = err.response?.statusCode;
    
    if (alreadyHandled) return;
    
    if (_shouldSkipRefreshToken(err.requestOptions.path) &&
        (statusCode == 401 || statusCode == 403 || _isTokenInvalid(data))) {
      handler.next(err);
      return;
    }
    
    if (statusCode == 401 || _isTokenInvalid(data)) {
      await _handleAuthError(data, originalRequest: err.requestOptions, handler: handler, originalError: err);
      return;
    }
    handler.next(err);
  }

  bool _isTokenInvalid(dynamic data) {
    if (data is Map<String, dynamic>) {
      final code = data['error_code'] ?? data['errorCode'];
      return ErrorCodes.tokenInvalidCodes.contains(code);
    }
    return false;
  }

  /// Kiểm tra xem path này có cần skip refresh token không
  bool _shouldSkipRefreshToken(String path) {
    if (path.isEmpty) return false;
    for (String skipPath in _skipRefreshTokenPaths) {
      if (path.contains(skipPath)) {
        print('🔍 Path "$path" matches skip pattern "$skipPath", skipping refresh token.');
        return true;
      }
    }
    print('🔍 Path "$path" does not match any skip patterns, will attempt refresh token if needed.');
    return false;
  }

  Future<void> _handleAuthError(dynamic data, {RequestOptions? originalRequest, ErrorInterceptorHandler? handler, DioException? originalError}) async {
    if (_isHandlingAuth) return;
    _isHandlingAuth = true;
    try {
      // Thử refresh token trước khi logout
      final refreshService = TokenRefreshService();
      if (!refreshService.isRefreshing) {
        await refreshService.refreshToken((success) async {
          if (success && originalRequest != null && handler != null) {
            try {
              final RequestOptions retryOptions = originalRequest.copyWith();
              retryOptions.extra.remove(_kAuthHandledKey);
              final dio = DioHttpService().dio;
              final Response retried = await dio.fetch(retryOptions);
              handler.resolve(retried);
              return;
            } catch (e) {
              handler.reject(errFrom(e, originalRequest));
            }
          } else if (!success) {
            _performLogout(data);
            if (handler != null && originalError != null) handler.reject(originalError);
          }
        });
      } else {
        _performLogout(data);
        if (handler != null && originalError != null) handler.reject(originalError);
      }
    } finally {
      _isHandlingAuth = false;
    }
  }

  DioException errFrom(Object e, RequestOptions req) {
    if (e is DioException) return e;
    return DioException(requestOptions: req, error: e);
  }

  Future<void> _performLogout(dynamic data) async {
    LogoutService.logout();
    await DataPreference.instance.clearData();
    String? message;
    if (data is Map<String, dynamic>) {
      message = data['error_message']?.toString() ??
          data['errorMessage']?.toString() ??
          data['message']?.toString();
    }
    await AppNavigator.showAuthAlertAndGoLogin(message ?? ErrorCodes.tokenInvalidMessage);
  }
}
