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 Dio dio;
  dynamic authArguments;
  static Completer<String?>? _refreshCompleter;
  static bool _isRefreshing = false;

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

  @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';
        } else {
          // اگر توکن جدید وجود نداشت، درخواست را رد کن
          handler.reject(DioException(requestOptions: options, type: DioExceptionType.cancel));
          return;
        }
      } 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 && err.response?.data['detail'] != "No active account found with the given credentials") {
      final retryResult = await _handleUnauthorizedError(err);
      if (retryResult != null) {
        handler.resolve(retryResult);
        return;
      }
      // اگر رفرش توکن ناموفق بود، درخواست را رد کن
      handler.reject(err);
      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?.call();

      if (newToken != null && newToken.isNotEmpty) {
        await saveTokenCallback(newToken); // ذخیره توکن جدید
        _refreshCompleter!.complete(newToken);
        return await _retryRequest(err.requestOptions, newToken);
      } else {
        await clearTokenCallback(); // پاک کردن توکن‌های قبلی
        _refreshCompleter!.complete(null);
        _handleRefreshFailure();
        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);
  }

  //TODO
  void _handleRefreshFailure() {
    ApiHandler.cancelAllRequests("Token refresh failed");
  }
}
