import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:path/path.dart' as p;

import 'package:fluttertoast/fluttertoast.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/exceptions/api_exception.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/widgets/loading_dialog.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';

class Utils {
  static bool _isLoadingVisible = false;

  static bool get isLoading => _isLoadingVisible;

  static void showToast(String message) {
    Fluttertoast.showToast(
        msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 2, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
  }

  static Future<void> openNumberViaCaller({required String phoneNumber}) async {
    Uri phoneLaunchUrl = Uri.parse('tel:$phoneNumber');

    if (await canLaunchUrl(phoneLaunchUrl)) {
      try {
        await launchUrl(phoneLaunchUrl);
      } catch (e) {
        await launchUrl(phoneLaunchUrl);
      }
    }
  }

  static Future<void> openEmailViaEmailApp({required String emailAddress}) async {
    Uri emailLaunchUrl = Uri.parse('mailto:$emailAddress');

    if (await canLaunchUrl(emailLaunchUrl)) {
      try {
        await launchUrl(emailLaunchUrl);
      } catch (e) {
        await launchUrl(emailLaunchUrl);
      }
    }
  }

  static Future<void> openNumberViaWhatsApp({required String phoneNumber}) async {
    final url = 'https://wa.me/$phoneNumber?text=';

    await launchUrlString(url, mode: LaunchMode.externalApplication);
  }

  static Future<String> pickDateFromDatePicker(BuildContext context, {DateTime? initial, DateTime? firstDate, DateTime? lastDate}) async {
    DateTime? pickedDate = await showDatePicker(
        context: context,
        initialDate: initial ?? DateTime.now(), //get today's date
        firstDate: firstDate ?? DateTime.now(), //DateTime.now() - not to allow to choose before today.
        lastDate: lastDate ?? DateTime(2101));

    if (pickedDate == null) {
      return "";
    }

    String formattedDate = DateHelper.formatAsYearMonthDay(pickedDate); // format date in required form here we use yyyy-MM-dd that means time is removed
    return formattedDate;
  }

  static Future<String> pickTime(BuildContext context, {TimeOfDay? initialTime}) async {
    TimeOfDay? timeOfDay = await showTimePicker(
      context: context,
      initialTime: initialTime ?? TimeOfDay.now(),
    );

    if (timeOfDay == null) {
      return "";
    }

    return ("${timeOfDay.hour.toString().length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute.toString().length == 1 ? "0" : ""}${timeOfDay.minute}").toString();
  }

  static dynamic getNotNullValue(List<dynamic> list, int index) {
    try {
      return list[index];
    } catch (ex) {
      return null;
    }
  }

  static int stringToHex(String colorCode) {
    try {
      return int.parse(colorCode.replaceAll("#", "0xff"));
    } catch (ex) {
      return (0xff000000);
    }
  }

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

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

  static void handleException(dynamic exception, Function(String)? onErrorMessage) {
    String errorMessage;
    if (exception is APIException) {
      if (exception.message == APIException.UNAUTHORIZED) {
        return;
      } else {
        errorMessage = exception.error?.errorMessage ?? exception.message;
      }
    } else {
      errorMessage = APIException.UNKNOWN;
    }
    if (onErrorMessage != null) {
      onErrorMessage(errorMessage);
    } else {
      showToast(errorMessage);
    }
  }

  static Color getColorFromHex(String hexColor) {
    hexColor = hexColor.toUpperCase().replaceAll('#', '');

    if (hexColor.length == 6) {
      hexColor = 'FF$hexColor';
    }

    return Color(int.parse(hexColor, radix: 16));
  }

  static Widget spacerVertical(double v) {
    return SizedBox(
      height: v,
      width: double.infinity,
    );
  }

  static String convertFileToBase64(File file) {
    List<int> imageBytes = file.readAsBytesSync();
    return base64Encode(imageBytes);
  }

  static Future delay(int millis) async {
    return await Future.delayed(Duration(milliseconds: millis));
  }

  static inkWellCorner({double? r}) {
    return RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(r ?? 4),
    );
  }

  static Widget spacerHorizontal(double v) {
    return SizedBox(
      height: v,
      width: v,
    );
  }

  static Widget mDivider(Color color, {double? h}) {
    return Container(
      width: double.infinity,
      height: h ?? 1,
      color: color,
    );
  }

  static Widget mDivider3({double? h}) {
    return Container(
      width: double.infinity,
      height: h ?? 1,
      color: borderLightColor!.withOpacity(0.7),
    );
  }

  static Widget mDivider2(Color color, double w) {
    return Container(
      width: w,
      height: 1,
      color: color,
    );
  }

  static Color getChipColorByAdStatus(AdPostStatus adPostStatus) {
    switch (adPostStatus) {
      case AdPostStatus.pendingForReview:
        return MyColors.adPendingStatusColor;

      case AdPostStatus.pendingForPayment:
        return MyColors.submittedColor;

      case AdPostStatus.rejected:
        return MyColors.adCancelledStatusColor;

      case AdPostStatus.cancelled:
        return MyColors.adCancelledStatusColor;

      case AdPostStatus.pendingForPost:
      case AdPostStatus.pendingForActive:
        return MyColors.inProgressColor;

      case AdPostStatus.active:
        return MyColors.greenColor;

      case AdPostStatus.expired:
        return MyColors.adCancelledStatusColor;

      case AdPostStatus.sold:
        return MyColors.adSoldStatusColor;

      case AdPostStatus.reserved:
        return MyColors.primaryColor;

      case AdPostStatus.deActive:
        return MyColors.textColor;

      case AdPostStatus.buyingService:
      case AdPostStatus.reserveCancel:
      case AdPostStatus.allAds:
        return MyColors.greenColor;
    }
  }

  static Color getChipColorByRequestStatus(RequestStatusEnum requestStatus) {
    switch (requestStatus) {
      case RequestStatusEnum.pending:
        return MyColors.pendingColor;
      case RequestStatusEnum.submitted:
        return MyColors.submittedColor;
      case RequestStatusEnum.inProgress:
        return MyColors.inProgressColor;
      case RequestStatusEnum.completed:
        return MyColors.completedColor;
      case RequestStatusEnum.cancelled:
        return MyColors.cancelledColor;
      case RequestStatusEnum.paid:
        return MyColors.paidColor;
      case RequestStatusEnum.expired:
        return MyColors.expiredColor;
      case RequestStatusEnum.shipping:
        return MyColors.shippingColor;
      case RequestStatusEnum.delivery:
        return MyColors.deliveryColor;
    }
  }

  static Color getChipColorByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) {
    switch (requestOfferStatusEnum) {
      case RequestOfferStatusEnum.offer:
        return MyColors.pendingColor;

      case RequestOfferStatusEnum.negotiate:
        return MyColors.submittedColor;

      case RequestOfferStatusEnum.accepted:
        return MyColors.completedColor;
      case RequestOfferStatusEnum.rejected:
        return MyColors.cancelledColor;

      case RequestOfferStatusEnum.cancel:
        return MyColors.cancelledColor;
    }
  }

  static String getNameByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) {
    switch (requestOfferStatusEnum) {
      case RequestOfferStatusEnum.offer:
        return "Offer";
      case RequestOfferStatusEnum.negotiate:
        return "Negotiate";
      case RequestOfferStatusEnum.accepted:
        return "Accepted";
      case RequestOfferStatusEnum.rejected:
        return "Rejected";
      case RequestOfferStatusEnum.cancel:
        return "Cancelled";
    }
  }

  static String getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
    switch (shippingRequestStatusEnum) {
      case ShippingRequestStatusEnum.allRequests:
        return "All Requests";

      case ShippingRequestStatusEnum.initiated:
        return "Initiated";

      case ShippingRequestStatusEnum.inTransit:
        return "In Transit";

      case ShippingRequestStatusEnum.outForDelivery:
        return "Out For Delivery";

      case ShippingRequestStatusEnum.delivered:
        return "Delivered";

      case ShippingRequestStatusEnum.pending:
        return "Pending";
    }
  }

  static Color getChipColorByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
    switch (shippingRequestStatusEnum) {
      case ShippingRequestStatusEnum.allRequests:
        return MyColors.submittedColor;

      case ShippingRequestStatusEnum.initiated:
        return MyColors.submittedColor;

      case ShippingRequestStatusEnum.inTransit:
        return MyColors.shippingColor;

      case ShippingRequestStatusEnum.outForDelivery:
        return MyColors.deliveryColor;

      case ShippingRequestStatusEnum.delivered:
        return MyColors.greenColor;

      case ShippingRequestStatusEnum.pending:
        return MyColors.pendingColor;
    }
  }

  static Color getChipColorByBranchStatus(BranchStatusEnum branchStatusEnum) {
    switch (branchStatusEnum) {
      case BranchStatusEnum.pending:
        return MyColors.adPendingStatusColor;

      case BranchStatusEnum.review:
        return MyColors.adPendingStatusColor;

      case BranchStatusEnum.rejected:
        return MyColors.adCancelledStatusColor;

      case BranchStatusEnum.deactivated:
        return MyColors.adCancelledStatusColor;

      case BranchStatusEnum.blocked:
        return MyColors.expiredColor;

      case BranchStatusEnum.approvedOrActive:
        return MyColors.greenColor;
    }
  }

  static String getChipStatusTextByBranchStatus(BranchStatusEnum branchStatusEnum) {
    switch (branchStatusEnum) {
      case BranchStatusEnum.pending:
        return "Pending Approval";

      case BranchStatusEnum.review:
        return "In Review";

      case BranchStatusEnum.rejected:
        return "Rejected";

      case BranchStatusEnum.deactivated:
        return "Deactivated";

      case BranchStatusEnum.blocked:
        return "Blocked";

      case BranchStatusEnum.approvedOrActive:
        return "Active";
    }
  }

  static statusContainerChip({
    required String text,
    EdgeInsetsGeometry padding = const EdgeInsets.symmetric(vertical: 3, horizontal: 6),
    Color chipColor = MyColors.greenColor,
    Color textColor = MyColors.white,
  }) {
    return Container(
        decoration: BoxDecoration(
          color: chipColor,
        ),
        padding: padding,
        child: text.toText(fontSize: 10, color: textColor, letterSpacing: -0.50));
  }

  static InputDecoration txtField(String label) {
    return InputDecoration(
      border: InputBorder.none,
      focusedBorder: InputBorder.none,
      enabledBorder: InputBorder.none,
      errorBorder: InputBorder.none,
      hintText: label,
      hintStyle: const TextStyle(color: Colors.grey),
      disabledBorder: InputBorder.none,
      isDense: false,
      contentPadding: const EdgeInsets.only(left: 15, right: 15),
    );
  }

  static Widget mFlex(int f) {
    return Flexible(
      flex: f,
      child: const SizedBox(
        width: double.infinity,
        height: double.infinity,
      ),
    );
  }

  static Widget mExp(int f) {
    return Expanded(
      flex: f,
      child: Container(
        width: double.infinity,
      ),
    );
  }

  static String checkFileExt(String path) {
    String ex = p.extension(path);
    var parts = ex.split('.');
    return parts[1]; // '.dart'
  }

  static spacer() {
    return const SizedBox(
      height: 8,
    );
  }

  static cardRadius(double radius) {
    return RoundedRectangleBorder(
      side: const BorderSide(color: Colors.transparent, width: 1),
      borderRadius: BorderRadius.circular(radius),
    );
  }

  static cardRadiusWithoutBorder(double radius) {
    return RoundedRectangleBorder(
      side: const BorderSide(color: Colors.transparent, width: 1),
      borderRadius: BorderRadius.circular(radius),
    );
  }

  static Image imageFromBase64String(String base64String) {
    return Image.memory(base64Decode(base64String));
  }

  static Uint8List dataFromBase64String(String base64String) {
    return base64Decode(base64String);
  }

  static String base64String(Uint8List data) {
    return base64Encode(data);
  }

  static Widget overLayWidget({double? width, double? height, List<Color>? color}) {
    return Container(
      width: width ?? double.infinity,
      height: height ?? 60,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: color ??
              [
                Colors.black.withOpacity(0.2),
                Colors.black.withOpacity(0.1),
                Colors.black.withOpacity(0.004),
              ],
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          tileMode: TileMode.clamp,
        ),
      ),
    );
  }

  static Decoration containerRadius(Color color, double r) {
    return BoxDecoration(
      color: color,
      borderRadius: BorderRadius.all(Radius.circular(r)),
    );
  }

  static Decoration containerRadiusTop({Color? color, double? r}) {
    return BoxDecoration(
      color: color ?? Colors.white,
      borderRadius: BorderRadius.only(topRight: Radius.circular(r ?? 12), topLeft: Radius.circular(r ?? 12)),
    );
  }

  static Decoration containerRadiusBorder(Color color, double r) {
    return BoxDecoration(
      color: Colors.transparent,
      border: Border.all(color: color, width: 1),
      borderRadius: BorderRadius.all(Radius.circular(r)),
    );
  }

  static Decoration containerRadiusBottom(Color color, double r) {
    return BoxDecoration(
      color: color,
      borderRadius: BorderRadius.only(bottomLeft: Radius.circular(r), bottomRight: Radius.circular(r)),
    );
  }

  static ShapeBorder cardRadiusTop(double radius) {
    return RoundedRectangleBorder(
      side: const BorderSide(color: Colors.transparent, width: 0),
      borderRadius: BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius)),
    );
  }

  static Decoration containerColorRadiusBorderWidth(Color background, double radius, Color color, double w) {
    return BoxDecoration(
      color: background,
      border: Border.all(
          width: w, //
          color: color //                  <--- border width here
          ),
      borderRadius: BorderRadius.circular(radius),
    );
  }

  static ShapeBorder cardRadiusTop2(double radius) {
    return RoundedRectangleBorder(
      borderRadius: BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius)),
    );
  }

  static ShapeBorder cardRadiusBottom(double radius) {
    return RoundedRectangleBorder(
      borderRadius: BorderRadius.only(bottomLeft: Radius.circular(radius), bottomRight: Radius.circular(radius)),
    );
  }

  static Decoration containerColorRadiusBorder(Color background, double radius, Color color) {
    return BoxDecoration(
      color: background,
      border: Border.all(
          width: 1, //
          color: color //                  <--- border width here
          ),
      borderRadius: BorderRadius.circular(radius),
    );
  }

  static bool passwordValidateStructure(String value) {
    String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{6,}$';
    RegExp regExp = RegExp(pattern);
    return regExp.hasMatch(value);
  }

  static bool isEmailValid(String email) {
    String p = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
    RegExp regExp = RegExp(p);
    return regExp.hasMatch(email);
  }

  static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) {
    return '<html> <head></head><body><form id="paymentForm" action="${ApiConsts.paymentWebViewUrl}" method="post"><input type="hidden" name="PaymentType" value="$paymentId"><input type="hidden" name="AdsID" value="$adId"></form><script type="text/javascript"> document.getElementById("paymentForm").submit(); </script></body></html>';
  }

  // BOTTOM SHEETS
  static void showHelpBottomSheet(BuildContext context) {
    return actionConfirmationBottomSheet(
      context: context,
      title: LocaleKeys.help.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
      subtitle: LocaleKeys.customerCarePrompt.tr(),
      isOnlyOneButton: true,
      actionButtonYes: Expanded(
        child: ShowFillButton(
          maxHeight: 55,
          title: LocaleKeys.callNow.tr(),
          fontSize: 18,
          onPressed: () {
            pop(context);
          },
        ),
      ),
      actionButtonNo: const SizedBox(),
    );
  }

  static Widget buildStatusContainer(String text, {double marginAll = 8, double fontSize = 14}) {
    if (text.isEmpty) {
      return const SizedBox();
    }
    return Center(
      child: text.toText(color: MyColors.lightTextColor, fontSize: fontSize),
    ).toContainer(
      marginAll: marginAll,
      paddingAll: 15,
      borderRadius: 8,
      width: double.infinity,
      backgroundColor: MyColors.grey98Color.withOpacity(0.1),
    );
  }

  static Future<void> openLocationInMaps({required double latitude, required double longitude}) async {
    final Uri googleMapsUrl = Uri.parse('https://www.google.com/maps/search/?api=1&query=$latitude,$longitude');

    if (await canLaunchUrl(googleMapsUrl)) {
      try {
        await launchUrl(googleMapsUrl);
      } catch (e) {
        await launchUrl(googleMapsUrl);
      }
    }
  }

  static Future<ShareResult> shareAppInvitation() async {
    ShareResult result = await Share.share(GlobalConsts.getAppInvitationLink(), subject: 'Join Mowater');
    return result;
  }
}
