import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_api_availability/google_api_availability.dart';
import 'package:huawei_location/huawei_location.dart';
import 'package:intl/intl.dart';
import 'package:nfc_manager/nfc_manager.dart';
import 'package:nfc_manager/platform_tags.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/main.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/swipe_module/dialoge/confirm_dialog.dart';
import 'package:test_sa/new_views/swipe_module/dialoge/nfc_reader_sheet.dart';
import 'package:test_sa/new_views/swipe_module/enums/swipe_type.dart';
import 'package:test_sa/new_views/swipe_module/models/swipe_model.dart';
import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart';
import 'package:test_sa/new_views/swipe_module/utils/location_utils.dart';
import 'package:test_sa/views/widgets/qr/scan_qr.dart';
import 'package:wifi_iot/wifi_iot.dart';

class SwipeGeneralUtils {
  SwipeGeneralUtils._();

  static SwipeGeneralUtils instance = SwipeGeneralUtils._();
  static bool _isLoadingVisible = false;

  static bool get isLoading => _isLoadingVisible;

  void markFakeAttendance(dynamic sourceName, String lat, String long, @required BuildContext context) async {
    showLoading(context);
    try {
      hideLoading(navigatorKey.currentState!.overlay!.context);
      confirmDialog(navigatorKey.currentState!.overlay!.context, "Fake Location)");
    } catch (ex) {
      log('$ex');
      hideLoading(context);
      //handleException(ex, context, null);
    }
  }

  void showLoading(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _isLoadingVisible = true;
      showDialog(
        context: context,
        barrierColor: Colors.black.withOpacity(0.5),
        useRootNavigator: false,
        builder: (BuildContext context) => const AppLazyLoading(),
      ).then((value) {
        _isLoadingVisible = false;
      });
    });
  }

  void hideLoading(BuildContext context) {
    if (_isLoadingVisible) {
      _isLoadingVisible = false;
      Navigator.of(context).pop();
    }
    _isLoadingVisible = false;
  }

  static Future<String> getStringFromPrefs(String key) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getString(key) ?? "";
  }

  void confirmDialog(cxt, String message, {VoidCallback? onTap}) {
    showDialog(
      context: cxt,
      builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap),
    );
  }

  void showErrorDialog({String ?message, required BuildContext context}) {
    showDialog(
      context: context,
      builder: (context) => ConfirmDialog(message: message, title: 'Error', onTap: () => Navigator.pop(context)),
    );
  }

  void showMDialog(context, {Widget ?child, Color? backgroundColor, bool isDismissable = true, bool isBusniessCard = false}) async {
    return showDialog(
      context: context,
      barrierDismissible: isDismissable,
      builder: (context) {
        return Dialog(
          shape: isBusniessCard
              ? const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(15.0),
                  ),
                )
              : null,
          backgroundColor: backgroundColor,
          child: child,
        );
      },
    );
  }

  Widget attendanceTypeCard(String title, String icon, bool isEnabled, VoidCallback onPress, BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: isEnabled ? Colors.white : AppColor.white70,
        borderRadius: BorderRadius.circular(18),
        border: Border.all(color: AppColor.white70, width: 2),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          icon.toSvgAsset(color: isEnabled ? null : Colors.grey.withOpacity(0.5)),
          title.heading5(context).custom(color: isEnabled ? AppColor.neutral50 : Colors.grey.withOpacity(0.5)),
        ],
      ),
    ).onPress(
      () {
        if (!isEnabled) return;
        onPress();
      },
    );
  }

  //huawei permission part....
  void getHuaweiCurrentLocation({SwipeTypeEnum ?attendanceType, required BuildContext context}) async {
    try {
      showLoading(context);
      FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService();
      LocationRequest locationRequest = LocationRequest();
      locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
      locationRequest.interval = 500;
      List<LocationRequest> locationRequestList = <LocationRequest>[locationRequest];
      LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList);

      late StreamSubscription<Location> _streamSubscription;
      int requestCode = (await (locationService.requestLocationUpdates(locationRequest)))!;
      _streamSubscription = locationService.onLocationData!.listen(
        (Location location) async {
          hideLoading(context);
          await locationService.removeLocationUpdates(requestCode);
          handleSwipeOperation(swipeType: attendanceType!, context: context, lat: location.latitude??0, long: location.longitude??0);
          requestCode = 0;
          _streamSubscription.cancel();
        },
      );
    } catch (error) {
      log("HUAWEI LOCATION ERROR!!!!!");
      log('$error');
      hideLoading(context);
      // handleException(error, context, null);
    }
  }

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

  void checkHuaweiLocationPermission({required SwipeTypeEnum attendanceType,required  BuildContext context}) async {
    // Permission_Handler permissionHandler = PermissionHandler();
    LocationUtilities.isEnabled((bool isEnabled) async {
      if (isEnabled) {
        LocationUtilities.havePermission((bool permission) async {
          if (permission) {
            getHuaweiCurrentLocation(attendanceType: attendanceType, context: context);
          } else {
            bool has = await requestPermissions();
            if (has) {
              getHuaweiCurrentLocation(attendanceType: attendanceType, context: context);
            } else {
              showDialog(
                context: context,
                builder: (BuildContext cxt) => ConfirmDialog(
                  message: "You need to give location permission to mark attendance",
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
              );
            }
          }
        });
      } else {
        showDialog(
          context: context,
          builder: (BuildContext cxt) => ConfirmDialog(
            message: "You need to enable location services to mark attendance",
            onTap: () async {
              Navigator.pop(context);
              await Geolocator.openLocationSettings();
            },
          ),
        );
      }
    });

    // if (await permissionHandler.hasLocationPermission()) {
    //   getHuaweiCurrentLocation(attendanceType);
    // } else {
    //   bool has = await requestPermissions();
    //   if (has) {
    //     getHuaweiCurrentLocation(attendanceType);
    //   } else {
    //     showDialog(
    //       context: context,
    //       builder: (BuildContext cxt) => ConfirmDialog(
    //         message: "You need to give location permission to mark attendance",
    //         onTap: () {
    //           Navigator.pop(context);
    //         },
    //       ),
    //     );
    //   }
    // }
  }

  void handleSwipeOperation({required SwipeTypeEnum swipeType,required double lat,required double long,required  BuildContext context}) {
    switch (swipeType) {
      case SwipeTypeEnum.NFC:
        handleNfcAttendance(latitude: lat, longitude: long, context: context);
        return;
      case SwipeTypeEnum.QR:
        performQrCodeAttendance(latitude: lat, longitude: long, context: context);
        return;
      case SwipeTypeEnum.Wifi:
        performWifiAttendance(latitude: lat, long: long, context: context);
        return;
    }
  }

  String formatTimeOnly(DateTime dateTime) {
    return DateFormat.Hms().format(dateTime);
  }

  Future<void> performQrCodeAttendance({double ?latitude, double? longitude,required  BuildContext context}) async {
    UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);

    String qrCodeValue = await Navigator.of(context).push(
      MaterialPageRoute(builder: (_) => ScanQr()),
    ) as String;

    if (qrCodeValue != null) {
      showLoading(context);
      try {
        final swipeModel = Swipe(
          swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(),
          value: qrCodeValue,
          latitude: latitude,
          longitude: longitude,
        );

        await userProvider.makeSwipe(model: swipeModel).then((swipeResponse) {
          if (swipeResponse.isSuccess==true) {
            hideLoading(context);
            Navigator.pushNamed(context, SwipeSuccessView.routeName);
          } else {
            hideLoading(context);
            showDialog(
              barrierDismissible: true,
              context: context,
              builder: (cxt) => ConfirmDialog(
                message: swipeResponse.message ?? "",
                onTap: () {
                  Navigator.pop(context);
                },
                onCloseTap: () {},
              ),
            );
          }
        });
      } catch (ex) {
        log('$ex');
        hideLoading(context);
        //this need to confirm where it comes..
        // handleException(ex, context, null);
      }
    }
  }

  Future<void> handleNfcAttendance({double ?latitude = 0, double? longitude = 0,required  BuildContext context}) async {
    // UserProvider _userProvider = Provider.of<UserProvider>(context,listen:false);

    if (Platform.isIOS) {
      readNFc(onRead: (String nfcId) async {
        await _processNfcAttendance(nfcId, latitude, longitude, context);
      });
    } else {
      showNfcReader(context, onNcfScan: (String nfcId) async {
        await _processNfcAttendance(nfcId ?? '', latitude, longitude, context);
      });
    }
  }

  Future<void> _processNfcAttendance(
    String nfcId,
    double ?latitude,
    double ?longitude,
    BuildContext context,
  ) async {
    showLoading(context);
    try {
      final swipeModel = Swipe(swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(), value: nfcId, latitude: latitude, longitude: longitude);
      UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);

      final swipeResponse = await userProvider.makeSwipe(model: swipeModel);

      if (swipeResponse.isSuccess==true) {
        hideLoading(context);
        Navigator.pushNamed(context, SwipeSuccessView.routeName);
      } else {
        hideLoading(context);
        showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context);
      }
    } catch (errSwipeGeneralUtilsor) {
      hideLoading(context);
    }
  }

  void handleSwipe({required SwipeTypeEnum swipeType, required bool isEnable, required BuildContext context}) async {
    if (Platform.isAndroid && !(await isGoogleServicesAvailable())) {
      checkHuaweiLocationPermission(attendanceType: swipeType, context: context);
    } else {
      LocationUtilities.isEnabled((bool isEnabled) {
        if (isEnabled) {
          LocationUtilities.havePermission((bool permission) {
            if (permission) {
              showLoading(context);
              LocationUtilities.getCurrentLocation(
                (Position position, bool isMocked) {
                  if (isMocked) {
                    hideLoading(context);
                    markFakeAttendance(swipeType.name, position.latitude.toString() ?? "", position.longitude.toString() ?? "", context);
                  } else {
                    hideLoading(context);
                    handleSwipeOperation(swipeType: swipeType, lat: position.latitude, long: position.longitude, context: context);
                  }
                },
                () {
                  hideLoading(context);
                  confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working.");
                },
                context,
              );
            } else {
              showInfoDialog(
                  message: "You need to give location permission to mark attendance",
                  onTap: () async {
                    await Geolocator.openAppSettings();
                  });
            }
          });
        } else {
          showInfoDialog(
              message: "You need to enable location services to mark attendance",
              onTap: () async {
                await Geolocator.openLocationSettings();
              });
        }
      });
    }
  }

  void showInfoDialog({required String message, VoidCallback? onTap}) {
    showDialog(
      context: navigatorKey.currentState!.overlay!.context,
      builder: (BuildContext cxt) => ConfirmDialog(
        message: message,
        onTap: () async {
          Navigator.pop(navigatorKey.currentState!.overlay!.context);
          onTap!();
        },
      ),
    );
  }

  List<Widget> availableAttendanceMethodList({required BuildContext context, required UserProvider userProvider, required bool isNfcSupported}) {
    List<Widget> availableMethods = [];
    if (userProvider.user!.enableNFC!) {
      availableMethods.add(attendanceTypeCard(SwipeTypeEnum.NFC.name, 'nfc_icon', isNfcSupported, () {
        Navigator.pop(context);
        handleSwipe(swipeType: SwipeTypeEnum.NFC, isEnable: userProvider.user!.enableNFC!, context: navigatorKey.currentState!.overlay!.context);
      }, context));
    }
    if (userProvider.user!.enableQR!) {
      availableMethods.add(attendanceTypeCard(SwipeTypeEnum.QR.name, 'qr', userProvider.user!.enableQR!, () {
        Navigator.pop(context);
        handleSwipe(swipeType: SwipeTypeEnum.QR, isEnable: userProvider.user!.enableQR!, context: navigatorKey.currentState!.overlay!.context);
      }, context));
    }
    if (kDebugMode) {
      userProvider.user!.enableWifi!= true;
    }

    if (userProvider.user!.enableWifi!) {
      availableMethods.add(attendanceTypeCard(SwipeTypeEnum.Wifi.name, 'wifi_icon', userProvider.user!.enableWifi!, () {
        Navigator.pop(context);
        handleSwipe(swipeType: SwipeTypeEnum.Wifi, isEnable: userProvider.user!.enableWifi!, context: navigatorKey.currentState!.overlay!.context);
      }, context));
    }
    return availableMethods;
  }

  void showSwipeTypeBottomSheetSheet({required bool isNfcSupported}) {
    BuildContext context = navigatorKey.currentState!.overlay!.context;
    UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);

    showModalBottomSheet(
      context: context,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(
          top: Radius.circular(20),
        ),
      ),
      clipBehavior: Clip.antiAliasWithSaveLayer,
      builder: (BuildContext context) => Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          context.translation.markAttendance.heading4(context).custom(color: AppColor.white936),
          8.height,
          context.translation.selectMethodToMarkAttendance.bodyText2(context).custom(color: AppColor.neutral120),
          12.height,
          GridView(
              padding: const EdgeInsets.all(0),
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
              children: availableAttendanceMethodList(context: context, userProvider: _userProvider, isNfcSupported: isNfcSupported)),
        ],
      ).paddingAll(16),
    );
  }

  void readNFc({Function(String) ?onRead}) {
    NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
      MifareUltralight f;
      if (Platform.isAndroid) {
        f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
      } else {
        f = MifareUltralight(tag: tag, identifier: tag.data["mifare"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
      }
      String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join('');
      NfcManager.instance.stopSession();
      onRead!(identifier);
    }).catchError((err) {
      print(err);
    });
  }

  //HUAWEI DECISION MAKING
  Future<bool> isGoogleServicesAvailable() async {
    GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
    String status = availability.toString().split('.').last;
    if (status == "success") {
      return true;
    }
    return false;
  }

  Future<void> performWifiAttendance({required double latitude, required double long, required BuildContext context}) async {
    String ssId = String.fromCharCodes(base64Decode("SE1HLU1PSEVNTQ=="));
    String password = String.fromCharCodes(base64Decode("TTBoZW1tQDEyMTI="));
    showLoading(context);
    bool isConnected = await WiFiForIoTPlugin.connect(ssId, password: password, joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false);

    if (Platform.isIOS) {
      if (await WiFiForIoTPlugin.getSSID() == ssId) {
        isConnected = true;
      } else {
        isConnected = false;
      }
    }
    UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);

    if (isConnected) {
      await WiFiForIoTPlugin.forceWifiUsage(true);
      await Future.delayed(const Duration(seconds: 6));
      try {
        final swipeModel = Swipe(swipeTypeValue: SwipeTypeEnum.Wifi.getIntFromSwipeTypeEnum(), value: '', latitude: latitude, longitude: long);

        final swipeResponse = await userProvider.makeSwipe(model: swipeModel);
        await closeWifiRequest();
        if (swipeResponse.isSuccess==true) {
          hideLoading(context);
          Navigator.pushNamed(context, SwipeSuccessView.routeName);
        } else {
          hideLoading(context);
          await Future.delayed(const Duration(milliseconds: 250));
          showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context);
        }
      } catch (errSwipeGeneralUtilsor) {
        hideLoading(context);
        await closeWifiRequest();
      }
    } else {
      // if (userProvider.) {
      hideLoading(context);
      confirmDialog(context, "Come Near HMG Wifi");
      // } else {
      //   await closeWifiRequest();
      // }
      await closeWifiRequest();
    }
  }

  Future<bool> closeWifiRequest() async {
    if (Platform.isAndroid) {
      await WiFiForIoTPlugin.forceWifiUsage(false);
    }
    return await WiFiForIoTPlugin.disconnect();
  }
}
