import '../../../common/config.dart';
import '../../../common/tools.dart';
import '../../../modules/dynamic_layout/helper/helper.dart';
import '../../entities/woo_smart_cod.dart';
import '../../index.dart';
import '../cart_item_meta_data.dart';

mixin CartMixin {
  User? user;
  double taxesTotal = 0;
  List<Tax> taxes = [];
  bool isIncludingTax = false;
  double rewardTotal = 0;
  double walletAmount = 0;
  bool enableCheckoutButton = true;

  List<Fee> fees = [];

  PaymentMethod? paymentMethod;
  LoyaltyCoupon? loyaltyCoupon;
  WooSmartCod? wooSmartCod;

  String? notes;

  /// The currency code for the cart and checkout process. It may be different
  /// from the currency code of AppModel. For example, in the case of a wallet
  /// cart, the currency code is set to the default currency code.
  String? currencyCode;
  Map<String, dynamic>? currencyRates;

  // The IDs and products currently in the cart.
  final Map<String?, Product?> item = {};

  // The IDs and quantities of products and variant products currently in the cart.
  final Map<String, int?> productsInCart = {};

  // The IDs and cart item metadata in the cart.
  final Map<String, CartItemMetaData?> cartItemMetaDataInCart = {};

  void resetValues() {
    user = null;
    taxesTotal = 0;
    taxes = [];
    fees = [];
    isIncludingTax = false;
    rewardTotal = 0;
    walletAmount = 0;
    enableCheckoutButton = true;

    paymentMethod = null;
    loyaltyCoupon = null;
    wooSmartCod = null;

    notes = null;
    currencyCode = null;
    currencyRates = null;

    item.clear();
    cartItemMetaDataInCart.clear();
    productsInCart.clear();
  }

  /// Resetting the 'smart cod' does not call the model update method
  /// (possibly `notifyListeners`), so in some cases, the model will not refresh
  /// immediately.
  ///
  /// Caution is advised when using this function.
  void resetSmartCod() {
    wooSmartCod = null;
  }

  Future<void> resetCheckoutInfo() async {
    setFees([]);
    setTaxInfo([], 0.0, false);
    setWalletAmount(0.0);
  }

  void removeItemFromProductId(String productId) {}

  int get totalCartQuantity => productsInCart.values.fold(0, (v, e) => v + e!);

  bool _hasProductVariation(String id) {
    var productVariation = cartItemMetaDataInCart[id]?.variation;
    return productVariation?.price?.isNotEmpty ?? false;
  }

  double getProductPrice(id) {
    if (_hasProductVariation(id)) {
      final item = cartItemMetaDataInCart[id];
      final price = item?.variation?.valuePrice ?? 0.0;
      return price * productsInCart[id]!;
    } else {
      var productId = Product.cleanProductID(id);

      var price = PriceTools.getPriceProductValue(
        item[productId],
        bookingInfo: cartItemMetaDataInCart[id]?.bookingInfo,
        onSale: true,
      );
      if ((price?.isNotEmpty ?? false) && productsInCart[id] != null) {
        return double.parse(price!) * productsInCart[id]!;
      }
      return 0.0;
    }
  }

  double getProductAddonsPrice(String id) {
    var addOns = cartItemMetaDataInCart[id]?.addonsOptions;
    var price = 0.0;
    if (addOns == null) {
      return 0.0;
    }
    for (var option in addOns) {
      var quantity = productsInCart[id] ?? 0;
      var optionPrice = (double.tryParse(option.price ?? '0.0') ?? 0.0);
      if (option.isQuantityBased) {
        optionPrice *= quantity;
      }
      price += optionPrice;
    }
    return price;
  }

  double? getSubTotal() {
    return productsInCart.keys.fold(0.0, (sum, id) {
      final product = getProductPrice(id);
      final addonsPrice = getProductAddonsPrice(id);
      final componentsPrice = getProductComponentsPrice(id);

      return sum! + product + addonsPrice + componentsPrice;
    });
  }

  void setPaymentMethod(data) {
    paymentMethod = data;
  }

  void setLoyaltyCoupon(data) {
    loyaltyCoupon = data;
  }

  void setWooSmartCod(data) {}

  // Returns the Product instance matching the provided id.
  Product? getProductById(String id) {
    return item[id];
  }

  // Returns the Product instance matching the provided id.
  ProductVariation? getProductVariationById(String key) {
    return cartItemMetaDataInCart[key]?.variation;
  }

  /// Get the current cart ID if available
  /// This method is used to get the cart ID from the cart data
  /// This method is used for Shopify
  String getCartId() {
    return '';
  }

  void setUser(data) {
    user = data;
  }

  void loadSavedCoupon() {}

  bool isEnabledShipping() {
    return kPaymentConfig.enableShipping;
  }

  void setWalletAmount(double total) {
    walletAmount = total;
  }

  bool isWalletCart() {
    return false;
  }

  bool isB2BKingCart() {
    return false;
  }

  void addWalletProductToCart({required Product product, int quantity = 1}) {
    final key = product.id.toString();
    item[product.id] = product;
    productsInCart[key] = quantity;

    currencyCode = kAdvanceConfig.defaultCurrency?.currencyCode;
  }

  void setTaxInfo(List<Tax> taxes, double taxesTotal, bool isIncludingTax) {
    this.taxes = taxes;
    this.taxesTotal = taxesTotal;
    this.isIncludingTax = isIncludingTax;
  }

  void setFees(List<Fee> fees) {
    this.fees = fees;
  }

  double getCODExtraFee() {
    final enabled =
        (kPaymentConfig.smartCOD?.enabled ?? false) &&
        kCashOnDeliveryConfig
            .getValueList('paymentMethodIds')
            .contains(paymentMethod?.id);
    final extraFee = kPaymentConfig.smartCOD?.extraFee ?? 0;
    final amountStop = kPaymentConfig.smartCOD?.amountStop ?? 0;
    final subtotal = getSubTotal() ?? 0;
    return (enabled && extraFee > 0 && subtotal < amountStop) &&
            double.tryParse('$extraFee') != null
        ? double.parse('$extraFee')
        : 0;
  }

  /// Get product detail with quantity in the current cart
  List getProductsInCart() {
    var productList = [];
    for (var key in productsInCart.keys) {
      var productId = Product.cleanProductID(key);
      var product = getProductById(productId);

      if (product != null) {
        productList.add({
          'id': key,
          'product': product,
          'quantity': productsInCart[key],
        });
      }
    }
    return productList;
  }

  void updateProduct(String productId, Product? product) {
    //keep booking info after choose datetime in detail screen.
    var oldProduct = item[productId];
    if (oldProduct != null) {
      if (oldProduct.bookingInfo != null) {
        product?.bookingInfo = oldProduct.bookingInfo;
      }
      item[productId] = product;
    }
  }

  void updateProductVariant(
    String productId,
    ProductVariation? productVariant,
  ) {
    cartItemMetaDataInCart[productId] = cartItemMetaDataInCart[productId]
        ?.copyWith(variation: productVariant);
  }

  void updateStateCheckoutButton() {
    enableCheckoutButton = true;
    // Check all product and variation in cart
    for (var key in productsInCart.keys) {
      var productId = Product.cleanProductID(key);
      var variation = getProductVariationById(key);
      var product = getProductById(productId);
      var quantityProductInCart = productsInCart[key];
      final maxAllowQuantity =
          Helper.formatInt(kCartDetail['maxAllowQuantity']) ?? 100;

      var inStock =
          (variation != null ? variation.inStock : product?.inStock) ?? false;

      var totalQuantity = variation != null
          ? (variation.stockQuantity ?? maxAllowQuantity)
          : (product?.stockQuantity ?? maxAllowQuantity);

      var limitQuantity = totalQuantity > maxAllowQuantity
          ? maxAllowQuantity
          : totalQuantity;

      final isOnBackorder = variation != null
          ? variation.backordersAllowed ?? false
          : product?.backordersAllowed ?? false;

      if (isOnBackorder == false) {
        if (!inStock) {
          enableCheckoutButton = false;
          break;
        }
        if (inStock &&
            quantityProductInCart != null &&
            quantityProductInCart > limitQuantity) {
          enableCheckoutButton = false;
          break;
        }
      }
    }
  }

  double getProductComponentsPrice(String id) {
    var productComponents = cartItemMetaDataInCart[id]?.selectedComponents;
    var price = 0.0;
    if (productComponents == null) {
      return 0.0;
    }
    for (var item in productComponents.values) {
      var quantity = productsInCart[id] ?? 0;
      var optionPrice = (item.getPrice() ?? 0.0) * quantity;
      price += optionPrice;
    }
    return price;
  }

  double? getTotal();

  double? getPaymentTotal() => getTotal();
}
