import 'dart:async';
import 'dart:math';
import 'package:dio/dio.dart';
import '../network_config.dart';
import '../../utils/app_logger.dart';
import '../../errors/network_exceptions.dart';

/// 재시도 인터셉터
///
/// 네트워크 오류 발생 시 자동으로 재시도합니다.
/// 지수 백오프(exponential backoff) 알고리즘을 사용합니다.
class RetryInterceptor extends Interceptor {
  final Dio dio;

  RetryInterceptor({required this.dio});

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    // 재시도 카운트 확인
    final retryCount = err.requestOptions.extra['retryCount'] ?? 0;

    // 재시도 가능한 오류인지 확인
    if (_shouldRetry(err) && retryCount < NetworkConfig.maxRetries) {
      try {
        // 지수 백오프 계산
        final delay = _calculateBackoffDelay(retryCount);

        AppLogger.debug(
          'RetryInterceptor: 재시도 ${retryCount + 1}/${NetworkConfig.maxRetries} - ${delay}ms 대기',
        );

        // 대기
        await Future.delayed(Duration(milliseconds: delay));

        // 재시도 카운트 증가
        err.requestOptions.extra['retryCount'] = retryCount + 1;

        // 재시도 실행
        final response = await dio.fetch(err.requestOptions);

        return handler.resolve(response);
      } catch (e) {
        // 재시도도 실패한 경우
        if (retryCount + 1 >= NetworkConfig.maxRetries) {
          return handler.reject(
            DioException(
              requestOptions: err.requestOptions,
              error: MaxRetriesExceededException(originalError: e),
            ),
          );
        }
      }
    }

    return handler.next(err);
  }

  /// 재시도 가능한 오류인지 판단
  bool _shouldRetry(DioException err) {
    // 네이버 관련 요청은 재시도하지 않음
    final url = err.requestOptions.uri.toString();
    if (url.contains('naver.com') || url.contains('naver.me')) {
      AppLogger.debug('RetryInterceptor: 네이버 API 요청은 재시도하지 않음 - $url');
      return false;
    }

    // 네트워크 연결 오류
    if (err.type == DioExceptionType.connectionTimeout ||
        err.type == DioExceptionType.sendTimeout ||
        err.type == DioExceptionType.receiveTimeout ||
        err.type == DioExceptionType.connectionError) {
      return true;
    }

    // 서버 오류 (5xx)
    final statusCode = err.response?.statusCode;
    if (statusCode != null && statusCode >= 500 && statusCode < 600) {
      return true;
    }

    // 429 Too Many Requests는 재시도하지 않음
    // 재시도하면 더 많은 요청이 발생하여 문제가 악화됨

    return false;
  }

  /// 지수 백오프 지연 시간 계산
  int _calculateBackoffDelay(int retryCount) {
    final baseDelay = NetworkConfig.retryDelayMillis;
    final multiplier = NetworkConfig.retryDelayMultiplier;

    // 지수 백오프: delay = baseDelay * (multiplier ^ retryCount)
    final exponentialDelay = baseDelay * pow(multiplier, retryCount);

    // 지터(jitter) 추가로 동시 재시도 방지
    final jitter = Random().nextInt(1000);

    return exponentialDelay.toInt() + jitter;
  }
}
