import 'package:google_navigation_flutter/google_navigation_flutter.dart';

class NavigationSessionService {
  static final NavigationSessionService _instance =
      NavigationSessionService._internal();

  factory NavigationSessionService() {
    return _instance;
  }

  NavigationSessionService._internal();

  bool _isSessionInitialized = false;
  GoogleNavigationViewController? _controller;

  bool get isSessionInitialized => _isSessionInitialized;

  Future<void> initializeSession() async {
    if (_isSessionInitialized) {
      return;
    }

    try {
      await GoogleMapsNavigator.initializeNavigationSession();
      _isSessionInitialized = true;
    } catch (e) {
      throw NavigationSessionException('Failed to initialize session: $e');
    }
  }

  Future<void> setController(
    GoogleNavigationViewController controller,
  ) async {
    _controller = controller;
  }

  Future<NavigationRoute> calculateRoute({
    required double startLatitude,
    required double startLongitude,
    required double destinationLatitude,
    required double destinationLongitude,
  }) async {
    if (!_isSessionInitialized) {
      throw NavigationSessionException('Session not initialized');
    }

    if (_controller == null) {
      throw NavigationSessionException('Controller not set');
    }

    try {
      final origin = LatLng(
        latitude: startLatitude,
        longitude: startLongitude,
      );

      final destination = LatLng(
        latitude: destinationLatitude,
        longitude: destinationLongitude,
      );

      final waypoint = NavigationWaypoint.withLatLngTarget(
        title: 'Destination',
        target: destination,
      );

      final destinations = Destinations(
        waypoints: [waypoint],
        displayOptions: NavigationDisplayOptions(showDestinationMarkers: true),
      );

      // Set destinations will trigger route calculation
      await GoogleMapsNavigator.setDestinations(destinations);

      return NavigationRoute(
        startLocation: origin,
        endLocation: destination,
        isCalculated: true,
      );
    } catch (e) {
      throw NavigationSessionException('Failed to calculate route: $e');
    }
  }

  Future<void> startNavigation() async {
    if (!_isSessionInitialized) {
      throw NavigationSessionException('Navigation not properly initialized');
    }

    try {
      await GoogleMapsNavigator.startGuidance();
    } catch (e) {
      throw NavigationSessionException('Failed to start navigation: $e');
    }
  }

  Future<void> stopNavigation() async {
    if (!_isSessionInitialized) {
      return;
    }

    try {
      await GoogleMapsNavigator.stopGuidance();
    } catch (e) {
      throw NavigationSessionException('Failed to stop navigation: $e');
    }
  }

  void addLocationListener(
    Function(RoadSnappedLocationUpdatedEvent event) onLocationUpdate,
  ) {
    if (!_isSessionInitialized) {
      throw NavigationSessionException('Navigation not initialized');
    }

    GoogleMapsNavigator.setRoadSnappedLocationUpdatedListener((event) {
      onLocationUpdate(event);
    });
  }

  void addArrivalListener(Function(OnArrivalEvent event) onArrival) {
    if (!_isSessionInitialized) {
      throw NavigationSessionException('Navigation not initialized');
    }

    GoogleMapsNavigator.setOnArrivalListener((event) {
      onArrival(event);
    });
  }

  // Note: Remaining distance listener API may vary by version
  // This is a placeholder for future implementation
  void addRemainingDistanceListener(
    Function(dynamic event) onDistanceChange,
  ) {
    if (!_isSessionInitialized) {
      throw NavigationSessionException('Navigation not initialized');
    }
    // TODO: Implement when correct API is available
    // GoogleMapsNavigator does not expose a public remaining distance listener
  }

  void clearAllListeners() {
    if (!_isSessionInitialized) {
      return;
    }

    // Clear listeners by setting them to empty callbacks
    // Note: The API doesn't support null, so we use no-op callbacks
    GoogleMapsNavigator.setRoadSnappedLocationUpdatedListener((_) {});
    GoogleMapsNavigator.setOnArrivalListener((_) {});
  }

  Future<void> cleanup() async {
    try {
      if (_isSessionInitialized) {
        await stopNavigation();
        clearAllListeners();
        await GoogleMapsNavigator.cleanup();
      }
      _isSessionInitialized = false;
      _controller = null;
    } catch (e) {
      throw NavigationSessionException('Failed to cleanup: $e');
    }
  }
}

class NavigationRoute {
  final LatLng startLocation;
  final LatLng endLocation;
  final bool isCalculated;
  final int? distanceMeters;
  final Duration? estimatedTime;

  NavigationRoute({
    required this.startLocation,
    required this.endLocation,
    required this.isCalculated,
    this.distanceMeters,
    this.estimatedTime,
  });
}

class NavigationSessionException implements Exception {
  final String message;

  NavigationSessionException(this.message);

  @override
  String toString() => 'NavigationSessionException: $message';
}
