import 'dart:convert';
import 'dart:developer';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:google_api_availability/google_api_availability.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart';
import 'package:hmg_patient_app_new/widgets/loading_dialog.dart';
import 'package:lottie/lottie.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Utils {
  static AppState appState = getIt.get<AppState>();
  static NavigationService navigationService = getIt.get<NavigationService>();

  static bool _isLoadingVisible = false;

  static bool get isLoading => _isLoadingVisible;

  static void showToast(String message, {bool longDuration = true}) {
    Fluttertoast.showToast(
        msg: message,
        toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
        gravity: ToastGravity.BOTTOM,
        timeInSecForIosWeb: 1,
        backgroundColor: AppColors.blackColor,
        textColor: AppColors.whiteColor,
        fontSize: 16.0);
  }

  static bool isArabicText(String inputText) {
    bool isArabicText = false;
    final arabic = RegExp(r'^[\u0621-\u064A]+');
    if (arabic.hasMatch(inputText)) {
      isArabicText = true;
    } else {
      isArabicText = false;
    }

    return isArabicText;
  }

  static String getFreeSlotsTimeText(String startTime, {bool isAddHours = false}) {
    // return DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add(
    //   Duration(
    //     hours: isAddHours ? 3 : 0,
    //   ),
    // ));
    return !isAddHours
        ? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal())
        : DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add(
            Duration(
              hours: isAddHours ? 3 : 0,
            ),
          ));
  }

  static String convertStringToDateTime(String dateTimeString) {
    String timeString = dateTimeString;
    // Parse the time string using DateFormat
    DateFormat format = DateFormat.Hms(); // 'Hms' = 'HH:mm:ss'
    DateTime time = format.parse(timeString);

    DateTime now = DateTime.now();
    DateTime dateTimeWithToday = DateTime(
      now.year,
      now.month,
      now.day,
      time.hour,
      time.minute,
      time.second,
    );

    return dateTimeWithToday.toIso8601String();
  }

  static String getMonthDayYearDateFormatted(DateTime dateTime) {
    return appState.isArabic()
        ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString()
        : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
  }

  /// get month by
  /// [month] convert month number in to month name
  static getMonth(int month) {
    switch (month) {
      case 1:
        return "January";
      case 2:
        return "February";
      case 3:
        return "March";
      case 4:
        return "April";
      case 5:
        return "May";
      case 6:
        return "June";
      case 7:
        return "July";
      case 8:
        return "August";
      case 9:
        return "September";
      case 10:
        return "October";
      case 11:
        return "November";
      case 12:
        return "December";
    }
  }

  /// get month by
  /// [month] convert month number in to month name in Arabic
  static getMonthArabic(int month) {
    switch (month) {
      case 1:
        return "يناير";
      case 2:
        return " فبراير";
      case 3:
        return "مارس";
      case 4:
        return "أبريل";
      case 5:
        return "مايو";
      case 6:
        return "يونيو";
      case 7:
        return "يوليو";
      case 8:
        return "أغسطس";
      case 9:
        return "سبتمبر";
      case 10:
        return " اكتوبر";
      case 11:
        return " نوفمبر";
      case 12:
        return "ديسمبر";
    }
  }

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

  static Future<bool> saveStringFromPrefs(String key, String value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setString(key, value);
  }

  static Future<int> getIntFromPrefs(String key) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getInt(key) ?? 0;
  }

  static Future<bool> saveIntFromPrefs(String key, int value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setInt(key, value);
  }

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

  static Future<bool> saveNumFromPrefs(String key, num value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setString(key, value.toString());
  }

  static Future<bool> removeFromPrefs(String key) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.remove(key);
  }

  static void showLoading({bool isNeedBinding = true}) {
    if (isNeedBinding) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        showLoadingDialog();
      });
    } else {
      showLoadingDialog();
    }
  }

  static void showLoadingDialog() {
    _isLoadingVisible = true;
    showDialog(
      context: navigationService.navigatorKey.currentContext!,
      barrierColor: AppColors.blackColor,
      builder: (BuildContext context) => LoadingDialog(),
    )
        .then((value) {
          _isLoadingVisible = false;
        })
        .catchError((e) {})
        .onError(
          (error, stackTrace) {},
        );
  }

  static void hideLoading() {
    try {
      if (_isLoadingVisible) {
        _isLoadingVisible = false;
        Navigator.of(navigationService.navigatorKey.currentContext!).pop();
      }
      _isLoadingVisible = false;
    } catch (e) {
      log("errr: ${e.toString()}");
    }
  }

  static List<T> uniqueBy<T, K>(List<T> list, K Function(T) keySelector) {
    final seenKeys = <K>{};
    return list.where((item) => seenKeys.add(keySelector(item))).toList();
  }

  static void showAppDialog(BuildContext context, String? title, String? message, VoidCallback? onTap) {
    showDialog(
      barrierDismissible: false,
      context: context,
      builder: (cxt) => ConfirmDialog(
        title: title!,
        message: message!,
        onTap: onTap,
      ),
    );
  }

  static bool isSAUDIIDValid(String id, type) {
    if (type == 1) {
      try {
        id = id.toString();
        id = id.trim();
        var returnValue = int.parse(id);
        var sum = 0;
        if (returnValue > 0) {
          var type = int.parse(id[0]);

          if (id.length != 10) {
            return false;
          }
          if (type != 2 && type != 1) {
            return false;
          }

          for (var i = 0; i < 10; i++) {
            if (i % 2 == 0) {
              var a = id[i];
              var x = int.parse(a) * 2;
              var b = x.toString();
              if (b.length == 1) {
                b = "0$b";
              }
              sum += int.parse(b[0]) + int.parse(b[1]);
            } else {
              sum += int.parse(id[i]);
            }
          }
          return sum % 10 == 0;
        }
      } catch (err) {
        log("errr: ${err.toString()}");
      }
      return false;
    } else {
      return true;
    }
  }

  static Widget getNoDataWidget(BuildContext context, {String? errorText}) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        SvgPicture.asset('assets/images/NoDataAvailableIcon.svg', width: 150.0, height: 150.0),
        (errorText ?? LocaleKeys.noDataAvailable.tr()).toText16(isCenter: true).paddingOnly(top: 15),
      ],
    ).center;
  }

  static Widget getLoadingWidget({String? loadingText}) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
        SizedBox(height: 8.h),
        (loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor),
        SizedBox(height: 8.h),
      ],
    ).center;
  }

  static bool isVidaPlusProject(AppState appState, int projectID) {
    bool isVidaPlus = false;
    for (var element in appState.vidaPlusProjectList) {
      if (element.projectID == projectID) {
        isVidaPlus = true;
      }
    }
    return isVidaPlus;
  }

  static getPhoneNumberWithoutZero(String number) {
    String newNumber = "";
    if (number.startsWith('0')) {
      newNumber = number.substring(1);
    } else {
      newNumber = number;
    }
    return newNumber;
  }

  static String removeHtmlTags(String htmlString) {
    if (htmlString.isEmpty) {
      return '';
    }

    // Replace HTML line breaks with newlines
    var withLineBreaks =
        htmlString.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'<divider>', multiLine: true), '\n');

    // Remove all other HTML tags
    var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), '');

    // Decode HTML entities
    var decodedString = withoutTags
        .replaceAll('&nbsp;', ' ')
        .replaceAll('&amp;', '&')
        .replaceAll('&lt;', '<')
        .replaceAll('&gt;', '>')
        .replaceAll('&quot;', '"')
        .replaceAll('&#39;', "'")
        .replaceAll('&rsquo;', "'")
        .replaceAll('&lsquo;', "'")
        .replaceAll('&rdquo;', '"')
        .replaceAll('&ldquo;', '"');

    // Remove extra whitespace and normalize line breaks
    var normalizedString = decodedString
        .replaceAll(RegExp(r'\n\s*\n'), '\n\n') // Replace multiple blank lines with double line break
        .replaceAll(RegExp(r' +'), ' ') // Replace multiple spaces with single space
        .trim(); // Remove leading/trailing whitespace

    return normalizedString;
  }

  Widget mDivider(Color color) {
    return Divider(
      // width: double.infinity,
      height: 1,
      color: color,
    );
  }

  // New Ui Items

  static String formatDateToDisplay(String isoDateString) {
    try {
      final dateTime = DateTime.parse(isoDateString);
      final day = dateTime.day.toString().padLeft(2, '0');
      final year = dateTime.year.toString();

      // Map month number to short month name
      const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
      final month = monthNames[dateTime.month - 1];

      return '$day $month, $year';
    } catch (e) {
      log("Error formatting date: $e");
      return "";
    }
  }

  static String formatHijriDateToDisplay(String hijriDateString) {
    try {
      // Assuming hijriDateString is in the format yyyy-MM-dd
      final datePart = hijriDateString.split("T").first;
      final parts = datePart.split('-');
      if (parts.length != 3) return "";

      final day = parts[2].padLeft(2, '0');
      final year = parts[0];

      // Map month number to short month name (Hijri months)
      const hijriMonthNames = ['Muharram', 'Safar', 'Rabi I', 'Rabi II', 'Jumada I', 'Jumada II', 'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah'];
      final monthIndex = int.tryParse(parts[1]) ?? 1;
      final month = hijriMonthNames[monthIndex - 1];

      return '$day $month, $year';
    } catch (e) {
      log("Error formatting hijri date: $e");
      return "";
    }
  }

  static String formatDateToUsage(String isoDateString) {
    try {
      final dateTime = DateTime.parse(isoDateString);
      final day = dateTime.day.toString().padLeft(2, '0');
      final month = dateTime.month.toString().padLeft(2, '0');
      final year = dateTime.year.toString();

      return '$day-$month-$year';
    } catch (e) {
      log("Error formatting date: $e");
      return "";
    }
  }

  static Widget showLottie({
    required BuildContext context,
    String assetPath = 'assets/icons/no_property.json',
    double? height,
    double? width,
    BoxFit fit = BoxFit.cover,
    Alignment alignment = Alignment.center,
    bool repeat = false,
    bool animate = true,
    void Function(LottieComposition)? onLoaded,
  }) {
    return Lottie.asset(assetPath,
        height: height ?? MediaQuery.of(context).size.height * 0.26,
        width: width ?? MediaQuery.of(context).size.width,
        fit: fit,
        alignment: alignment,
        repeat: repeat,
        animate: animate,
        onLoaded: onLoaded);
  }

  static Widget buildSvgWithAssets({
    required String icon,
    Color? iconColor,
    bool isDisabled = false,
    double width = 24,
    double height = 24,
    BoxFit fit = BoxFit.cover,
  }) {
    return SvgPicture.asset(
      icon,
      colorFilter: iconColor != null ? ColorFilter.mode(isDisabled ? iconColor.withOpacity(0.5) : iconColor, BlendMode.srcIn) : null,
      width: width,
      height: height,
      fit: fit,
    );
  }

  /// Widget to build an SVG from network
  static Widget buildSvgWithNetwork({
    required String url,
    required Color iconColor,
    bool isDisabled = false,
    double width = 24,
    double height = 24,
  }) {
    return SvgPicture.network(
      url,
      colorFilter: ColorFilter.mode(
        isDisabled ? iconColor.withOpacity(0.5) : iconColor,
        BlendMode.srcIn,
      ),
      width: width,
      height: height,
    );
  }

  static Widget getPaymentMethods() {
    return Row(
      mainAxisSize: MainAxisSize.max,
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Image.asset(AppAssets.mada, width: 25, height: 25),
        Image.asset(AppAssets.tamara_en, width: 25, height: 25),
        Image.asset(AppAssets.visa, width: 25, height: 25),
        Image.asset(AppAssets.Mastercard, width: 25, height: 25),
        Image.asset(AppAssets.apple_pay, width: 25, height: 25),
      ],
    );
  }

  static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true}) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        appState.isArabic()
            ? Container()
            : Utils.buildSvgWithAssets(
                icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol,
                iconColor: iconColor,
                width: iconSize.h,
                height: iconSize.h,
                fit: BoxFit.contain,
              ),
        SizedBox(width: 5.h),
        paymentAmountWidget,
        SizedBox(width: 5.h),
        !appState.isArabic()
            ? Container()
            : Utils.buildSvgWithAssets(
                icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol,
                iconColor: iconColor,
                width: iconSize.h,
                height: iconSize.h,
                fit: BoxFit.contain,
              ),
      ],
    );
  }

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

  static Future<bool> checkConnection({bool bypassConnectionCheck = false}) async {
    if (bypassConnectionCheck) return true;
    List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) {
      return true;
    } else {
      return false;
    }
  }

  static String generateMd5Hash(String input) {
    return crypto.md5.convert(utf8.encode(input)).toString();
  }

  static String getAppointmentTransID(int projectID, int clinicID, int appoNo, {bool isAddMilliseconds = true}) {
    String currentMillis = DateTime.now().millisecondsSinceEpoch.toString();
    return '$projectID-$clinicID-$appoNo${isAddMilliseconds ? '-${currentMillis.substring(currentMillis.length - 5, currentMillis.length)}' : ""}';
  }

  static String getAdvancePaymentTransID(int projectID, int fileNumber) {
    return '$projectID-$fileNumber-${DateTime.now().millisecondsSinceEpoch}';
  }
}
