const sequelize = require("../../../connection/db");
const {
  sellerProductImageBuilder,
} = require("../../../helpers/image-src-builder");
const {
  createAuditTrail,
} = require("../../../helpers/sellerAuditTrail.service");
const ProductImages = require("../../../models/ProductImages");
const ProductMenu = require("../../../models/ProductMenu");
const Products = require("../../../models/Products");
const ProductVideos = require("../../../models/ProductVideos");

exports.createUpdateSellerProductV2 = async (req, res, next) => {
  const {
    id,
    name,
    sku,
    details,
    price,
    discountedPrice = 0,
    stocks,
    qtyLimit,
    visible,
    categoryId,
    removedProductImagesId = [],
    removedProductVideosId = [],
    variants = [],
  } = req.body;

  const productImages = req.files["productImages[]"];
  const productVideos = req.files["productVideos[]"];
  const isThumbnailFlags = req.body["is_thumbnail"];
  const { seller_id, seller_account_id } = req;

  const t = await sequelize.transaction();

  try {
    const productCategory = await ProductMenu.findOne({
      where: {
        id: categoryId,
        status: true,
      },
      transaction: t,
    });

    if (!productCategory) {
      await t.rollback();
      return res
        .status(200)
        .json({ success: false, message: "Invalid product category." });
    }

    let product;

    if (id) {
      product = await Products.findOne({
        where: { id, seller_id },
        transaction: t,
      });

      if (!product) {
        await t.rollback();
        return res
          .status(200)
          .json({ success: false, message: "Invalid product" });
      }

      product.menu_id = categoryId;
      product.menu = name?.trim();
      product.sku = sku?.trim();
      product.description = details?.trim();
      product.price = price;
      product.discounted_price =
        discountedPrice && discountedPrice !== "" ? discountedPrice : 0;
      product.stocks = stocks;
      product.quantity_limit = qtyLimit;
      product.available = visible;

      for (const productVariant of variants) {
        const {
          id: variantId,
          name: variantName,
          price: variantPrice,
          discountedPrice: variantDiscountedPrice,
          sku: variantSku,
          stocks: variantStocks,
          quantityLimit: variantQtyLimit,
          subVariants = [],
        } = productVariant;

        let itemVariantId = variantId;
        if (
          variantId &&
          variantId !== "" &&
          variantId.includes("placeholder")
        ) {
          const newVariant = await Products.create(
            {
              seller_id,
              parent_id: product.id,
              menu_id: categoryId,
              menu: variantName?.trim(),
              sku: variantSku?.trim(),
              description: "",
              price: variantPrice,
              discounted_price:
                variantDiscountedPrice && variantDiscountedPrice !== ""
                  ? variantDiscountedPrice
                  : 0,
              stocks: variantStocks,
              quantity_limit: variantQtyLimit,
              available: visible,
              status: true,
            },
            { transaction: t }
          );
          itemVariantId = newVariant.id;
        } else {
          const variant = await Products.findOne({
            where: {
              id: variantId,
              parent_id: id,
            },
            transaction: t,
          });

          variant.menu_id = categoryId;
          variant.menu = variantName?.trim();
          variant.sku = variantSku?.trim();
          variant.description = "";
          variant.price = variantPrice;
          variant.discounted_price =
            variantDiscountedPrice && variantDiscountedPrice !== ""
              ? variantDiscountedPrice
              : 0;
          variant.stocks = variantStocks;
          variant.quantity_limit = variantQtyLimit;
          variant.available = visible;
          await variant.save({ transaction: t });
        }

        for (const productSubVariant of subVariants) {
          const {
            id: subVariantId,
            name: subVariantName,
            price: subVariantPrice,
            discountedPrice: subVariantDiscountedPrice,
            sku: subVariantSku,
            stocks: subVariantStocks,
            quantityLimit: subVariantQtyLimit,
          } = productSubVariant;

          if (
            subVariantId &&
            subVariantId !== "" &&
            subVariantId.includes("placeholder")
          ) {
            const newSubVariant = await Products.create(
              {
                seller_id,
                parent_id: itemVariantId,
                menu_id: categoryId,
                menu: subVariantName?.trim(),
                sku: subVariantSku?.trim(),
                description: "",
                price: subVariantPrice,
                discounted_price:
                  subVariantDiscountedPrice && subVariantDiscountedPrice !== ""
                    ? subVariantDiscountedPrice
                    : 0,
                stocks: subVariantStocks,
                quantity_limit: subVariantQtyLimit,
                available: visible,
                status: true,
              },
              { transaction: t }
            );
          } else {
            const sVariant = await Products.findOne({
              where: {
                id: subVariantId,
                parent_id: variantId,
              },
              transaction: t,
            });

            sVariant.menu_id = categoryId;
            sVariant.menu = subVariantName?.trim();
            sVariant.sku = subVariantSku?.trim();
            sVariant.description = "";
            sVariant.price = subVariantPrice;
            sVariant.discounted_price =
              subVariantDiscountedPrice && subVariantDiscountedPrice !== ""
                ? subVariantDiscountedPrice
                : 0;
            sVariant.stocks = subVariantStocks;
            sVariant.quantity_limit = subVariantQtyLimit;
            sVariant.available = visible;
            await sVariant.save({ transaction: t });
          }
        }
      }
      if (
        removedProductImagesId &&
        Array.isArray(removedProductImagesId) &&
        removedProductImagesId.length > 0
      ) {
        await Promise.all(
          removedProductImagesId.map((imageId) =>
            ProductImages.destroy({
              where: {
                product_id: id,
                id: imageId,
              },
              transaction: t,
            })
          )
        );
      }

      if (
        productImages &&
        Array.isArray(productImages) &&
        productImages.length > 0
      ) {
        const hasMain = isThumbnailFlags?.includes("true");

        const productImagesArray = productImages.map(
          ({ filename, path }, i) => ({
            product_id: product.id,
            file_name: filename,
            file_path: path,
            is_thumbnail: isThumbnailFlags[i] === "true",
          })
        );

        if (hasMain) {
          await ProductImages.update(
            { is_thumbnail: false },
            {
              where: { product_id: product.id },
              transaction: t,
            }
          );
        }

        const createdImages = await ProductImages.bulkCreate(
          productImagesArray,
          {
            transaction: t,
          }
        );

        if (createdImages.length > 0) {
          product.seller_dashboard_src = true;
        }
      } else {
        const { mainPhotoId } = req.body;

        await ProductImages.update(
          { is_thumbnail: false },
          {
            where: {
              product_id: product.id,
            },
            transaction: t,
          }
        );

        const p = await ProductImages.findOne({
          where: {
            product_id: product.id,
            id: mainPhotoId,
          },
          transaction: t,
        });

        if (p) {
          p.is_thumbnail = true;
          await p.save({ transaction: t });
        }
      }

      if (removedProductVideosId) {
        await Promise.all(
          removedProductVideosId.map((imageId) =>
            ProductVideos.destroy({
              where: {
                product_id: id,
                id: imageId,
              },
              transaction: t,
            })
          )
        );
      }
      if (
        productVideos &&
        Array.isArray(productVideos) &&
        productVideos.length > 0
      ) {
        const productVideosArray = productVideos.map(
          ({ filename, path }, i) => ({
            product_id: product.id,
            file_name: filename,
            file_path: path,
          })
        );

        const createdVideos = await ProductVideos.bulkCreate(
          productVideosArray,
          {
            transaction: t,
          }
        );
        if (createdVideos.length > 0) {
          product.seller_dashboard_src = true;
        }
      }
      await product.save({ transaction: t });
    } else {
      product = await Products.create(
        {
          seller_id,
          menu_id: categoryId,
          menu: name?.trim(),
          sku: sku?.trim(),
          description: details?.trim(),
          price,
          discounted_price:
            discountedPrice && discountedPrice !== "" ? discountedPrice : 0,
          stocks,
          quantity_limit: qtyLimit,
          available: visible,
          status: true,
        },
        { transaction: t }
      );

      for (const productVariant of variants) {
        const {
          name: variantName,
          price: variantPrice,
          discountedPrice: variantDiscountedPrice,
          sku: variantSku,
          stocks: variantStocks,
          quantityLimit: variantQtyLimit,
          subVariants = [],
        } = productVariant;

        const pVariant = await Products.create(
          {
            seller_id,
            parent_id: product.id,
            menu_id: categoryId,
            menu: variantName?.trim(),
            sku: variantSku?.trim(),
            description: "",
            price: variantPrice,
            discounted_price:
              variantDiscountedPrice && variantDiscountedPrice !== ""
                ? variantDiscountedPrice
                : 0,
            stocks: variantStocks,
            quantity_limit: variantQtyLimit,
            available: visible,
            status: true,
          },
          { transaction: t }
        );

        for (const productSubVariant of subVariants) {
          const {
            name: subVariantName,
            price: subVariantPrice,
            discountedPrice: subVariantDiscountedPrice,
            sku: subVariantSku,
            stocks: subVariantStocks,
            quantityLimit: subVariantQtyLimit,
          } = productSubVariant;

          const sVariant = await Products.create(
            {
              seller_id,
              parent_id: pVariant.id,
              menu_id: categoryId,
              menu: subVariantName?.trim(),
              sku: subVariantSku?.trim(),
              description: "",
              price: subVariantPrice,
              discounted_price:
                subVariantDiscountedPrice && subVariantDiscountedPrice !== ""
                  ? subVariantDiscountedPrice
                  : 0,
              stocks: subVariantStocks,
              quantity_limit: subVariantQtyLimit,
              available: visible,
              status: true,
            },
            { transaction: t }
          );
        }
      }

      if (
        productImages &&
        Array.isArray(productImages) &&
        productImages.length > 0
      ) {
        const productImagesArray = productImages.map(
          ({ filename, path }, i) => ({
            product_id: product.id,
            file_name: filename,
            file_path: path,
            is_thumbnail: isThumbnailFlags[i] === "true",
          })
        );

        const createdImages = await ProductImages.bulkCreate(
          productImagesArray,
          { transaction: t }
        );

        if (createdImages.length > 0) {
          await product.save({ transaction: t });
        }
      }

      if (
        productVideos &&
        Array.isArray(productVideos) &&
        productVideos.length > 0
      ) {
        const productVideosArray = productVideos.map(
          ({ filename, path }, i) => ({
            product_id: product.id,
            file_name: filename,
            file_path: path,
          })
        );

        const createdVideos = await ProductVideos.bulkCreate(
          productVideosArray,
          {
            transaction: t,
          }
        );
        if (createdVideos.length > 0) {
          product.seller_dashboard_src = true;
        }
      }
    }

    await t.commit();

    return res.status(200).json({ success: true, productId: product.id });
  } catch (err) {
    await t.rollback();
    next(err);
  }
};

exports.getSellerProductByIdV2 = async (req, res, next) => {
  const { seller_id } = req;
  const { product_id } = req.query;

  try {
    const product = await Products.findOne({
      where: {
        id: product_id,
        seller_id: seller_id,
        product_status: true,
      },
      include: [
        {
          model: ProductImages,
          as: "product_images",
        },
        {
          model: ProductVideos,
          as: "product_videos",
        },
        {
          model: Products,
          as: "children",
          include: [
            {
              model: Products,
              as: "children",
            },
          ],
        },
      ],
    });

    if (!product) {
      return res
        .status(200)
        .json({ success: false, message: "Product not found." });
    }

    const productImages = (product.product_images || []).map((i) => ({
      id: i.id,
      url: sellerProductImageBuilder(i.file_name, product.seller_dashboard_src),
      file_name: i.file_name,
      file_path: i.file_path,
      is_thumbnail: i.is_thumbnail,
    }));

    const productVideos = (product.product_videos || []).map((i) => ({
      id: i.id,
      url: sellerProductImageBuilder(i.file_name, product.seller_dashboard_src),
      file_name: i.file_name,
      file_path: i.file_path,
    }));

    if (productImages.length === 0) {
      productImages.push({
        id: 0,
        url: sellerProductImageBuilder(
          product.photo,
          product.seller_dashboard_src
        ),
        is_thumbnail: false,
        deprecated_image: !product.seller_dashboard_src,
      });
    }

    const buildParentTree = (children) => {
      if (!children || children.length === 0) return [];

      return children.map((child) => ({
        id: child.id,
        name: child.menu,
        price: child.price,
        discountedPrice: child.discounted_price,
        sku: child.sku,
        stocks: child.stocks,
        quantityLimit: child.quantity_limit,
        hasDiscount: child.discounted_price > 0,
        subVariants: buildParentTree(child.children),
      }));
    };

    const productResponse = {
      id: product.id,
      name: product.menu,
      sku: product.sku,
      details: product.description,
      price: product.price,
      discountedPrice: product.discounted_price,
      stocks: product.stocks,
      qtyLimit: product.quantity_limit,
      visible: product.available,
      categoryId: product.menu_id,
      product_images: productImages,
      product_videos: productVideos,
      variants: buildParentTree(product.children),
    };

    res.status(200).json({ success: true, product: productResponse });
  } catch (err) {
    next(err);
  }
};

exports.addOrDeductItemBeginningBalance = async (req, res, next) => {
  try {
    const { action, qty, productId } = req.body;
    const { seller_id, seller_account_id } = req;

    const product = await Products.findOne({
      where: {
        id: productId,
        seller_id: seller_id,
      },
    });

    if (!product)
      return res
        .status(200)
        .json({ success: false, message: "Product not found." });

    const currentStock = parseFloat(product.stocks) || 0;

    let newItemStock = currentStock;
    const originalStock = currentStock;

    if (action === "Add") {
      newItemStock += qty;
    } else {
      newItemStock -= qty;
    }

    product.stocks = newItemStock;

    await product.save();

    await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Products",
      action: "update",
      action_description: `Update stocks for product id: ${productId}, Original Stock: ${originalStock}, New Item Stock: ${newItemStock}`,
    });

    res
      .status(200)
      .json({ success: true, message: "Stock successfully updated." });
  } catch (err) {
    next(err);
  }
};
