import 'dart:async';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:location/location.dart' as LocationPlugin;
import 'package:flutter_polyline_points/flutter_polyline_points.dart';

class Techniciantrackingprovider extends ChangeNotifier {
  final String _googleApikey = "AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs";

  GoogleMapController? _mapController;
  LocationPlugin.LocationData? _currentLocation;
  bool _isLoading = true;
  bool _hasPermission = false;

  final Set<Marker> _markers = {};
  final Set<Polyline> _polylines = {};
  final List<LatLng> _polylineCoordinates = [];
  late PolylinePoints polylinePoints;
  BitmapDescriptor? customerIcon;
  BitmapDescriptor? technicianIcon;

  LatLng get startLocation => const LatLng(17.439112226708446, 78.43292499146135);
  GoogleMapController? get mapController => _mapController;
  Set<Marker> get markers => _markers;
  Set<Polyline> get polylines => _polylines;
  LocationPlugin.LocationData? get currentLocation => _currentLocation;
  bool get isLoading => _isLoading;

  set mapController(GoogleMapController? controller) {
    _mapController = controller;
    notifyListeners();
  }

  Future<void> loadCustomIcons() async {
    customerIcon ??= await BitmapDescriptor.fromAssetImage(
      const ImageConfiguration(size: Size(80, 80)),
      'assets/images/maps_ic.png',
    );

    technicianIcon ??= await BitmapDescriptor.fromAssetImage(
      const ImageConfiguration(size: Size(80, 80)),
      'assets/images/technician_marker.png',
    );
    notifyListeners();
  }

  Future<void> getLocationPermission(BuildContext context) async {
    _isLoading = true;
    notifyListeners();

    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _isLoading = false;
      notifyListeners();
      return;
    }

    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _isLoading = false;
        notifyListeners();
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      _isLoading = false;
      notifyListeners();
      return;
    }

    _hasPermission = true;
    await loadCustomIcons();

    final LocationPlugin.Location location = LocationPlugin.Location();
    _currentLocation = await location.getLocation();

    // Add customer marker
    if (_currentLocation != null) {
      _markers.add(Marker(
        markerId: const MarkerId('customer'),
        position: LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!),
        infoWindow: const InfoWindow(title: "You are here"),
        icon: customerIcon ?? BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen),
      ));
    }

    _isLoading = false;
    notifyListeners();
  }

  void updateTechnicianLocation(double? lat, double? lng) {
    if (lat == null || lng == null || lat == 0 || lng == 0) return;

    final technicianLatLng = LatLng(lat, lng);

    // Remove old technician marker
    _markers.removeWhere((m) => m.markerId.value == 'technician');
    _polylines.clear();
    _polylineCoordinates.clear();

    // Add new technician marker
    _markers.add(Marker(
      markerId: const MarkerId('technician'),
      position: technicianLatLng,
      infoWindow: const InfoWindow(title: "Technician"),
      icon: technicianIcon ?? BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
    ));

    // Draw route if customer location exists
    if (_currentLocation != null) {
      _drawRoute(
        LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!),
        technicianLatLng,
      );
    }

    // Adjust camera
    _fitBothMarkers();
    setPolylines(lat,lng);
    notifyListeners();
  }

  void setPolylines(double? lat, double? lng) async {
    _polylineCoordinates.clear();
    _polylines.clear();
    PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
      // googleApiKey: "AIzaSyAA2ukvrb1kWQZ2dttsNIMynLJqVCYYrhw",
      request: PolylineRequest(
          origin: await PointLatLng(
              lat!,
              lng!),
          destination: await PointLatLng(
              _currentLocation!.latitude!,
              _currentLocation!.longitude!),
          mode: TravelMode.driving),
      // Example LatLng// Example LatLng
      // Example LatLng
    );

    if (result.points.isNotEmpty) {
      result.points.forEach((PointLatLng point) {
        _polylineCoordinates.add(LatLng(point.latitude, point.longitude));
      });


      _polylines.add(Polyline(
        width: 1,
        polylineId: PolylineId("poly"),
        color: Color(0xFF008CDE),
        points: _polylineCoordinates,
      ));
      notifyListeners();
    }
  }

  Future<void> _drawRoute(LatLng origin, LatLng destination) async {
    final polylinePoints = PolylinePoints(apiKey: _googleApikey);
    try {
      final result = await polylinePoints.getRouteBetweenCoordinates(

        request: PolylineRequest(
          origin: PointLatLng(origin.latitude, origin.longitude),
          destination: PointLatLng(destination.latitude, destination.longitude),
          mode: TravelMode.driving,
        ),
      );

      if (result.points.isNotEmpty) {
        _polylineCoordinates.clear();
        for (var point in result.points) {
          _polylineCoordinates.add(LatLng(point.latitude, point.longitude));
        }

        _polylines.add(Polyline(
          polylineId: const PolylineId('route'),
          color: Colors.blue,
          width: 5,
          points: _polylineCoordinates,
          patterns: [PatternItem.dash(20), PatternItem.gap(10)],
        ));
      }
    } catch (e) {
      debugPrint("Polyline Error: $e");
    }
    notifyListeners();
  }

  void _fitBothMarkers() {
    if (_markers.length < 2 || _mapController == null) return;

    final positions = _markers.map((m) => m.position).toList();
    double minLat = positions[0].latitude;
    double maxLat = positions[0].latitude;
    double minLng = positions[0].longitude;
    double maxLng = positions[0].longitude;

    for (var pos in positions) {
      if (pos.latitude < minLat) minLat = pos.latitude;
      if (pos.latitude > maxLat) maxLat = pos.latitude;
      if (pos.longitude < minLng) minLng = pos.longitude;
      if (pos.longitude > maxLng) maxLng = pos.longitude;
    }

    _mapController!.animateCamera(
      CameraUpdate.newLatLngBounds(
        LatLngBounds(
          southwest: LatLng(minLat, minLng),
          northeast: LatLng(maxLat, maxLng),
        ),
        100,
      ),
    );
  }

  Future<void> setMapStyle(GoogleMapController controller) async {
    String mapStyle = '''
    [
      {
        "featureType": "road",
        "elementType": "geometry",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "road.arterial",
        "elementType": "geometry",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "road.highway",
        "elementType": "geometry",
        "stylers": [
          {
            "visibility": "off"
          }
        ]
      },
      {
        "featureType": "road.local",
        "elementType": "geometry",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "poi",
        "elementType": "labels",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "poi.business",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "transit",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      },
      {
        "featureType": "road.local",
        "elementType": "labels",
        "stylers": [
          {
            "visibility": "on"
          }
        ]
      }
    ]
    ''';
    await controller.setMapStyle(mapStyle);
  }
  void clearMap() {
    _markers.clear();
    _polylines.clear();
    _polylineCoordinates.clear();
    notifyListeners();
  }
}