import 'dart:async';

import '../../core.dart';

typedef RefreshTokenCallback = Future<String?> Function();
typedef SaveTokenCallback = Future<void> Function(String token);
typedef ClearTokenCallback = Future<void> Function();

class AppInterceptor extends Interceptor {
  final RefreshTokenCallback? refreshTokenCallback;
  final SaveTokenCallback saveTokenCallback;
  final ClearTokenCallback clearTokenCallback;
  late final Dio dio;
  static Completer<String?>? _refreshCompleter;
  static bool _isRefreshing = false;

  AppInterceptor({
    required this.saveTokenCallback,
    required this.clearTokenCallback,
    this.refreshTokenCallback,
  });

  @override
  Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    if (_isRefreshing && _refreshCompleter != null) {
      try {
        final newToken = await _refreshCompleter!.future;
        if (newToken != null && newToken.isNotEmpty) {
          options.headers['Authorization'] = 'Bearer $newToken';
        }
      } catch (_) {
        handler.reject(DioException(requestOptions: options, type: DioExceptionType.cancel));
        return;
      }
    }
    handler.next(options);
  }

  @override
  Future<void> onError(DioException err, ErrorInterceptorHandler handler) async {
    if (err.response?.statusCode == 401) {
      final retryResult = await _handleUnauthorizedError(err);
      if (retryResult != null) {
        handler.resolve(retryResult);
        return;
      }
    }
    handler.next(err);
  }

  Future<Response?> _handleUnauthorizedError(DioException err) async {
    if (_isRefreshing && _refreshCompleter != null) {
      try {
        final newToken = await _refreshCompleter!.future;
        return newToken != null ? await _retryRequest(err.requestOptions, newToken) : null;
      } catch (_) {
        return null;
      }
    }

    _isRefreshing = true;
    _refreshCompleter = Completer<String?>();

    try {
      final newToken = await refreshTokenCallback!();

      if (!_refreshCompleter!.isCompleted) _refreshCompleter!.complete(newToken);

      if (newToken != null) {
        await saveTokenCallback(newToken); // ✅ ذخیره توکن جدید
        return await _retryRequest(err.requestOptions, newToken);
      } else {
        await clearTokenCallback(); // ✅ پاک‌کردن توکن‌های قبلی
        return null;
      }
    } catch (e) {
      if (!_refreshCompleter!.isCompleted) _refreshCompleter!.completeError(e);
      await clearTokenCallback(); // ✅ پاک‌کردن توکن در صورت خطا
      _handleRefreshFailure();
      return null;
    } finally {
      _isRefreshing = false;
      _refreshCompleter = null;
    }
  }

  Future<Response> _retryRequest(RequestOptions options, String token) async {
    final newOptions = options.copyWith();
    newOptions.headers['Authorization'] = 'Bearer $token';
    return dio.fetch(newOptions);
  }

  void _handleRefreshFailure() {
    ApiHandler.cancelAllRequests("Token refresh failed");
    Future.delayed(const Duration(milliseconds: 100), () {
      if (Get.currentRoute != '/Auth') {
        Get.offAllNamed('/Auth');
      }
    });
  }
}