import 'package:dio/dio.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'sentry_service.dart';

/// Sentry Dio 拦截器
/// 自动追踪 HTTP 请求，记录面包屑和性能指标
class SentryDioInterceptor extends Interceptor {
  /// 是否启用性能追踪
  final bool enablePerformanceTracing;

  /// 是否记录请求体 (注意隐私)
  final bool captureRequestBody;

  /// 是否记录响应体 (注意大小和隐私)
  final bool captureResponseBody;

  /// 敏感路径列表 (不记录详情)
  final List<String> sensitiveEndpoints;

  /// 请求开始时间缓存
  final Map<RequestOptions, DateTime> _requestStartTimes = {};

  /// 事务缓存
  final Map<RequestOptions, ISentrySpan> _transactions = {};

  SentryDioInterceptor({
    this.enablePerformanceTracing = true,
    this.captureRequestBody = false,
    this.captureResponseBody = false,
    this.sensitiveEndpoints = const [
      '/auth',
      '/login',
      '/token',
      '/password',
      '/mnemonic',
    ],
  });

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    _requestStartTimes[options] = DateTime.now();

    // 启动性能追踪事务
    if (enablePerformanceTracing && SentryService().isInitialized) {
      final transaction = SentryService().startTransaction(
        name: '${options.method} ${_sanitizePath(options.path)}',
        operation: 'http.client',
        description: options.uri.toString(),
      );
      if (transaction != null) {
        _transactions[options] = transaction;
      }
    }

    // 添加 Sentry trace header (用于分布式追踪)
    final span = Sentry.getSpan();
    if (span != null) {
      final traceHeader = span.toSentryTrace();
      options.headers['sentry-trace'] = traceHeader.value;

      final baggageHeader = span.toBaggageHeader();
      if (baggageHeader != null) {
        options.headers['baggage'] = baggageHeader.value;
      }
    }

    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    _recordHttpBreadcrumb(
      options: response.requestOptions,
      statusCode: response.statusCode,
    );
    _finishTransaction(response.requestOptions, response.statusCode);
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    final statusCode = err.response?.statusCode;

    _recordHttpBreadcrumb(
      options: err.requestOptions,
      statusCode: statusCode,
      error: err,
    );

    _finishTransaction(
      err.requestOptions,
      statusCode,
      error: err,
    );

    // 对于特定错误类型，上报到 Sentry
    if (_shouldReportError(err)) {
      SentryService().captureException(
        err,
        message: 'HTTP Error: ${err.message}',
        extras: {
          'url': _sanitizeUrl(err.requestOptions.uri.toString()),
          'method': err.requestOptions.method,
          'status_code': statusCode,
          'error_type': err.type.name,
        },
      );
    }

    handler.next(err);
  }

  void _recordHttpBreadcrumb({
    required RequestOptions options,
    int? statusCode,
    DioException? error,
  }) {
    final startTime = _requestStartTimes.remove(options);
    final duration = startTime != null
        ? DateTime.now().difference(startTime).inMilliseconds
        : null;

    SentryService().addHttpBreadcrumb(
      url: options.uri.toString(),
      method: options.method,
      statusCode: statusCode,
      reason: error?.message,
    );

    // 添加详细的请求上下文
    if (!_isSensitiveEndpoint(options.path)) {
      SentryService().addBreadcrumb(
        message: 'HTTP ${options.method} completed',
        category: 'http.detail',
        data: {
          'url': _sanitizeUrl(options.uri.toString()),
          'method': options.method,
          'status_code': statusCode,
          if (duration != null) 'duration_ms': duration,
          if (error != null) 'error_type': error.type.name,
        },
        level: (statusCode != null && statusCode >= 400)
            ? SentryLevel.error
            : SentryLevel.info,
      );
    }
  }

  void _finishTransaction(
    RequestOptions options,
    int? statusCode, {
    DioException? error,
  }) {
    final transaction = _transactions.remove(options);
    if (transaction == null) return;

    // 设置状态
    if (error != null) {
      transaction.status = _mapErrorToSpanStatus(error);
      transaction.throwable = error;
    } else if (statusCode != null) {
      transaction.status = _mapStatusCodeToSpanStatus(statusCode);
    }

    // 添加标签
    transaction.setTag('http.method', options.method);
    transaction.setTag('http.url', _sanitizePath(options.path));
    if (statusCode != null) {
      transaction.setTag('http.status_code', statusCode.toString());
    }

    transaction.finish();
  }

  SpanStatus _mapStatusCodeToSpanStatus(int statusCode) {
    if (statusCode >= 200 && statusCode < 300) {
      return const SpanStatus.ok();
    } else if (statusCode == 400) {
      return const SpanStatus.invalidArgument();
    } else if (statusCode == 401) {
      return const SpanStatus.unauthenticated();
    } else if (statusCode == 403) {
      return const SpanStatus.permissionDenied();
    } else if (statusCode == 404) {
      return const SpanStatus.notFound();
    } else if (statusCode == 429) {
      return const SpanStatus.resourceExhausted();
    } else if (statusCode >= 500) {
      return const SpanStatus.internalError();
    }
    return const SpanStatus.unknownError();
  }

  SpanStatus _mapErrorToSpanStatus(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return const SpanStatus.deadlineExceeded();
      case DioExceptionType.cancel:
        return const SpanStatus.cancelled();
      case DioExceptionType.connectionError:
        return const SpanStatus.unavailable();
      default:
        return const SpanStatus.unknownError();
    }
  }

  bool _shouldReportError(DioException error) {
    // 不上报取消的请求
    if (error.type == DioExceptionType.cancel) return false;

    // 不上报超时 (太常见)
    if (error.type == DioExceptionType.connectionTimeout ||
        error.type == DioExceptionType.sendTimeout ||
        error.type == DioExceptionType.receiveTimeout) {
      return false;
    }

    // 服务端错误 (5xx) 上报
    final statusCode = error.response?.statusCode;
    if (statusCode != null && statusCode >= 500) return true;

    // 连接错误上报
    if (error.type == DioExceptionType.connectionError) return true;

    return false;
  }

  bool _isSensitiveEndpoint(String path) {
    return sensitiveEndpoints.any((endpoint) =>
        path.toLowerCase().contains(endpoint.toLowerCase()));
  }

  String _sanitizePath(String path) {
    // 移除查询参数
    final uri = Uri.tryParse(path);
    if (uri != null) {
      return uri.path;
    }
    return path.split('?').first;
  }

  String _sanitizeUrl(String url) {
    try {
      final uri = Uri.parse(url);
      // 保留 scheme, host, path，移除敏感查询参数
      final sanitizedParams = <String, String>{};
      uri.queryParameters.forEach((key, value) {
        if (_isSensitiveParam(key)) {
          sanitizedParams[key] = '[REDACTED]';
        } else {
          sanitizedParams[key] = value;
        }
      });

      if (sanitizedParams.isEmpty) {
        return '${uri.scheme}://${uri.host}${uri.path}';
      }
      return uri.replace(queryParameters: sanitizedParams).toString();
    } catch (_) {
      return url;
    }
  }

  bool _isSensitiveParam(String key) {
    final sensitiveKeys = [
      'token',
      'password',
      'secret',
      'key',
      'auth',
      'bearer',
      'credential',
    ];
    return sensitiveKeys.any((k) => key.toLowerCase().contains(k));
  }
}
