const { Op } = require("sequelize");
const Sequelize = require("sequelize");
const OrderForm = require("../../models/OrderForm");
const OrderFormDetails = require("../../models/OrderFormDetails");
const Products = require("../../models/Products");
const ProductVariation = require("../../models/ProductVariation");
const ProductSubVariation = require("../../models/ProductSubVariation");
const {
  customerAttachmentProofBuilder,
  sellerProductImageBuilder,
  sellerReleaseOrderBuilder,
  sellerImageBuilder,
} = require("../../helpers/image-src-builder");
const MultipleDr = require("../../models/MultipleDR");
const {
  isSellerHasFeatureFlag,
  isUserHasPermissionToDoAction,
  SELLER_ORDERS_MODULE,
  generateRandomNumber,
  generateReferenceNumber,
} = require("../../helpers/common");
const { createAuditTrail } = require("../../helpers/sellerAuditTrail.service");
const {
  sellerEnabledPurchaseOrders,
  checkPOItemStock,
} = require("../../services/purchase-order.service");
const ProductImages = require("../../models/ProductImages");
const {
  getUserCartExcludes,
  getProductUserCartExcludes,
} = require("../../helpers/model-excludes-attributes/excludes");
const SellersCompany = require("../../models/SellersCompany");

const statuses = [
  "Pending",
  "Cancelled",
  "Verified",
  "For Preparation",
  "Release Order - Delivery",
  "Release Order - Customer Pickup",
  "For Delivery - Warehouse",
  "Delivered",
  "Received",
  "Denied",
];

exports.getAllOrderForm = async (req, res, next) => {
  try {
    const { seller_ids = [], seller_account_id, parent_company } = req;
    const { orderStatus = "", orderDate = "", keyword = "" } = req.query;
    const { limit, page } = req.pagination;

    let sellerIds = Array.isArray(seller_ids) ? [...seller_ids] : [];

    if (!sellerIds.length && req.seller_id) {
      sellerIds = [req.seller_id];
    }

    sellerIds = sellerIds.filter(
      (id) => id !== null && id !== undefined && id !== ""
    );

    if (parent_company && sellerIds.length > 0) {
      const childCompanies = await SellersCompany.findAll({
        where: {
          parent_company: {
            [Op.in]: sellerIds,
          },
        },
        attributes: ["id"],
        raw: true,
      });

      const childCompanyIds = childCompanies.map((company) => company.id);
      sellerIds = [...new Set([...sellerIds, ...childCompanyIds])];
    }

    if (!sellerIds.length) {
      const counts = {};
      statuses.forEach((status) => {
        counts[status] = 0;
      });

      return res.status(200).json({
        success: true,
        orderForms: [],
        pagination: {
          totalPages: 0,
          currentPage: page,
          hasNextPage: false,
          hasPreviousPage: page > 1,
        },
        statusCount: counts,
      });
    }

    const whereClause = {
      seller_id: {
        [Op.in]: sellerIds,
      },
    };

    if (orderStatus) {
      whereClause.status = orderStatus;
    }

    if (orderDate) {
      const dates = orderDate.split("-");
      if (dates.length === 2) {
        const [startDate, endDate] = dates.map((date) => new Date(date.trim()));
        whereClause.date_created = {
          [Op.between]: [startDate, endDate],
        };
      }
    }

    if (keyword && keyword.trim() !== "") {
      const trimmedKeyword = keyword.trim();
      const searchPattern = {
        [Op.like]: `%${trimmedKeyword}%`,
      };

      const keywordConditions = [
        { status: searchPattern },
        { reference_no: searchPattern },
        { name: searchPattern },
        { address: searchPattern },
        { contact_number: searchPattern },
        { payment_method: searchPattern },
        { shipping_type: searchPattern },
      ];

      if (parent_company) {
        keywordConditions.push(
          { "$sellers_company_details.company_name$": searchPattern },
          { "$sellers_company_details.shop_name$": searchPattern }
        );
      }

      whereClause[Op.or] = keywordConditions;
    }

    const offset = (page - 1) * limit;

    const includeClause = [
      {
        model: SellersCompany,
        as: "sellers_company_details",
        attributes: ["id", "company_name", "shop_name"],
      },
    ];

    const orders = await OrderForm.findAll({
      where: whereClause,
      limit,
      offset,
      order: [["date_created", "DESC"]],
      include: includeClause,
      distinct: true,
      subQuery: false,
    });

    const orderForms = orders.map(
      ({
        id,
        email,
        name,
        customer_id,
        contact_number,
        reference_no,
        note,
        total_amount,
        proof_of_payment,
        status,
        total_qty,
        address,
        longitude,
        latitude,
        payment_method,
        date_created,
        delivery_fee,
        shipping_type,
        release_order_image,
        release_order_image_new_src,
        dateTime_verified,
        dateTime_for_preparation,
        dateTime_ready_pickup,
        dateTime_for_delivery,
        is_v2_order,
        sellers_company_details,
      }) => ({
        id,
        customer: {
          id: customer_id,
          name,
          email,
          contact_number,
          delivery_address: {
            address,
            longitude,
            latitude,
          },
          remarks: proof_of_payment,
        },
        reference_no,
        bank_proof_attachment:
          note !== ""
            ? customerAttachmentProofBuilder(note, is_v2_order)
            : null,
        release_order_image:
          release_order_image !== null
            ? sellerReleaseOrderBuilder(
                release_order_image,
                release_order_image_new_src
              )
            : null,
        total_amount,
        date_created,
        total_order_qty: total_qty,
        delivery_fee,
        shipping_type,
        payment_method,
        timestamp: {
          verified: dateTime_verified,
          for_preparation: dateTime_for_preparation,
          ready_pickup: dateTime_ready_pickup,
          for_delivery: dateTime_for_delivery,
        },
        seller: sellers_company_details
          ? {
              id: sellers_company_details.id,
              company_name: sellers_company_details.company_name,
              shop_name: sellers_company_details.shop_name,
            }
          : null,
        order_status: status,
      })
    );

    const orderFormCounts = await OrderForm.findAll({
      attributes: [
        "status",
        [Sequelize.fn("COUNT", Sequelize.col("status")), "count"],
      ],
      where: {
        seller_id: {
          [Op.in]: sellerIds,
        },
        status: {
          [Op.in]: statuses,
        },
      },
      group: ["status"],
    });

    const counts = {};
    statuses.forEach((status) => {
      counts[status] = 0;
    });
    orderFormCounts.forEach((row) => {
      counts[row.status] = Number(row.get("count"));
    });

    const orderFormCount = await OrderForm.count({
      where: whereClause,
      include: [
        {
          model: SellersCompany,
          as: "sellers_company_details",
          attributes: [],
        },
      ],
      distinct: true,
      col: "id",
    });

    await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: sellerIds[0] || null,
      module: "Orders",
      action: "view - Orders",
      action_description: ``,
    });

    const totalPages = Math.ceil(orderFormCount / limit);
    const hasNextPage = page < totalPages;
    const hasPreviousPage = page > 1;

    res.status(200).json({
      success: true,
      orderForms,
      pagination: {
        totalPages,
        currentPage: page,
        hasNextPage,
        hasPreviousPage,
      },
      statusCount: counts,
    });
  } catch (err) {
    next(err);
  }
};

exports.getOrderFormByIdWithOrderDetails = async (req, res, next) => {
  const { seller_id, seller_account_id, parent_company } = req;
  const { reference_no } = req.params;

  const sellerIds = [seller_id];
  if (parent_company) {
    const childCompanies = await SellersCompany.findAll({
      where: {
        parent_company: seller_id,
      },
      attributes: ["id"],
    });
    childCompanies.forEach((company) => sellerIds.push(company.id));
  }

  OrderForm.findOne({
    where: {
      seller_id: {
        [Op.in]: sellerIds,
      },
      reference_no,
    },
    include: [
      {
        model: OrderFormDetails,
        as: "order_form_details",
        include: [
          {
            model: Products,
            as: "product",
            include: [
              {
                model: ProductVariation,
                as: "product_variations",
                attributes: {
                  exclude: ["product_id"],
                },
                include: [
                  {
                    model: ProductSubVariation,
                    as: "ProductSubVariations",
                    required: false,
                    attributes: {
                      exclude: ["product_variation_id"],
                    },
                  },
                ],
              },
            ],
          },
        ],
      },
      {
        model: MultipleDr,
        as: "delivery_receipts",
        attributes: ["id", "reference_no", "delivered_picture", "date_created"],
      },
      {
        model: SellersCompany,
        as: "sellers_company_details",
        attributes: ["id", "company_name", "shop_name"],
      },
    ],
  })
    .then(async (orderForm) => {
      if (!orderForm)
        return res
          .status(404)
          .json({ success: false, msg: "Order not found." });
      const orderFormDetails = orderForm.order_form_details.map(
        ({
          id,
          quantity,
          discounted_price,
          price,
          amount,
          has_sub_variation_chosen,
          product_id,
          product_variation_id,
          product_sub_variation_id,
          product,
        }) => {
          const orderFormDetailStructure = {
            id,
            quantity,
            discounted_price,
            price,
            total_amount: amount,
            has_sub_variation_chosen:
              has_sub_variation_chosen !== "" ? false : true,
            product_variation_id,
            product_sub_variation_id,
            product_detail: {
              id: product?.id,
              name: product?.menu,
              description: product?.description,
              price: product?.price,
              discounted_price: product?.discounted_price,
              photo:
                product?.photo !== null
                  ? sellerProductImageBuilder(
                      product.photo,
                      product.seller_dashboard_src,
                    )
                  : null,
              qty_limit: product?.quantity_limit,
              stocks: product?.stocks,
              available: product?.available,
              product_variation_id: product?.product_variation_id,
              product_sub_variation_id: product?.product_sub_variation_id,
              product_variation_detail: [],
            },
          };

          const productVariationDetail = product.product_variations.map(
            (productVariation) => ({
              id: productVariation.id,
              variation: productVariation.variation,
              description: productVariation.description,
              qty_limit: productVariation.quantity_limit,
              discounted_price: productVariation.discounted_price,
              has_sub_variation: productVariation.hasSubVariation,
              isAvailable: productVariation.isAvailable,
              image:
                productVariation.variationImage !== ""
                  ? sellerProductImageBuilder(
                      productVariation.variationImage,
                      true,
                    )
                  : null,
              stocks: productVariation.stocks,
              sku: productVariation.sku,
              product_sub_variation_detail:
                productVariation.ProductSubVariations,
            }),
          );

          orderFormDetailStructure.product_detail.product_variation_detail =
            productVariationDetail;

          return orderFormDetailStructure;
        },
      );

      let deliveryReceipts = [];
      for (const deliveryReceipt of orderForm.delivery_receipts) {
        deliveryReceipts.push({
          id: deliveryReceipt.id,
          delivered_picture:
            orderForm.shipping_type === "Pick-up"
              ? `https://buildhub.ph/uploads/${deliveryReceipt.delivered_picture}`
              : `https://buildhub.ph/img/delivery/${deliveryReceipt.delivered_picture}`,
        });
      }
      const response = {
        id: orderForm.id,
        reference_no: orderForm.reference_no,
        agent: {
          code: orderForm.agentCode,
        },
        date_created: orderForm.date_created,
        pickup_date: orderForm.pickup_date,
        delivered_date: orderForm.date_delivered,
        shipping_type: orderForm.shipping_type,
        order_status: orderForm.status,
        customer: {
          id: orderForm.customer_id,
          name: orderForm.name,
          email: orderForm.email,
          contact_number: orderForm.contact_number,
          delivery_address: {
            address: orderForm.address,
            longitude: orderForm.longitude,
            latitude: orderForm.latitude,
          },
        },
        billing: {
          payment_method: orderForm.payment_method,
          delivery_fee: orderForm.delivery_fee,
          total_amount: orderForm.total_amount,
        },
        seller: {
          id: orderForm.sellers_company_details.id,
          company_name: orderForm.sellers_company_details.company_name,
          shop_name: orderForm.sellers_company_details.shop_name,
        },
        order_instruction: orderForm.proof_of_payment,
        orderFormDetails,
        delivery_receipts: deliveryReceipts,
      };

      const trail = await createAuditTrail({
        seller_id: seller_account_id,
        seller_company_id: seller_id,
        module: "Orders",
        action: "view - Detailed Order",
        action_description: `View Detailed Order ID: ${reference_no}`,
      });
      res.status(200).json({ success: true, order_detail: response });
    })
    .catch((err) => {
      next(err);
    });
};

exports.updateOrderForm = async (req, res, next) => {
  const { seller_id, seller_account_id, parent_company } = req;
  const { release_order_image } = req.files;
  const { reference_no } = req.params;
  const { data } = req.body;

  const { status: updatedStatus } = data;
  let roFileName;
  if (release_order_image) roFileName = release_order_image[0].filename;

  if (!statuses.includes(updatedStatus))
    return res.status(404).json({ success: false, msg: "Invalid status" });

  let isPreparation = false,
    roDelivery = false,
    roCustomerPickup = false;
  switch (updatedStatus) {
    case "For Preparation":
      isPreparation = true;
      break;
    case "Release Order - Delivery":
      roDelivery = true;
      break;
    case "Release Order - Customer Pickup":
      roCustomerPickup = true;
      break;
  }

  const sellerIds = [seller_id];
  if (parent_company) {
    const childCompanies = await SellersCompany.findAll({
      where: {
        parent_company: seller_id,
      },
      attributes: ["id"],
    });
    childCompanies.forEach((company) => sellerIds.push(company.id));
  }

  OrderForm.findOne({
    where: {
      reference_no,
      seller_id: {
        [Op.in]: sellerIds,
      },
    },
    include: [
      {
        model: SellersCompany,
        as: "sellers_company_details",
        attributes: ["id", "company_name", "shop_name"],
      },
    ],
  })
    .then((orderForm) => {
      if (!orderForm)
        return res
          .status(404)
          .json({ success: false, msg: "Order not found." });

      const dateNow = new Date();

      orderForm.status = updatedStatus;
      orderForm.release_order_image = roFileName;
      orderForm.release_order_image_new_src = true;

      isPreparation ? (orderForm.dateTime_for_preparation = new Date()) : null;
      roCustomerPickup ? (orderForm.dateTime_ready_pickup = new Date()) : null;
      return orderForm.save();
    })
    .then(async () => {
      const trail = await createAuditTrail({
        seller_id: seller_account_id,
        seller_company_id: seller_id,
        module: "Orders",
        action: "update - Order",
        action_description: `Update Detailed Order ID: ${reference_no}, status: ${updatedStatus}`,
      });

      res
        .status(200)
        .json({ success: true, msg: "Record updated successfully." });
    })
    .catch((err) => {
      next(err);
    });
};

exports.dashboardOrderData = async (req, res, next) => {
  const { seller_id, parent_company } = req;

  try {
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    const endOfToday = new Date();
    endOfToday.setDate(today.getDate() + 1);

    const upcomingDate = new Date();
    upcomingDate.setDate(endOfToday.getDate() + 2);

    const responseData = {
      ordersCount: [],
      today_orders: [],
      upcoming_orders: [],
    };

    const sellerIds = [seller_id];
    if (parent_company) {
      const childCompanies = await SellersCompany.findAll({
        where: {
          parent_company: seller_id,
        },
        attributes: ["id"],
      });
      childCompanies.forEach((company) => sellerIds.push(company.id));
    }

    const orderFormsPromise = OrderForm.findAll({
      attributes: [
        "status",
        [Sequelize.fn("COUNT", Sequelize.col("status")), "count"],
      ],
      where: {
        seller_id: {
          [Op.in]: sellerIds,
        },
        status: {
          [Op.in]: statuses,
        },
      },
      group: ["status"],
    });

    const orderFormsTodayPromise = OrderForm.findAll({
      where: {
        seller_id: {
          [Op.in]: sellerIds,
        },
        status: {
          [Op.in]: statuses,
        },
        pickup_date: {
          [Op.between]: [today, endOfToday],
        },
      },
      attributes: ["id", "reference_no", "name", "pickup_date"],
      order: [["id", "ASC"]],
    });

    const orderFormsUpcomingPromise = OrderForm.findAll({
      where: {
        seller_id: {
          [Op.in]: sellerIds,
        },
        status: {
          [Op.in]: statuses,
        },
        pickup_date: {
          [Op.between]: [endOfToday, upcomingDate],
        },
      },
      attributes: ["id", "reference_no", "name", "pickup_date"],
      order: [["id", "ASC"]],
    });

    const [orderForms, orderFormsToday, orderFormsUpcoming] = await Promise.all(
      [orderFormsPromise, orderFormsTodayPromise, orderFormsUpcomingPromise],
    );

    responseData.ordersCount = orderForms;
    responseData.today_orders = orderFormsToday;
    responseData.upcoming_orders = orderFormsUpcoming;

    const currentYear = new Date().getFullYear();
    const lastYear = currentYear - 1;

    const salesReportCurrentYearPromise = getYearlySalesReport(
      sellerIds,
      currentYear,
    );
    const salesReportPreviousYearPromise = getYearlySalesReport(
      sellerIds,
      lastYear,
    );

    const [salesReportCurrent, salesReportPrevious] = await Promise.all([
      salesReportCurrentYearPromise,
      salesReportPreviousYearPromise,
    ]);

    res.status(200).json({
      success: true,
      data: responseData,
      sales_report_current_year: salesReportCurrent,
      sales_report_previous_year: salesReportPrevious,
    });
  } catch (err) {
    next(err);
  }
};

const getYearlySalesReport = async (sellerIds, year) => {
  try {
    const startOfYear = new Date(year, 0, 1);
    const endOfYear = new Date(year, 11, 31, 23, 59, 59);

    const salesReport = await OrderForm.findAll({
      where: {
        seller_id: {
          [Op.in]: sellerIds,
        },
        date_created: {
          [Op.between]: [startOfYear, endOfYear],
        },
      },
      attributes: [
        [Sequelize.fn("MONTH", Sequelize.col("date_created")), "month"],
        [Sequelize.fn("SUM", Sequelize.col("total_amount")), "total_sales"],
        [Sequelize.fn("COUNT", Sequelize.col("id")), "total_orders"],
      ],
      group: [Sequelize.fn("MONTH", Sequelize.col("date_created"))],
      order: [[Sequelize.fn("MONTH", Sequelize.col("date_created")), "ASC"]],
      raw: true,
    });

    return salesReport;
  } catch (error) {
    console.error("Error fetching yearly sales report:", error);
    throw error;
  }
};

exports.qrScanOrder = async (req, res, next) => {
  try {
    const { seller_id, seller_account_id, parent_company } = req;
    const { qrOrders } = req.body;

    const validProducts = [];
    const errors = [];

    const sellerIds = [seller_id];
    if (parent_company) {
      const childCompanies = await SellersCompany.findAll({
        where: {
          parent_company: seller_id,
        },
        attributes: ["id"],
      });
      childCompanies.forEach((company) => sellerIds.push(company.id));
    }

    if (qrOrders && Array.isArray(qrOrders)) {
      const sellerEnabledPo = await sellerEnabledPurchaseOrders(seller_id);

      for (const qrOrder of qrOrders) {
        const { productId, quantity } = qrOrder;

        const product = await Products.findOne({
          where: {
            id: productId,
            seller_id: {
              [Op.in]: sellerIds,
            },
            product_status: true,
          },
        });

        if (!product) {
          errors.push(`Product ID ${productId} not found or unavailable.`);
          continue;
        }

        let itemStock = product.stocks;
        if (sellerEnabledPo) {
          itemStock = await checkPOItemStock(product.id);
        }

        if (quantity > itemStock) {
          errors.push(`Insufficient stock for Product ID ${productId}.`);
          continue;
        }

        const discountedPrice = parseFloat(product.discounted_price);
        const regularPrice = parseFloat(product.price);
        const itemPrice = discountedPrice ? discountedPrice : regularPrice;

        validProducts.push({
          productId: product.id,
          quantity,
          price: itemPrice,
          total_amount: itemPrice * parseFloat(quantity),
        });
      }

      if (errors.length > 0) {
        return res.status(200).json({ success: false, errors });
      }

      const generatedNum = generateRandomNumber();
      const generatedGuestID = `GUEST-${generatedNum}`;
      const referenceNo = await generateReferenceNumber();

      const qrCreatedOrderForm = await OrderForm.create({
        customer_id: generatedNum,
        email: "",
        name: generatedGuestID,
        contact_number: "",
        address: "",
        longitude: 0,
        latitude: 0,
        shipping_type: "QR Scan Order",
        payment_method: "QR Scan Order",
        status: "QR Scan Order",
        seller_id: seller_id,
        reference_no: referenceNo,
        is_v2_order: true,
      });

      const qrCreateOrderFormDetails = await Promise.all(
        validProducts.map((item) =>
          OrderFormDetails.create({
            order_form_id: qrCreatedOrderForm.id,
            product_id: item.productId,
            quantity: item.quantity,
            price: item.price,
            amount: item.total_amount,
            po_tracked: sellerEnabledPo ? true : false,
          }),
        ),
      );

      const orderForm = await OrderForm.findOne({
        where: {
          id: qrCreatedOrderForm.id,
        },
        include: [
          {
            model: OrderFormDetails,
            as: "order_form_details",
            include: [
              {
                model: Products,
                as: "product",
                attributes: [
                  "id",
                  "menu",
                  "description",
                  "photo",
                  "price",
                  "seller_dashboard_src",
                ],
                attributes: {
                  exclude: getProductUserCartExcludes(),
                },
                include: [
                  {
                    model: ProductImages,
                    as: "product_images",
                  },
                ],
              },
            ],
          },
          {
            model: SellersCompany,
            as: "sellers_company_details",
          },
        ],
        attributes: {
          exclude: getUserCartExcludes(),
        },
      });

      const modifiedOrderForm = {
        id: orderForm.id,
        reference_no: orderForm.reference_no,
        name: generatedGuestID,
        order_type: orderForm.payment_method,
        details: [],
        seller: {
          id: orderForm.sellers_company_details.id,
          company_name: orderForm.sellers_company_details.company_name,
          logo: sellerImageBuilder(
            orderForm.sellers_company_details.seller_logo,
            orderForm.sellers_company_details.seller_dashboard_src,
          ),
        },
      };

      for (const detail of orderForm.order_form_details) {
        modifiedOrderForm.details.push({
          id: detail.id,
          quantity: detail.quantity,
          price: detail.price,
          total_amount: detail.amount,
          product: {
            id: detail.product.id,
            menu: detail.product.menu,
            image: detail.product.photo
              ? sellerProductImageBuilder(
                  detail.product.photo,
                  detail.product.seller_dashboard_src,
                )
              : null,
            stock: sellerEnabledPo
              ? (await checkPOItemStock(detail.product.id)).availableStock
              : detail.product.stocks,
          },
        });
      }
      return res.status(201).json({
        success: true,
        message: "QR order created successfully",
        order: modifiedOrderForm,
      });
    }

    return res
      .status(400)
      .json({ success: false, message: "Invalid QR orders data" });
  } catch (err) {
    next(err);
  }
};
