import 'dart:io';

import 'package:hmg_patient_app/config/shared_pref_kay.dart';
import 'package:hmg_patient_app/core/viewModels/project_view_model.dart';
import 'package:hmg_patient_app/uitl/app_shared_preferences.dart';
import 'package:hmg_patient_app/uitl/translations_delegate_base.dart';
import 'package:hmg_patient_app/uitl/utils.dart';
import 'package:hmg_patient_app/widgets/dialogs/confirm_dialog.dart';
import 'package:flutter/cupertino.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:huawei_location/huawei_location.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';

class LocationUtils {
  AppSharedPreferences sharedPref = new AppSharedPreferences();

  bool isShowConfirmDialog;
  bool isShowLocationTimeoutDialog;
  BuildContext context;
  bool isHuawei;
  final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance;

  LocationUtils({required this.isShowConfirmDialog, required this.context, this.isHuawei = false, this.isShowLocationTimeoutDialog = true});

  void getCurrentLocation({Function(LatLng)? callBack, VoidCallback? onConsentDeclined}) async {
    if (Platform.isAndroid && isHuawei) {
      _getHMSCurrentLocation(callBack!);
    } else {
      Geolocator.isLocationServiceEnabled().then((value) async {
        if (value) {
          await Geolocator.checkPermission().then((permission) async {
            if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) {
              // Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) {
              Geolocator.getLastKnownPosition().then((value) {
                setLocation(value);
                if (callBack != null) callBack(LatLng(value?.latitude ?? 0.0, value?.longitude ?? 0.0));
              }).catchError((err) {
                print(err);
                if (isShowConfirmDialog && isShowLocationTimeoutDialog) {
                  showLocationTimeOutDialog(failureCallBack: () {
                    Geolocator.openAppSettings();
                  });
                } else {
                  onConsentDeclined?.call();
                }
              });
            }

            if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
              if (Platform.isAndroid) {
                Utils.showPermissionConsentDialog(context, TranslationBase.of(context).locationPermissionDialog, () async {
                  final hasPermission = await _handlePermission();
                  if (hasPermission) {
                    // Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) {
                    Geolocator.getLastKnownPosition().then((value) {
                      setLocation(value);
                      if (callBack != null) callBack(LatLng(value?.latitude ?? 0.0, value?.longitude ?? 0.0));
                    });
                  } else {
                    if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
                  }
                }, onConsentDeclined: () {
                  onConsentDeclined?.call();
                });
              } else {
                if (await Permission.location.request().isGranted) {
                  getCurrentLocation(callBack: callBack);
                } else {
                  setZeroLocation();
                  if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
                }
              }
            }
          }).catchError((err) {
            print(err);
          });
        } else {
          if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
        }
      }).catchError((err) {
        print(err);
      });
    }
  }

  Future<bool> checkIfGPSIsEnabled() async {
    if (Platform.isAndroid && isHuawei) {
      FusedLocationProviderClient locationService = FusedLocationProviderClient();
      LocationRequest locationRequest = LocationRequest();
      locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
      locationRequest.interval = 1000;
      List<LocationRequest> locationRequestList = <LocationRequest>[locationRequest];
      LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList);
      bool success = false;
      locationService.checkLocationSettings(locationSettingsRequest).then((settings) {
        success = true;
      });
      return success;
    }
    return await Geolocator.isLocationServiceEnabled();
  }

  Future<bool> _handlePermission() async {
    bool serviceEnabled;
    LocationPermission permission;

    serviceEnabled = await _geolocatorPlatform.isLocationServiceEnabled();
    if (!serviceEnabled) {
      return false;
    }

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

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

  late LocationCallback _locationCallback;

  _getHMSCurrentLocation(Function(LatLng) callBack) async {
    PermissionStatus permissionHandler = await Permission.location.request();

    // print(statuses[Permission.location]);

    int _locationUpdateCbId = 0;
    doIt() {
      FusedLocationProviderClient locationService = FusedLocationProviderClient();
      LocationRequest locationRequest = LocationRequest();
      locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
      locationRequest.interval = 1000;
      List<LocationRequest> locationRequestList = <LocationRequest>[locationRequest];
      LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList);

      locationService.checkLocationSettings(locationSettingsRequest).then((settings) async {
        _locationUpdateCbId = await locationService.requestLocationUpdatesCb(
            locationRequest,
            LocationCallback(onLocationResult: (locationResult) {
              Location location = locationResult.lastLocation!;
              locationService.removeLocationUpdatesCb(_locationUpdateCbId);
              callBack(LatLng(location.latitude!, location.longitude!));
              setLocation(
                Position(
                  latitude: location.latitude!,
                  longitude: location.longitude!,
                  altitude: location.altitude!,
                  timestamp: DateTime.now(),
                  accuracy: 1.0,
                  heading: 0.0,
                  speed: 0.0,
                  speedAccuracy: 1,
                  altitudeAccuracy: 0.0,
                  headingAccuracy: 0.0,
                  // altitudeAccuracy: 0.0,
                  //  headingAccuracy: 0.0,
                  //  altitudeAccuracy: 0,
                  // headingAccuracy: 0,
                  // Added by Aamir
                ),
              );
            }, onLocationAvailability: (locationAvailability) {
              print("onLocationAvailability: $locationAvailability");
            }));
      }).catchError((error) {
        if (error.code == "LOCATION_SETTINGS_NOT_AVAILABLE") {
          // Location service not enabled.
        }
      });
    }

    if (await permissionHandler.isGranted) {
      doIt();
    } else {
      bool has = await requestPermissions();
      if (has)
        doIt();
      else if (isShowConfirmDialog) showErrorLocationDialog(false);
    }
  }

  showLocationTimeOutDialog({Function()? failureCallBack}) {
    ConfirmDialog dialog = new ConfirmDialog(
        context: context,
        confirmMessage: TranslationBase.of(context).locationTimeoutError,
        okText: TranslationBase.of(context).ok,
        cancelText: TranslationBase.of(context).cancel_nocaps,
        okFunction: () {
          ConfirmDialog.closeAlertDialog(context);
          Navigator.of(context).canPop();
          if (failureCallBack != null) {
            failureCallBack();
          }
        },
        cancelFunction: () {
          if (failureCallBack != null) {
            failureCallBack();
          }
        });
    return dialog.showAlertDialog(context);
  }

  showErrorLocationDialog(bool isPermissionError, {Function()? failureCallBack}) {
    setLocation(null);
    ConfirmDialog dialog = new ConfirmDialog(
        context: context,
        confirmMessage: TranslationBase.of(context).locationDialogMessage,
        okText: TranslationBase.of(context).confirm,
        cancelText: TranslationBase.of(context).cancel_nocaps,
        okFunction: () {
          ConfirmDialog.closeAlertDialog(context);
          if (isPermissionError)
            Geolocator.openAppSettings();
          else
            Geolocator.openLocationSettings();
          Navigator.of(context).canPop();
          if (failureCallBack != null) {
            failureCallBack();
          }
        },
        cancelFunction: () {
          if (failureCallBack != null) {
            failureCallBack();
          }
        });
    return dialog.showAlertDialog(context);
  }

  void setLocation(Position? position) {
    this.sharedPref.setDouble(USER_LAT, position?.latitude ?? 0.0);
    this.sharedPref.setDouble(USER_LONG, position?.longitude ?? 0.0);
    ProjectViewModel projectViewModel = Provider.of(context, listen: false);
    projectViewModel.setLatitudeLongitude(position?.latitude ?? 0.0, position?.longitude ?? 0.0);
  }

  void setZeroLocation() {
    this.sharedPref.setDouble(USER_LAT, 0.0);
    this.sharedPref.setDouble(USER_LONG, 0.0);
  }

  Future<bool> requestPermissions() async {
    var result = await [
      Permission.location,
    ].request();
    return (result[Permission.location]!.isGranted || result[Permission.locationAlways]!.isGranted);
  }
}
