import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

/// Sentry service for error tracking and performance monitoring.
///
/// This service handles:
/// - Initializing Sentry SDK
/// - Capturing exceptions and errors
/// - Capturing custom messages
/// - Setting user context after login
/// - Performance monitoring
///
/// Usage:
/// ```dart
/// // Initialize in main.dart
/// await SentryService.init(
///   dsn: 'your-sentry-dsn',
///   appRunner: () => runApp(MyApp()),
/// );
///
/// // Capture exception
/// SentryService.captureException(error, stackTrace: stackTrace);
///
/// // Capture message
/// SentryService.captureMessage('User performed action X');
///
/// // Set user context after login
/// SentryService.setUser(userId: '123', email: 'user@example.com');
/// ```
class SentryService {
  SentryService._();

  /// Sentry DSN - Replace with your actual DSN from Sentry dashboard
  static const String _dsn = 'https://2c5893508a29e5ea750b64d5ee31aeef@o4509632266436608.ingest.us.sentry.io/4510464530972672';

  /// Initialize Sentry SDK
  ///
  /// Must be called before runApp() in main.dart.
  /// Wraps the app with Sentry error boundary.
  ///
  /// [dsn] - Optional DSN override (uses default if not provided)
  /// [appRunner] - The function that runs the app (typically runApp(MyApp()))
  /// [environment] - Environment name (e.g., 'development', 'production')
  static Future<void> init({
    String? dsn,
    required Future<void> Function() appRunner,
    String? environment,
  }) async {
    // Get package info for release version
    final packageInfo = await PackageInfo.fromPlatform();
    final release = 'partner@${packageInfo.version}+${packageInfo.buildNumber}';

    await SentryFlutter.init(
      (options) {
        options
          ..dsn = dsn ?? _dsn

          // Release version: worker@1.0.1+29
          ..release = release

          // Environment configuration
          ..environment = environment ?? (kReleaseMode ? 'production' : 'development')

          // Performance monitoring
          ..tracesSampleRate = kReleaseMode ? 0.2 : 1.0 // 20% in prod, 100% in dev
          ..profilesSampleRate = kReleaseMode ? 0.2 : 1.0

          // Enable automatic instrumentation
          ..enableAutoPerformanceTracing = true

          // Capture failed requests
          ..captureFailedRequests = true

          // Debug mode settings
          ..debug = kDebugMode

          // Add app-specific tags
          ..beforeSend = (event, hint) {
            // Filter out certain errors if needed
            // Return null to drop the event
            return event;
          };
      },
      appRunner: appRunner,
    );

    debugPrint('🔴 Sentry initialized (release: $release, enabled: ${!kDebugMode})');
  }

  /// Capture an exception with optional stack trace
  ///
  /// [exception] - The exception to capture
  /// [stackTrace] - Optional stack trace
  /// [hint] - Optional hint with additional context
  static Future<void> captureException(
    dynamic exception, {
    StackTrace? stackTrace,
    Hint? hint,
  }) async {
    try {
      await Sentry.captureException(
        exception,
        stackTrace: stackTrace,
        hint: hint,
      );
      debugPrint('🔴 Sentry: Exception captured - ${exception.runtimeType}');
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to capture exception - $e');
    }
  }

  /// Capture a custom message
  ///
  /// [message] - The message to capture
  /// [level] - Severity level (default: info)
  /// [params] - Optional parameters to include
  static Future<void> captureMessage(
    String message, {
    SentryLevel level = SentryLevel.info,
    Map<String, dynamic>? params,
  }) async {
    try {
      await Sentry.captureMessage(
        message,
        level: level,
        withScope: params != null
            ? (scope) {
                params.forEach((key, value) {
                  scope.setExtra(key, value);
                });
              }
            : null,
      );
      debugPrint('🔴 Sentry: Message captured - $message');
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to capture message - $e');
    }
  }

  /// Set user context for error tracking
  ///
  /// Call this after successful login to associate errors with users.
  ///
  /// [userId] - User's unique identifier
  /// [email] - User's email (optional)
  /// [username] - User's display name (optional)
  /// [extras] - Additional user data (optional)
  static Future<void> setUser({
    required String userId,
    String? email,
    String? username,
    Map<String, dynamic>? extras,
  }) async {
    try {
      await Sentry.configureScope((scope) {
        scope.setUser(SentryUser(
          id: userId,
          email: email,
          username: username,
          data: extras,
        ));
      });
      debugPrint('🔴 Sentry: User set - $userId');
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to set user - $e');
    }
  }

  /// Clear user context on logout
  static Future<void> clearUser() async {
    try {
      await Sentry.configureScope((scope) {
        scope.setUser(null);
      });
      debugPrint('🔴 Sentry: User cleared');
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to clear user - $e');
    }
  }

  /// Add a breadcrumb for tracking user actions
  ///
  /// Breadcrumbs are used to track the sequence of events leading to an error.
  ///
  /// [message] - Description of the action
  /// [category] - Category of the breadcrumb (e.g., 'navigation', 'ui.click')
  /// [data] - Additional data (optional)
  static Future<void> addBreadcrumb({
    required String message,
    String? category,
    Map<String, dynamic>? data,
    SentryLevel level = SentryLevel.info,
  }) async {
    try {
      await Sentry.addBreadcrumb(Breadcrumb(
        message: message,
        category: category,
        data: data,
        level: level,
        timestamp: DateTime.now(),
      ));
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to add breadcrumb - $e');
    }
  }

  /// Set a tag for filtering in Sentry dashboard
  ///
  /// [key] - Tag name
  /// [value] - Tag value
  static Future<void> setTag(String key, String value) async {
    try {
      await Sentry.configureScope((scope) {
        scope.setTag(key, value);
      });
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to set tag - $e');
    }
  }

  /// Set extra context data
  ///
  /// [key] - Context key
  /// [value] - Context value (will be serialized)
  static Future<void> setExtra(String key, dynamic value) async {
    try {
      await Sentry.configureScope((scope) {
        scope.setExtra(key, value);
      });
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to set extra - $e');
    }
  }

  /// Start a performance transaction
  ///
  /// [name] - Transaction name
  /// [operation] - Operation type (e.g., 'http.client', 'ui.load')
  ///
  /// Returns the transaction to be finished later.
  static ISentrySpan? startTransaction(String name, String operation) {
    try {
      return Sentry.startTransaction(name, operation);
    } catch (e) {
      debugPrint('🔴 Sentry error: Failed to start transaction - $e');
      return null;
    }
  }
}
