import 'package:dio/dio.dart';
import 'package:uuid/uuid.dart';

/// Interceptor yang secara otomatis menambahkan header X-Idempotency-Key
/// untuk endpoint-endpoint kritis yang memerlukan idempotency.
///
/// Key sebaiknya di-generate di level BLoC/Cubit saat user trigger action,
/// lalu dikirim via headers. Interceptor ini hanya berfungsi sebagai fallback
/// jika key belum di-set.
///
/// Jika response 409 dengan error code `request_in_progress`, interceptor
/// akan retry setelah delay 1-2 detik.
class IdempotencyInterceptor extends Interceptor {
  static const _headerKey = 'X-Idempotency-Key';
  static const _replayHeader = 'X-Idempotent-Replay';

  // Endpoints that require idempotency keys (exact match)
  static const _idempotentPaths = [
    '/api/v1/payments',
    '/api/v1/orders/void',
  ];

  // Endpoints that require idempotency keys (pattern match)
  static final _idempotentPathPatterns = [
    RegExp(r'/api/v1/orders/.+/add-items$'),
    RegExp(r'/api/v1/orders/.+/refund$'),
    RegExp(r'/api/v1/payments/.+/refund$'),
  ];

  static const _maxRetries = 3;
  static const _retryDelay = Duration(seconds: 2);

  final Dio _dio;

  IdempotencyInterceptor(this._dio);

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    if (options.method == 'POST' && _requiresIdempotencyKey(options.path)) {
      // Gunakan key yang sudah di-set dari BLoC, atau generate baru sebagai fallback
      options.headers[_headerKey] ??= const Uuid().v4();
    }
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // Log jika response adalah replay dari request sebelumnya
    final isReplay = response.headers.value(_replayHeader);
    if (isReplay == 'true') {
      // Response ini adalah hasil dari request pertama yang sudah diproses.
      // Treat as success — tidak perlu perlakuan khusus.
    }
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    final response = err.response;
    final options = err.requestOptions;

    if (response == null) {
      handler.next(err);
      return;
    }

    // Handle 409 Conflict with request_in_progress
    if (response.statusCode == 409 &&
        _isRequestInProgress(response.data) &&
        _requiresIdempotencyKey(options.path)) {
      final retryCount = options.extra['_idempotency_retry_count'] ?? 0;

      if (retryCount < _maxRetries) {
        await Future.delayed(_retryDelay);

        options.extra['_idempotency_retry_count'] = retryCount + 1;

        try {
          final retryResponse = await _dio.fetch(options);
          handler.resolve(retryResponse);
        } on DioException catch (e) {
          handler.next(e);
        }
        return;
      }
    }

    handler.next(err);
  }

  bool _requiresIdempotencyKey(String path) {
    if (_idempotentPaths.any((p) => path.endsWith(p))) return true;
    if (_idempotentPathPatterns.any((r) => r.hasMatch(path))) return true;
    return false;
  }

  bool _isRequestInProgress(dynamic data) {
    if (data is Map<String, dynamic>) {
      final errorCode = data['error_code'] ?? data['code'] ?? '';
      return errorCode == 'request_in_progress';
    }
    return false;
  }
}
