const UserCart = require("../../models/UserCart");
const Products = require("../../models/Products");
const ProductMenu = require("../../models/ProductMenu");
const ProductsVariation = require("../../models/ProductVariation");
const ProductsSubVariation = require("../../models/ProductSubVariation");
const {
  getUserCartExcludes,
  getProductUserCartExcludes,
} = require("../../helpers/model-excludes-attributes/excludes");
const ProductVariation = require("../../models/ProductVariation");
const ProductSubVariation = require("../../models/ProductSubVariation");
const Sequelize = require("sequelize");
const SellersCompany = require("../../models/SellersCompany");
const {
  sellerEnabledPurchaseOrders,
  checkPOItemStock,
} = require("../../services/purchase-order.service");

exports.addToCart = async (req, res, next) => {
  try {
    const { customerId } = req;
    const { product_id, quantity, variation_id, sub_variation_id } = req.body;

    // Check if cart has value and is in array and has length of 1 above.
    if (!product_id || !quantity)
      return res.status(400).json({ success: false, message: "Invalid cart." });

    // Validate the cart if it has valid ids & has enough stocks
    const errors = [];
    const promises = [];
    const validUserCart = [];

    // Get current user cart.
    const currentUserCart = await UserCart.findAll({
      where: {
        user_id: customerId,
      },
    });

    const product = await Products.findOne({
      where: {
        id: product_id,
        available: 1,
        product_status: true,
      },
      include: [
        {
          model: ProductMenu,
          as: "menus",
          attributes: ["size_category"],
        },
        {
          model: SellersCompany,
          as: "seller",
          attributes: ["id", "warehouse_id"],
        },
      ],
    });

    const sellerEnablePO = await sellerEnabledPurchaseOrders(product.seller_id);

    let itemStock = parseFloat(product.stocks);

    if (sellerEnablePO) {
      const poItemStock = await checkPOItemStock(product.id);
      itemStock = poItemStock.availableStock;
    }

    if (!product) {
      errors.push({ message: `Product with id ${product_id} not found` });
    }
    if (product && itemStock < quantity) {
      errors.push({
        message: `Not enough stocks available for product with id ${product_id}`,
      });
    }
    if (product && product.quantity_limit < quantity) {
      errors.push({
        message: `Quantity limit reached! Allowed qty:  ${product.quantity_limit}`,
      });
    }

    let chosenVariation = null;
    let chosenSubVariation = null;

    if (variation_id) {
      chosenVariation = await ProductsVariation.findOne({
        where: {
          id: variation_id,
          product_id: product_id,
        },
      });

      if (!chosenVariation) {
        errors.push({
          message: `Chosen variation not found for product with id ${product_id}`,
        });
      }

      if (chosenVariation.hasSubVariation && sub_variation_id) {
        chosenSubVariation = await ProductsSubVariation.findOne({
          where: {
            id: sub_variation_id,
            product_variation_id: variation_id,
          },
        });

        if (!chosenSubVariation) {
          errors.push({
            message: `Chosen sub-variation not found or does not belong to the chosen variation for product with id ${product_id}`,
          });
        }
      }
    }

    const isValidProductCategory = await validateProductCategory(
      currentUserCart,
      product
    );
    const isValidSeller = await validateProductSeller(currentUserCart, product);
    if (!isValidProductCategory) {
      errors.push({
        message: `Chosen item does not fit the current item category in user cart.`,
      });
    }
    if (!isValidSeller) {
      errors.push({
        message: `Chosen item does not fit the current seller in user cart.`,
      });
    }

    if (errors.length > 0) {
      return res.status(200).json({ success: false, errors });
    }
    const pricePerItem = chosenSubVariation
      ? chosenSubVariation.discounted_price &&
        chosenSubVariation.discounted_price !== null &&
        chosenSubVariation.discounted_price > 0
        ? chosenSubVariation.discounted_price
        : chosenSubVariation.price
      : chosenVariation
      ? chosenVariation.discounted_price &&
        chosenVariation.discounted_price !== null &&
        chosenVariation.discounted_price > 0
        ? chosenVariation.discounted_price
        : chosenVariation.price
      : product.discounted_price &&
        product.discounted_price !== null &&
        product.discounted_price > 0
      ? product.discounted_price
      : product.price;

    const totalPriceForItem = parseFloat(pricePerItem);

    const areEqual = (a, b) =>
      a === b || (a == null && b === "") || (a === "" && b == null);

    const existingItemInCart = currentUserCart.find(
      (userCart) =>
        userCart.menu_id === product_id &&
        areEqual(userCart.product_variation_id, variation_id) &&
        areEqual(userCart.product_sub_variation_id, sub_variation_id)
    );

    if (existingItemInCart) {
      const existingItemCartQuantity = existingItemInCart.quantity;
      const existingItemCartPrice = existingItemInCart.price;
      const updateJson = {
        quantity: parseFloat(existingItemCartQuantity) + parseFloat(quantity),
        price: parseFloat(totalPriceForItem),
      };

      const updateQuery = UserCart.update(updateJson, {
        where: {
          id: existingItemInCart.id,
        },
      });
      promises.push(updateQuery);
    } else {
      validUserCart.push({
        user_id: customerId,
        menu_id: product_id,
        quantity,
        price: parseFloat(totalPriceForItem),
        has_sub_variation_chosen: chosenSubVariation ? "true" : "false",
        product_variation_id: chosenVariation ? chosenVariation.id : null,
        product_sub_variation_id: chosenSubVariation
          ? chosenSubVariation.id
          : null,
        created_at: new Date(),
      });
    }

    // To Do:
    // Validation if Different Seller is in same warehouse.

    if (validUserCart.length > 0) {
      promises.push(UserCart.bulkCreate(validUserCart));
    }

    await Promise.all(promises);

    res.status(201).json({ success: true });
  } catch (err) {
    next(err);
  }
};

const validateProductCategory = async (currentUserCart, product) => {
  if (!currentUserCart || !product) return false;
  let validCategory = true;
  const productCategory =
    product && product.menus && product.menus.size_category
      ? product.menus.size_category
      : null;
  if (
    currentUserCart &&
    Array.isArray(currentUserCart) &&
    currentUserCart.length > 0
  ) {
    const userCartItemsCategoryPromises = currentUserCart.map((userCart) =>
      Products.findOne({
        where: {
          id: userCart.menu_id,
        },
        include: [
          {
            model: ProductMenu,
            as: "menus",
            attributes: ["size_category"],
          },
        ],
      })
    );
    const userCartItemsCategories = await Promise.all(
      userCartItemsCategoryPromises
    );

    for (const itemCategory of userCartItemsCategories) {
      const inventoryCategory = itemCategory?.menus?.size_category;

      if (inventoryCategory !== productCategory) {
        validCategory = false;
      }
    }
  }

  return validCategory;
};

const validateProductSeller = async (currentUserCart, product) => {
  if (!currentUserCart || !product) return false;
  let validProductSeller = true;
  const productSeller = product?.seller;

  if (
    currentUserCart &&
    Array.isArray(currentUserCart) &&
    currentUserCart.length > 0
  ) {
    const userCartItemsSellerPromises = currentUserCart.map((userCart) =>
      Products.findOne({
        where: {
          id: userCart.menu_id,
        },
        include: [
          {
            model: ProductMenu,
            as: "menus",
            attributes: ["size_category"],
          },
          {
            model: SellersCompany,
            as: "seller",
            attributes: ["id", "warehouse_id"],
          },
        ],
      })
    );
    const userCartItemsSeller = await Promise.all(userCartItemsSellerPromises);

    for (const itemSeller of userCartItemsSeller) {
      const inventorySeller = itemSeller?.seller;

      if (inventorySeller) {
        if (!inventorySeller.warehouse_id) {
          validProductSeller = inventorySeller.id === productSeller.id;
        } else {
          validProductSeller =
            inventorySeller.warehouse_id === productSeller?.warehouse_id;
        }
        if (!validProductSeller) break;
      }
    }
  }

  return validProductSeller;
};
