import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';

/// Model for trip data passed to the overlay
class TripData {
  final String tripId;
  final String passengerName;
  final String pickupAddress;
  final String dropoffAddress;
  final double distanceKm;
  final double estimatedFare;
  final int estimatedMinutes;
  final double pickupLat;
  final double pickupLng;
  final String? passengerAvatarUrl;

  TripData({
    required this.tripId,
    required this.passengerName,
    required this.pickupAddress,
    required this.dropoffAddress,
    required this.distanceKm,
    required this.estimatedFare,
    required this.estimatedMinutes,
    required this.pickupLat,
    required this.pickupLng,
    this.passengerAvatarUrl,
  });

  Map<String, dynamic> toMap() => {
    'tripId': tripId,
    'passengerName': passengerName,
    'pickupAddress': pickupAddress,
    'dropoffAddress': dropoffAddress,
    'distanceKm': distanceKm,
    'estimatedFare': estimatedFare,
    'estimatedMinutes': estimatedMinutes,
    'pickupLat': pickupLat,
    'pickupLng': pickupLng,
    'passengerAvatarUrl': passengerAvatarUrl ?? '',
  };

  factory TripData.fromMap(Map<String, dynamic> map) => TripData(
    tripId: map['tripId'] ?? '',
    passengerName: map['passengerName'] ?? '',
    pickupAddress: map['pickupAddress'] ?? '',
    dropoffAddress: map['dropoffAddress'] ?? '',
    distanceKm: (map['distanceKm'] ?? 0.0).toDouble(),
    estimatedFare: (map['estimatedFare'] ?? 0.0).toDouble(),
    estimatedMinutes: map['estimatedMinutes'] ?? 0,
    pickupLat: (map['pickupLat'] ?? 0.0).toDouble(),
    pickupLng: (map['pickupLng'] ?? 0.0).toDouble(),
    passengerAvatarUrl: map['passengerAvatarUrl'],
  );

  factory TripData.fromJson(String json) =>
      TripData.fromMap(jsonDecode(json) as Map<String, dynamic>);

  String toJson() => jsonEncode(toMap());
}

/// Result returned when the driver accepts a trip
class TripAcceptedResult {
  final String tripId;
  final DateTime acceptedAt;

  TripAcceptedResult({required this.tripId, required this.acceptedAt});
}

/// Main plugin class — single entry point for Flutter side
class TripOverlayPlugin {
  static const MethodChannel _channel = MethodChannel('trip_overlay_plugin');

  // Stream controller for trip accepted events coming FROM Android overlay
  static final StreamController<TripAcceptedResult> _tripAcceptedController =
      StreamController<TripAcceptedResult>.broadcast();

  // Stream controller for trip rejected/expired events
  static final StreamController<String> _tripRejectedController =
      StreamController<String>.broadcast();

  static bool _isInitialized = false;

  /// Stream that fires when the driver taps "Accept" in the overlay
  static Stream<TripAcceptedResult> get onTripAccepted =>
      _tripAcceptedController.stream;

  /// Stream that fires when the driver rejects or overlay times out
  static Stream<String> get onTripRejected => _tripRejectedController.stream;

  /// Initialize the plugin — call this once in main() or initState()
  static Future<void> initialize() async {
    if (_isInitialized) return;
    _channel.setMethodCallHandler(_handleMethodCall);
    _isInitialized = true;
  }

  /// Handle incoming calls FROM Android → Flutter
  static Future<dynamic> _handleMethodCall(MethodCall call) async {
    switch (call.method) {
      case 'onTripAccepted':
        final tripId = call.arguments['tripId'] as String;
        _tripAcceptedController.add(
          TripAcceptedResult(tripId: tripId, acceptedAt: DateTime.now()),
        );
        break;

      case 'onTripRejected':
        final tripId = call.arguments['tripId'] as String;
        _tripRejectedController.add(tripId);
        break;

      default:
        throw PlatformException(
          code: 'UNKNOWN_METHOD',
          message: 'Method ${call.method} not implemented',
        );
    }
  }

  /// Check if SYSTEM_ALERT_WINDOW permission is granted
  static Future<bool> isPermissionGranted() async {
    final result = await _channel.invokeMethod<bool>('isPermissionGranted');
    return result ?? false;
  }

  /// Open system settings to grant SYSTEM_ALERT_WINDOW permission
  static Future<void> requestPermission() async {
    await _channel.invokeMethod('requestPermission');
  }

  /// Show the trip overlay with the given [tripData]
  /// [autoCloseSeconds] — how long before auto-dismiss (default 30s)
  static Future<bool> showOverlay(
    TripData tripData, {
    int autoCloseSeconds = 30,
  }) async {
    final granted = await isPermissionGranted();
    if (!granted) {
      await requestPermission();
      return false;
    }

    final result = await _channel.invokeMethod<bool>('showOverlay', {
      'tripData': tripData.toJson(),
      'autoCloseSeconds': autoCloseSeconds,
    });
    return result ?? false;
  }

  /// Programmatically close the overlay (e.g. if trip was cancelled)
  static Future<void> hideOverlay() async {
    await _channel.invokeMethod('hideOverlay');
  }

  /// Check if the overlay is currently visible
  static Future<bool> isOverlayActive() async {
    final result = await _channel.invokeMethod<bool>('isOverlayActive');
    return result ?? false;
  }

  /// Dispose streams — call in app's dispose()
  static void dispose() {
    _tripAcceptedController.close();
    _tripRejectedController.close();
  }
}
