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

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/screens/crm/LeadDetailsByMode.dart';
import 'package:generp/screens/genTracker/GeneratorDetails.dart';
import 'package:generp/services/api_calling.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:geocoding/geocoding.dart' as geocoding;
import 'package:location/location.dart' as Location;
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';

import '../../Models/crmModels/NearbyOpenLeadsResponse.dart';
import '../../Utils/commonServices.dart';

class crmNearbyOpenLeadsProvider extends ChangeNotifier {


  List<LeadList> _leadslist = [];
  TextEditingController _locationController = TextEditingController();
  String _googleApikey = "AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs";
  GoogleMapController? _mapController;
  CameraPosition? _cameraPosition;
  LatLng _startLocation = const LatLng(17.439112226708446, 78.43292499146135);
  String _latlongs = "";
  List<Marker> _markers = [];
  List<String> _addresses = [];
  Location.LocationData? _currentLocation;
  bool _isLocationEnabled = false;
  bool _hasLocationPermission = false;
  Timer? _timer;
  File? _image;
  bool _isLoading = true;
  double _currentValue = 1.0;
  Timer? _debounceTimer;


  List<LeadList> get leadsList => _leadslist;
  TextEditingController get LocationController => _locationController;
  String get googleAPIKey => _googleApikey;
  GoogleMapController? get mapController => _mapController;
  CameraPosition? get cameraPosition => _cameraPosition;
  LatLng get startLocation => _startLocation;
  String get latlongs => _latlongs;
  List<Marker> get markers => _markers;
  List<String> get addresses => _addresses;
  Location.LocationData? get currentLocation => _currentLocation;
  bool get isLocationEnabled => _isLocationEnabled;
  bool get hasLocationPermission => _hasLocationPermission;
  bool get isLoading => _isLoading;
  Timer? get timer => _timer;
  File? get image => _image;
  double get currentValue => _currentValue;

  set currentValue(value){
    _currentValue = value;
    notifyListeners();
  }


  set markers(List<Marker> value){
    _markers = value;
    notifyListeners();
  }
  set mapController(value){
    _mapController = value;
    notifyListeners();
  }

  void resetAll(){
    _currentValue = 1.0;
    _markers= [];
    _addresses = [];
  }

  Future<void> getLocationPermission(context) async {
    // Check if location services are enabled
    _isLocationEnabled = await Geolocator.isLocationServiceEnabled();

    // Check if the app has been granted location permission
    LocationPermission permission = await Geolocator.checkPermission();
    _hasLocationPermission =
        permission == LocationPermission.always ||
            permission == LocationPermission.whileInUse;

    final Location.Location location = Location.Location();
    bool serviceEnabled;
    Location.PermissionStatus permissionGranted;
    serviceEnabled = await location.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await location.requestService();
      if (!serviceEnabled) {
        return;
      }
    }
    _isLoading = false;
    permissionGranted = (await location.hasPermission());
    if (permissionGranted == PermissionStatus) {
      permissionGranted = (await location.requestPermission());
      if (permissionGranted != PermissionStatus) {
        return;
      }
    }
    final Location.LocationData locData = await location.getLocation();

    _currentLocation = locData;

    if (_currentLocation != null) {
      _mapController?.animateCamera(
        CameraUpdate.newLatLng(
          LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!),
        ),
      );
      final lat = _currentLocation!.latitude;
      final lang = _currentLocation!.longitude!;
      _latlongs = '$lat,$lang';
      LoadNearbyOpenLeadsAPI(context,_currentValue);
    }
  }

  void onCameraMove(context, CameraPosition position) {
    _timer?.cancel(); // Cancel any previous timer
    _timer = Timer(Duration(seconds: 1), () {
      getLocationPermission(context);
    });
  }
  void debounce(VoidCallback callback, Duration duration) {
    _debounceTimer?.cancel();
    _debounceTimer = Timer(duration, callback);
  }


  Future<void> LoadNearbyOpenLeadsAPI(BuildContext context,radius) async {
    if (_latlongs.isEmpty || _currentValue <= 0) {
      print("Invalid parameters: latlongs=$_latlongs, currentValue=$_currentValue");
      return;
    }
    try {
      var provider = Provider.of<HomescreenNotifier>(context, listen: false);
      final data = await ApiCalling.loadNearbyOpenLeadsAPI(
        provider.empId,
        provider.session,
        _latlongs,
          radius
      );

      if (data != null) {
          if (data.error == 0) {
            _leadslist = data.leadList!;

            await updateMarkersFromApiResponse(context, data.leadList!);
            _isLoading = false;
            notifyListeners();
          } else if(data.error==1){
            toast(context, data.message);
          }

      } else {
        toast(context, "Something went wrong, Please try again.");
      }
    } on Exception catch (e) {
      print("$e");
    }
  }

  Future<void> updateMarkersFromApiResponse(
      BuildContext context,
      List<LeadList> leadsList,
      ) async {
    _markers = await createMarkersFromApiResponse(context, leadsList);
    _addresses.clear();
    await Future.forEach(leadsList, (store) async {
      String address = await _getAddressFromLatLng(store.loc);
      _addresses.add(address);

    });
    notifyListeners();
    // for (int i = 0; i < _addresses.length; i++) {
    //   //print('List of Addresses:' "${addresses[i]}");
    //   // print('List of Addresses:' "${addresses[1]}" );
    // }
  }

  Future<List<Marker>> createMarkersFromApiResponse(
      BuildContext context,
      List<LeadList> leadsList,
      ) async {
    List<Marker> markers = [];

    // print("Hello Nutsby!");
    ByteData data = await rootBundle.load("assets/images/leads_ic.png");
    Uint8List bytes = data.buffer.asUint8List();

    await Future.forEach(leadsList, (leads) async {
      ui.Codec codec = await ui.instantiateImageCodec(
        bytes,
      );
      ui.FrameInfo fi = await codec.getNextFrame();
      Uint8List resizedBytes =
      (await fi.image.toByteData(
        format: ui.ImageByteFormat.png,
      ))!.buffer.asUint8List();

      markers.add(
        Marker(
          markerId: MarkerId(leads.id.toString()),

          position: _parseLatLng(leads.loc),
          icon: BitmapDescriptor.fromBytes(resizedBytes),
          infoWindow: InfoWindow(

            onTap:() {
              // onMarkerTap(context, leads.id);
              Navigator.push(
                context, // Use the widget's BuildContext, which is valid here
                MaterialPageRoute(
                  builder: (context) => LeadDetailsByMode(
                    mode: "",
                    pageTitleName: "Lead Details",
                    leadId:leads.id ,

                  ),
                ),
              );
            },
            anchor: Offset(0, 0),
            title: "Name: ${leads.name}",
            snippet: "Address: ${leads.address}",

          ),
          zIndex: 100,

          onTap: () {
            int index = leadsList.indexWhere(
                  (techResponse) =>
              techResponse.id == leads.id,
            );
            // onMarkerTap(
            //   context,
            //   leads.id,
            // );
            // print("index:${index}");
            //   Navigator.push(
            //     context,
            //     MaterialPageRoute(
            //       builder:
            //           (context) => Generatordetails(
            //             activityName: "NearByGenerators",
            //             genLocation: generator.loc,
            //             generatorId: generator.generatorId,
            //           ),
            //     ),
            //   );

          },
        ),
      );
    });
    return markers;
  }
  Future<void> onMarkerTap(context, leadID) async {
///uncomment with screen navigation
    Navigator.push(
      context, // Use the widget's BuildContext, which is valid here
      MaterialPageRoute(
        builder: (context) => LeadDetailsByMode(
          mode: "",
          pageTitleName: "Lead Details",
          leadId:leadID ,

        ),
      ),
    );

    _markers = markers;
    notifyListeners();

  }

  LatLng _parseLatLng(String? location) {
    if (location != null) {
      List<String> parts = location.split(',');
      if (parts.length == 2) {
        double lat = double.tryParse(parts[0]) ?? 0.0;
        double lng = double.tryParse(parts[1]) ?? 0.0;
        return LatLng(lat, lng);
      }
    }
    return const LatLng(0.0, 0.0);
  }

  Future<String> _getAddressFromLatLng(String? location) async {
    if (location != null) {
      List<String> parts = location.split(',');
      if (parts.length == 2) {
        double lat = double.tryParse(parts[0]) ?? 0.0;
        double lng = double.tryParse(parts[1]) ?? 0.0;

        List<geocoding.Placemark> placemarks = await geocoding
            .placemarkFromCoordinates(lat, lng);

        if (placemarks.isNotEmpty) {
          final placemark = placemarks.first;
          String address =
              '${placemark.street ?? ''}, '
              '${placemark.thoroughfare ?? ''} '
          // '${placemark.subThoroughfare ?? ''}, '
          // '${placemark.name ?? ''}, '
              '${placemark.subLocality ?? ''}, '
              '${placemark.locality ?? ''}, '
              '${placemark.administrativeArea ?? ''}, '
              '${placemark.subAdministrativeArea ?? ''} '
              '${placemark.postalCode ?? ''}, '
              '${placemark.country ?? ''}';
          return address.trim();
        }
      }
    }
    return "Address not found";
  }

}
