const OrderForm = require("../models/OrderForm");
const OrderFormDetails = require("../models/OrderFormDetails");
const Customers = require("../models/Customers");
const Products = require("../models/Products");
const ProductVariation = require("../models/ProductVariation");
const ProductSubVariation = require("../models/ProductSubVariation");
const SellersCompany = require("../models/SellersCompany");
const UserCart = require("../models/UserCart");
const { getBuildCreditBalance } = require("./buildcredit");
const Vouchers = require("../models/Vouchers");
const { shippingService, lalamoveBooking } = require("./shipping.service");
const SplitPayments = require("../models/SplitPayments");
const emailBuilder = require("./transporter");
const { orderPlacedTemplate } = require("./email-templates/html-bodys-new");
const smsTemplates = require("./sms-no-templates/sms-no-templates");
const {
  filterAndFormatPhones,
  formatDate12Hour,
  generateReferenceNumber,
  SELLER_EXPEDITE_ORDERS,
} = require("./common");
const whispir = require("./whispir");
const {
  customerAttachmentProofBuilder,
  sellerProductImageBuilder,
} = require("./image-src-builder");
const { Op, Sequelize } = require("sequelize");
const { getHardwareCreditCheckout } = require("./hardwarecredit");
const { voucherService } = require("./voucher.service");
const {
  suggestedVoucherHelper,
} = require("../controllers/v3/suggested-voucher.controller");
const sequelizeConnect = require("../connection/db");
const SellerFeatureFlags = require("../models/SellerFeatureFlags");
const SellerControlFeatureFlags = require("../models/SellerControlFeatureFlags");
const YieldClient = require("./withyield");
const PaymentMethods = require("../models/PaymentMethods");
const { dispatchOrderNotification } = require("./seller-notifcation.service");
const ProductImages = require("../models/ProductImages");
const {
  sellerEnabledPurchaseOrders,
  checkPOItemStock,
} = require("../services/purchase-order.service");

exports.checkoutService = async (customer_id, dataObj, req) => {
  try {
    const {
      shipping_type,
      payment_method,
      buildcredit_payment,
      bank_payment,
      voucher_code,
      pickup_date,
      order_instructions,
      agent_code,
      transportify_shipping_fee,
      lalamove_shipping_fee,
      lalamove_quotation_id,
      lalamove_customer_stop_id,
      lalamove_seller_stop_id,
      checkoutAddress,
      checkoutLatitude,
      checkoutLongitude,
      bank_transfer_attachment = "",
      suggested_voucher_id,
      poAttachmentFileName,
    } = dataObj;

    // Variables
    const validShippingTypes = [
      "Standard Shipping",
      "Pick-up",
      "Transportify",
      "Lalamove",
      "Hardware Shipping",
    ];
    const validPaymentMethods = [
      "RPAF",
      "Build Credit",
      "Bank Transfer",
      "Bank Cheque",
      "Split",
      "Hardware Credit",
      "Credit Card",
      "Online Payment",
      "Yield",
      "QR PH",
    ];
    let buildCreditDetail = null;
    let hardwareCreditDetail = null;
    let yieldCreditDetail = null;

    let checkoutDifferentAddress = false;

    let splitPaymentRecordId = null;
    if (
      checkoutAddress &&
      checkoutAddress !== null &&
      checkoutAddress !== "" &&
      checkoutLatitude &&
      checkoutLatitude !== null &&
      checkoutLatitude !== "0" &&
      checkoutLongitude &&
      checkoutLongitude !== null &&
      checkoutLongitude !== "0"
    ) {
      checkoutDifferentAddress = true;
    }

    const customerPromise = Customers.findByPk(customer_id);
    const userCartPromise = UserCart.findAll({
      where: {
        user_id: customer_id,
      },
      include: [
        {
          model: Products,
          as: "product",
          include: [
            {
              model: SellersCompany,
              as: "seller",
            },
            {
              model: ProductVariation,
              as: "product_variations",
              include: [
                {
                  model: ProductSubVariation,
                  as: "ProductSubVariations",
                },
              ],
            },
          ],
        },
      ],
    });

    const [customer, userCart] = await Promise.all([
      customerPromise,
      userCartPromise,
    ]);

    // Validations
    if (
      !customer ||
      !userCart ||
      !(Array.isArray(userCart) && userCart.length > 0)
    ) {
      return { error: "Undefined customer or user cart do not exist." };
    }
    if (
      !validShippingTypes.includes(shipping_type) ||
      !validPaymentMethods.includes(payment_method)
    ) {
      return { error: "Undefined shipping type or payment method." };
    }

    if (
      payment_method &&
      "RPAF" &&
      payment_method !== "Split" &&
      payment_method !== "Online Payment" &&
      payment_method !== "Bank Cheque" &&
      payment_method !== "Credit Card"
    ) {
      const isValidPaymentMethod = await validatePaymentMethod(payment_method);

      if (!isValidPaymentMethod)
        return { error: "Payment method is either disabled or not available." };
    }

    if (
      payment_method === "Build Credit" ||
      payment_method === "RPAF" ||
      payment_method === "Split"
    ) {
      buildCreditDetail = await getBuildCreditBalance(customer_id);

      if (payment_method === "Split") {
        if (
          !buildcredit_payment ||
          buildcredit_payment === "" ||
          !bank_payment ||
          bank_payment === ""
        ) {
          return {
            error:
              "buildcredit_payment or bank_payment is either empty or not defined.",
          };
        }
      }
    }

    if (payment_method === "Hardware Credit") {
      hardwareCreditDetail = await getHardwareCreditCheckout(customer_id);
    }

    if (payment_method === "Yield") {
      yieldCreditDetail = await getYieldAvailableCredit(req, customer_id, {
        yieldCode: customer.yield_code,
      });

      if (yieldCreditDetail && yieldCreditDetail.error) {
        return {
          error:
            "Yield is experiencing technical difficulties at the moment. Please try again later.",
        };
      }
    }

    if (
      payment_method === "Bank Transfer" ||
      payment_method === "Split" ||
      payment_method === "QR PH"
    ) {
      if (!bank_transfer_attachment || bank_transfer_attachment === "") {
        return {
          error: "Bank Transfer attachment is either empty or not defined.",
        };
      }
    }
    const todayDate = new Date().toISOString().split("T")[0];
    if (pickup_date === todayDate) {
      return { error: "Cannot set pickup date today's date." };
    }

    let orderStatus = "Verified";
    if (payment_method === "Online Payment" || payment_method === "Yield")
      orderStatus = "To Pay";
    if (
      payment_method === "Bank Transfer" ||
      payment_method === "Split" ||
      payment_method === "QR PH"
    )
      orderStatus = "Pending";

    const sellers = userCart
      .map((cartItem) => cartItem.product?.seller?.id)
      .filter(Boolean);
    const sellerIds = new Set(sellers);

    const orderReferenceNos = [];
    if (sellerIds && sellerIds.size > 0) {
      for (const seller of sellerIds) {
        let voucherDetail = null;
        let isVoucherInPercent = false;
        let voucherAmount = 0;
        let suggestedVoucherIdUsed = null;

        const filteredCart = userCart.filter(
          (cart) => cart.product.seller.id === seller
        );

        const referenceNoPromise = generateReferenceNumber();
        const paynamicsReferenceNoPromise = generateReferenceNumber(true);

        // SELLER_EXPEDITE_ORDERS
        const sellerFeaturesFlagPromise = SellerFeatureFlags.findOne({
          where: {
            name: SELLER_EXPEDITE_ORDERS,
            status: true,
          },
        });
        // SELLER_EXPEDITE_ORDERS
        const [reference_no, sellerFeaturesFlag, paynamicsReferenceNo] =
          await Promise.all([
            referenceNoPromise,
            sellerFeaturesFlagPromise,
            paynamicsReferenceNoPromise,
          ]);

        // SELLER_EXPEDITE_ORDERS
        if (sellerFeaturesFlag) {
          const sellerControlFlag = await SellerControlFeatureFlags.findOne({
            where: {
              feature_flag_id: sellerFeaturesFlag.id,
              seller_company_id: seller,
              enabled: true,
              status: true,
            },
          });

          if (sellerControlFlag && payment_method === "Build Credit") {
            if (shipping_type === "Pick-up") {
              // Pickup Orders
              orderStatus = "Release Order - Customer Pickup";
            } else {
              // For Delivery Orders
              orderStatus = "Release Order - Delivery";
            }
          }
        }
        // SELLER_EXPEDITE_ORDERS

        // SELLER PURCHASE ORDER
        const enabledSellerPO = await sellerEnabledPurchaseOrders(seller);

        const orderForm = await OrderForm.create({
          customer_id: customer.id,
          email: customer.email,
          name: `${customer.first_name} ${customer.last_name}`,
          contact_number: customer.phone,
          address: checkoutDifferentAddress
            ? checkoutAddress
            : customer.address,
          longitude: checkoutDifferentAddress
            ? checkoutLongitude
            : customer.longitude,
          latitude: checkoutDifferentAddress
            ? checkoutLatitude
            : customer.latitude,
          agentCode: agent_code || null,
          shipping_type,
          pickup_date,
          payment_method,
          proof_of_payment: order_instructions,
          po_attachment: poAttachmentFileName,
          note:
            payment_method === "Bank Transfer" || payment_method === "Split"
              ? bank_transfer_attachment
              : null,
          status: orderStatus,
          voucher_id_used: null,
          seller_id: seller,
          reference_no: reference_no,
          paynamics_reference_no: paynamicsReferenceNo,
          is_v2_order: true,
        });

        const orderFormDetails = [];
        const productUpdateDetails = [];

        let subTotal = 0;
        let grandQuantity = 0;
        let grandTotal = 0;

        for (const cart of filteredCart) {
          const {
            menu_id: product_id,
            quantity,
            price,
            has_sub_variation_chosen,
            product_variation_id,
            product_sub_variation_id,
          } = cart;

          grandQuantity += parseFloat(quantity);

          let productId = product_id;
          let productVariationId = null;
          let productSubVariationId = null;
          let productPromise = Products.findByPk(productId);
          if (has_sub_variation_chosen === "true") {
            if (product_variation_id && !product_sub_variation_id) {
              productId = product_variation_id;
              productVariationId = product_variation_id;
              productPromise = ProductVariation.findByPk(productId);
            }
            if (product_variation_id && product_sub_variation_id) {
              productId = product_sub_variation_id;
              productSubVariationId = product_sub_variation_id;
              productPromise = ProductSubVariation.findByPk(productId);
            }
          }

          const [product] = await Promise.all([productPromise]);

          let itemStocks = parseFloat(product.stocks);
          let validItemStocks = true;
          if (enabledSellerPO) {
            const poItemStock = await checkPOItemStock(product.id);
            if (poItemStock) {
              itemStocks = poItemStock.availableStock;
            }
          }

          if (itemStocks < parseFloat(quantity)) {
            validItemStocks = false;
            await orderForm.destroy();
            return {
              itemStockError: true,
              error: `Insufficient stock for ${product.menu}. Available stock is ${itemStocks}.`,
            };
          }

          if (!enabledSellerPO && validItemStocks) {
            productUpdateDetails.push(
              product.update({ stocks: product.stocks - quantity })
            );
          }

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

          let itemPrice = discountedPrice ? discountedPrice : regularPrice;

          const itemTotal = parseFloat(itemPrice) * parseFloat(quantity);
          subTotal += parseFloat(itemTotal);

          const orderFormDetail = OrderFormDetails.create({
            order_form_id: orderForm.id,
            product_id: productId,
            quantity,
            discounted_price: itemPrice,
            price: discountedPrice ? discountedPrice : regularPrice,
            amount: itemTotal,
            has_sub_variation_chosen,
            product_variation_id: productVariationId,
            product_sub_variation_id: productSubVariationId,
            reference_no: reference_no,
            po_tracked: enabledSellerPO,
          });

          orderFormDetails.push(orderFormDetail);
        }
        await Promise.all([orderFormDetails, productUpdateDetails]);

        // Get Delivery Fee for this Order
        const finalCustomerLatitude = checkoutDifferentAddress
          ? checkoutLatitude
          : customer.latitude;
        const finalCustomerLongitude = checkoutDifferentAddress
          ? checkoutLongitude
          : customer.longitude;
        let _shippingService = null;

        if (shipping_type !== "Pick-up") {
          _shippingService = await shippingService(customer_id, {
            latitude: finalCustomerLatitude,
            longitude: finalCustomerLongitude,
          });
        }

        let shippingFee = 0;
        let shippingDistance = 0;
        if (_shippingService && _shippingService.error) {
          return { error: _shippingService.error };
        }
        if (shipping_type === "Standard Shipping" && _shippingService) {
          shippingFee =
            parseFloat(_shippingService.standard_shipping_fee.fee) /
            parseFloat(sellerIds.size);
          shippingDistance = parseFloat(
            _shippingService.standard_shipping_fee.total_distance_to_seller
          );
        }
        if (shipping_type === "Hardware Shipping" && _shippingService) {
          shippingFee = parseFloat(_shippingService.hardware_shipping.fee);
          shippingDistance = parseFloat(
            _shippingService.hardware_shipping.total_distance_to_seller
          );
        }

        // Lalamove & Transportify
        if (shipping_type === "Lalamove") {
          if (!lalamove_shipping_fee) {
            await orderForm.destroy();
            return {
              error: "Lalamove shipping fee is either undefined or missing.",
            };
          }
          shippingFee = parseFloat(lalamove_shipping_fee) || 0;
        }
        if (shipping_type === "Transportify") {
          if (!transportify_shipping_fee) {
            await orderForm.destroy();
            return {
              error:
                "Transportify shipping fee is either undefined or missing.",
            };
          }
          shippingFee = parseFloat(transportify_shipping_fee) || 0;
        }

        // Get Voucher Amount
        let totalVoucherAmount = 0;

        // subTotal += parseFloat(Math.round(shippingFee));

        // VOUCHER
        if (voucher_code && suggested_voucher_id) {
          await orderForm.destroy();
          return {
            error:
              "Sorry, you can only have one voucher applied. Remove applied voucher or suggested voucher to continue.",
          };
        }
        if (voucher_code && voucher_code !== "") {
          voucherDetail = await voucherService(
            voucher_code,
            seller,
            null,
            subTotal
          );
        }

        if (voucherDetail) {
          if (voucherDetail.in_percent === "Yes") {
            voucherAmount = voucherDetail.amount_in_percent;
            isVoucherInPercent = true;
          } else {
            voucherAmount = voucherDetail.amount;
          }
        }

        if (suggested_voucher_id) {
          const suggestedVoucher = await suggestedVoucherHelper(
            { customerId: customer_id },
            suggested_voucher_id
          );

          if (suggestedVoucher) {
            const {
              success: suggestedVoucherSuccess,
              voucherAmount: suggestedVoucherAmount,
            } = suggestedVoucher;

            if (!suggestedVoucherSuccess) {
              await orderForm.destroy();
              return {
                error:
                  "There's a problem with your suggested voucher. Either you don't meet the spending requirement or the voucher is not valid.",
              };
            }

            voucherApplied = true;
            voucherAmount = suggestedVoucherAmount;
            suggestedVoucherIdUsed = suggested_voucher_id;
          }
        }
        // VOUCHER
        voucherAmount = parseFloat(voucherAmount) / parseFloat(sellerIds.size);
        if (isVoucherInPercent) {
          totalVoucherAmount = parseFloat(subTotal) * parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        } else {
          totalVoucherAmount = parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        }

        grandTotal += parseFloat(Math.round(shippingFee));

        // Check for Build Credit Balance is greater than order total amount.
        if (
          payment_method === "Split" ||
          payment_method === "Build Credit" ||
          payment_method === "RPAF"
        ) {
          if (!buildCreditDetail) {
            await orderForm.destroy();
            return { error: "Build Credit Balance insufficient." };
          }

          if (payment_method === "Split") {
            if (
              parseFloat(buildcredit_payment) > buildCreditDetail.current_bal
            ) {
              await orderForm.destroy();
              return { error: "Build Credit Balance insufficient." };
            } else {
              const splitPaymentRecord = await SplitPayments.create({
                customer_id,
                rpaf_payment: buildcredit_payment,
                bank_payment: bank_payment,
              });
              splitPaymentRecordId = splitPaymentRecord.id;
            }
          } else {
            if (grandTotal > buildCreditDetail.current_bal) {
              await orderForm.destroy();
              return { error: "Build Credit Balance insufficient." };
            }
          }
        }

        if (payment_method === "Hardware Credit") {
          if (hardwareCreditDetail && hardwareCreditDetail.status) {
            const hardwareCreditBalance = parseFloat(
              hardwareCreditDetail.current_bal
            );
            if (grandTotal > hardwareCreditBalance) {
              await orderForm.destroy();
              return { error: "Hardware Credit Balance insufficient." };
            }
          } else {
            await orderForm.destroy();
            return { error: "Hardware Credit Balance insufficient." };
          }
        }

        if (payment_method === "Yield") {
          if (yieldCreditDetail && yieldCreditDetail.status) {
            const yieldCreditBalance = parseFloat(
              yieldCreditDetail.current_balance
            );
            if (grandTotal > yieldCreditBalance) {
              await orderForm.destroy();
              return { error: "Yield Credit Balance insufficient." };
            }
          } else {
            await orderForm.destroy();
            return { error: "Yield Credit Balance insufficient." };
          }
        }

        if (payment_method === "Yield") {
          const yieldOrder = await req.yieldClient.createOrder({
            customerID: yieldCreditDetail.id,
            totalAmount: {
              currencyCode: "PHP",
              value: grandTotal,
            },
            note: `Buildhub Order Reference No: ${reference_no}`,
          });

          if (yieldOrder && yieldOrder.status === "PENDING") {
            const { id, orderNumber, paymentLink } = yieldOrder;

            orderForm.third_party_payment_id = id;
            orderForm.third_party_payment_order_id = orderNumber;
            orderForm.third_party_payment_payment_link = paymentLink;
          }
        }

        // Update Order Form
        orderForm.delivery_fee = Math.round(shippingFee);
        orderForm.subtotal_amount = parseFloat(subTotal);
        orderForm.total_amount = parseFloat(grandTotal);
        orderForm.total_qty = parseFloat(grandQuantity);
        orderForm.split_payment_id = splitPaymentRecordId;
        orderForm.total_distance =
          shipping_type === "Standard Shipping" ? shippingDistance : null;
        orderForm.voucher_amount = parseFloat(totalVoucherAmount);
        orderForm.voucher_id_used = voucherDetail ? voucherDetail.id : null;
        orderForm.suggested_voucher_id_used = suggestedVoucherIdUsed
          ? suggestedVoucherIdUsed
          : null;

        if (shipping_type === "Lalamove" && orderStatus === "Verified") {
          const sellerCompany = await SellersCompany.findByPk(seller);
          const lalamoveBookingService = await lalamoveBooking({
            quotationId: lalamove_quotation_id,
            senderStopId: lalamove_seller_stop_id,
            senderName: sellerCompany.company_name,
            senderPhone: sellerCompany.phone_number_primary,
            recipientStopId: lalamove_customer_stop_id,
            recipientName: `${customer.first_name} ${customer.last_name}`,
            recipientPhone: customer.phone,
            reference_no: reference_no,
          });

          if (lalamoveBookingService) {
            const lalamoveShareLink = lalamoveBookingService.shareLink;
            const lalamoveOrderId = lalamoveBookingService.id;
            orderForm.lalamove_share_link = lalamoveShareLink;
            orderForm.lalamove_order_id = lalamoveOrderId;
          }
        }
        await orderForm.save();
        orderReferenceNos.push(reference_no);
        // Dispatch Seller Notification
        if (orderStatus === "Verified") {
          const _notification = await dispatchOrderNotification({
            seller_company_id: seller,
            order_id: orderForm.id,
            order_reference_no: reference_no,
          });
        }
        // Dispatch Seller Notification
      }

      // Email
      await orderMailer(orderReferenceNos, customer);
      // Text Message
      await orderText(orderReferenceNos, customer);

      // Response Data
      const builtResponse = await buildResponse(orderReferenceNos);

      // Clear Cart
      await UserCart.destroy({
        where: {
          user_id: customer_id,
        },
      });
      // Clear Cart

      return builtResponse;
    }
  } catch (err) {
    throw err;
  }
};

exports.mockCheckoutService = async (customer_id, dataObj) => {
  try {
    const {
      shipping_type,
      payment_method,
      buildcredit_payment,
      bank_payment,
      // voucher_code,
      pickup_date,
      transportify_shipping_fee,
      lalamove_shipping_fee,
      checkoutAddress,
      checkoutLatitude,
      checkoutLongitude,
      item_vouchers,
    } = dataObj;

    // Variables
    const validShippingTypes = [
      "Standard Shipping",
      "Pick-up",
      "Transportify",
      "Lalamove",
      "Hardware Shipping",
    ];
    const validPaymentMethods = [
      "RPAF",
      "Build Credit",
      "Bank Transfer",
      "Split",
      "Hardware Credit",
      "Credit Card",
      "Online Payment",
    ];
    let buildCreditDetail = null;
    let hardwareCreditDetail = null;

    // let voucherDetail = null;
    let voucherInPercent = false;
    // let voucherAmount = 0;

    let checkoutDifferentAddress = false;

    if (
      checkoutAddress &&
      checkoutAddress !== null &&
      checkoutAddress !== "" &&
      checkoutLatitude &&
      checkoutLatitude !== null &&
      checkoutLatitude !== "0" &&
      checkoutLongitude &&
      checkoutLongitude !== null &&
      checkoutLongitude !== "0"
    ) {
      checkoutDifferentAddress = true;
    }

    const customerPromise = Customers.findByPk(customer_id);
    const userCartPromise = UserCart.findAll({
      where: {
        user_id: customer_id,
      },
      include: [
        {
          model: Products,
          as: "product",
          include: [
            {
              model: SellersCompany,
              as: "seller",
            },
            {
              model: ProductVariation,
              as: "product_variations",
              include: [
                {
                  model: ProductSubVariation,
                  as: "ProductSubVariations",
                },
              ],
            },
          ],
        },
      ],
    });

    const [customer, userCart] = await Promise.all([
      customerPromise,
      userCartPromise,
    ]);

    // Validations
    if (
      !customer ||
      !userCart ||
      !(Array.isArray(userCart) && userCart.length > 0)
    ) {
      return { error: "Undefined customer or user cart do not exist." };
    }
    if (
      !validShippingTypes.includes(shipping_type) ||
      !validPaymentMethods.includes(payment_method)
    ) {
      return { error: "Undefined shipping type or payment method." };
    }

    if (
      payment_method === "Build Credit" ||
      payment_method === "RPAF" ||
      payment_method === "Split"
    ) {
      buildCreditDetail = await getBuildCreditBalance(customer_id);

      if (payment_method === "Split") {
        if (
          !buildcredit_payment ||
          buildcredit_payment === "" ||
          !bank_payment ||
          bank_payment === ""
        ) {
          return {
            error:
              "buildcredit_payment or bank_payment is either empty or not defined.",
          };
        }
      }
    }

    if (payment_method === "Hardware Credit") {
      hardwareCreditDetail = await getHardwareCreditCheckout(customer_id);
    }

    // if (voucher_code && voucher_code !== "") {
    //   voucherDetail = await Vouchers.findOne({
    //     where: {
    //       voucher_code,
    //       status: true,
    //       valid_until: {
    //         [Op.gte]: new Date(),
    //       },
    //     },
    //   });

    //   if (!voucherDetail) {
    //     return { error: "Voucher code do not exist." };
    //   }
    //   if (voucherDetail.in_percent === "Yes") {
    //     voucherInPercent = true;
    //     voucherAmount = voucherDetail.amount_in_percent;
    //   } else {
    //     voucherAmount = voucherDetail.amount;
    //   }
    // }

    const todayDate = new Date().toISOString().split("T")[0];
    if (pickup_date === todayDate) {
      return { error: "Cannot set pickup date today's date." };
    }

    if (payment_method === "Online Payment") orderStatus = "To Pay";
    if (payment_method === "Bank Transfer" || payment_method === "Split")
      orderStatus = "Pending";

    const sellers = userCart
      .map((cartItem) => cartItem.product?.seller?.id)
      .filter(Boolean);
    const sellerIds = new Set(sellers);

    const responseItems = [];
    let shippingFeeResponse = 0;
    let subTotalResponse = 0;
    let cartAmountResponse = 0;

    if (sellerIds && sellerIds.size > 0) {
      for (const seller of sellerIds) {
        const filteredCart = userCart.filter(
          (cart) => cart.product.seller.id === seller
        );

        let subTotal = 0;
        let cartAmount = 0;
        let grandQuantity = 0;
        let grandTotal = 0;
        let voucherAmount = 0;
        let totalItemVoucherAmount = 0;
        const cartItems = [];
        for (const cart of filteredCart) {
          const {
            menu_id: product_id,
            quantity,
            price,
            has_sub_variation_chosen,
            product_variation_id,
            product_sub_variation_id,
          } = cart;
          let voucherApplied = null;
          let itemVoucher = null;

          if (
            item_vouchers &&
            Array.isArray(item_vouchers) &&
            item_vouchers.length > 0
          ) {
            voucherApplied = item_vouchers.find(
              (itemVoucher) => itemVoucher.cart_item_id === cart.id
            );
          }

          if (voucherApplied) {
            itemVoucher = await voucherService(
              voucherApplied.voucher_code,
              seller,
              product_id
            );
            if (!itemVoucher)
              return {
                error: true,
                message: `Item Voucher Code ${voucherApplied.voucher_code} is invalid.`,
              };
          }

          grandQuantity += parseFloat(quantity);

          let productId = product_id;
          let productVariationId = null;
          let productSubVariationId = null;
          let productPromise = Products.findByPk(productId);
          if (has_sub_variation_chosen === "true") {
            if (product_variation_id && !product_sub_variation_id) {
              productId = product_variation_id;
              productVariationId = product_variation_id;
              productPromise = ProductVariation.findByPk(productId);
            }
            if (product_variation_id && product_sub_variation_id) {
              productId = product_sub_variation_id;
              productSubVariationId = product_sub_variation_id;
              productPromise = ProductSubVariation.findByPk(productId);
            }
          }

          const [product] = await Promise.all([productPromise]);

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

          let itemPrice = discountedPrice ? discountedPrice : regularPrice;
          let itemVoucherAmount = 0;
          if (voucherApplied && itemVoucher) {
            if (itemVoucher.in_percent === "Yes") {
              const voucherPercentage = itemVoucher.amount_in_percent
                ? parseFloat(itemVoucher.amount_in_percent)
                : 0;
              itemVoucherAmount = itemPrice * voucherPercentage;
              const mockItemPrice = itemPrice - itemVoucherAmount;
              if (mockItemPrice < 0) {
                itemPrice = 0;
              } else {
                itemPrice -= itemVoucherAmount;
              }
            } else {
              const voucherAbsoluteValue = itemVoucher.amount
                ? parseFloat(itemVoucher.amount)
                : 0;
              itemVoucherAmount = voucherAbsoluteValue;
              const mockItemPrice = itemPrice - itemVoucherAmount;
              if (mockItemPrice < 0) {
                itemPrice = 0;
              } else {
                itemPrice -= itemVoucherAmount;
              }
            }
          }

          subTotal += itemPrice;
          totalItemVoucherAmount += itemVoucherAmount;
          const itemTotal = parseFloat(itemPrice) * parseFloat(quantity);
          cartAmount += itemTotal;
          cartAmountResponse += itemTotal;
          subTotalResponse += itemTotal;

          cartItems.push({
            product_id: productId,
            name: product.menu,
            photo: sellerProductImageBuilder(
              product.photo,
              product.seller_dashboard_src
            ),
            item_price: itemPrice,
            quantity,
            item_regular_price:
              voucherApplied && itemVoucher
                ? discountedPrice
                  ? discountedPrice
                  : regularPrice
                : null,
            item_total_price: itemTotal,
            voucher: {
              id: voucherApplied && itemVoucher ? itemVoucher.id : null,
              code:
                voucherApplied && itemVoucher ? itemVoucher.voucher_code : null,
              amount: voucherApplied && itemVoucher ? itemVoucherAmount : 0,
            },
            has_sub_variation_chosen,
            product_variation_id: productVariationId,
            product_sub_variation_id: productSubVariationId,
          });
        }
        // Get Delivery Fee for this Order
        const finalCustomerLatitude = checkoutDifferentAddress
          ? checkoutLatitude
          : customer.latitude;
        const finalCustomerLongitude = checkoutDifferentAddress
          ? checkoutLongitude
          : customer.longitude;
        const _shippingService = await shippingService(customer_id, {
          latitude: finalCustomerLatitude,
          longitude: finalCustomerLongitude,
        });

        let shippingFee = 0;
        let shippingDistance = 0;
        if (shipping_type === "Standard Shipping" && _shippingService) {
          shippingFeeResponse = parseFloat(
            _shippingService.standard_shipping_fee.fee
          );
          shippingFee =
            parseFloat(_shippingService.standard_shipping_fee.fee) /
            parseFloat(sellerIds.size);
          shippingDistance = parseFloat(
            _shippingService.standard_shipping_fee.total_distance_to_seller
          );
        }
        if (shipping_type === "Hardware Shipping" && _shippingService) {
          shippingFeeResponse = parseFloat(
            _shippingService.hardware_shipping.fee
          );
          shippingFee = parseFloat(_shippingService.hardware_shipping.fee);
          shippingDistance = parseFloat(
            _shippingService.hardware_shipping.total_distance_to_seller
          );
        }

        // Lalamove & Transportify
        if (shipping_type === "Lalamove") {
          if (!lalamove_shipping_fee)
            return {
              error: "Lalamove shipping fee is either undefined or missing.",
            };
          shippingFee = parseFloat(lalamove_shipping_fee) || 0;
          shippingFeeResponse = parseFloat(lalamove_shipping_fee) || 0;
        }
        if (shipping_type === "Transportify") {
          if (!transportify_shipping_fee)
            return {
              error:
                "Transportify shipping fee is either undefined or missing.",
            };
          shippingFee = parseFloat(transportify_shipping_fee) || 0;
          shippingFeeResponse = parseFloat(transportify_shipping_fee) || 0;
        }

        // Get Voucher Amount
        let totalVoucherAmount = 0;
        subTotal += parseFloat(Math.round(shippingFee));
        subTotalResponse += parseFloat(Math.round(shippingFee));
        // voucherAmount = parseFloat(voucherAmount) / parseFloat(sellerIds.size);
        voucherAmount = 0;
        if (voucherInPercent) {
          totalVoucherAmount = parseFloat(subTotal) * parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        } else {
          totalVoucherAmount = parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        }

        // Check for Build Credit Balance is greater than order total amount.
        if (
          payment_method === "Split" ||
          payment_method === "Build Credit" ||
          payment_method === "RPAF"
        ) {
          if (!buildCreditDetail) {
            return { error: "Build Credit Balance insufficient." };
          }

          if (payment_method === "Split") {
            if (
              parseFloat(buildcredit_payment) > buildCreditDetail.current_bal
            ) {
              return { error: "Build Credit Balance insufficient." };
            }
          } else {
            if (grandTotal > buildCreditDetail.current_bal) {
              return { error: "Build Credit Balance insufficient." };
            }
          }
        }

        if (payment_method === "Hardware Credit") {
          if (hardwareCreditDetail && hardwareCreditDetail.status) {
            const hardwareCreditBalance = parseFloat(
              hardwareCreditDetail.current_bal
            );
            if (grandTotal > hardwareCreditBalance) {
              return { error: "Hardware Credit Balance insufficient." };
            }
          } else {
            return { error: "Hardware Credit Balance insufficient." };
          }
        }

        responseItems.push({
          seller: {
            id: seller,
            name:
              (filteredCart[0].product.seller.shop_name &&
                filteredCart[0].product.seller.shop_name !== null) ||
              filteredCart[0].product.seller.shop_name !== ""
                ? filteredCart[0].product.seller.shop_name
                : filteredCart[0].product.seller.company_name,
          },
          cart_items: cartItems,
          fees: {
            cart_items: parseFloat(cartAmount),
            voucher: parseFloat(totalItemVoucherAmount),
          },
        });
      }
      return {
        response: responseItems,
        fees: {
          cart_items: parseFloat(cartAmountResponse),
          shipping: Math.round(shippingFeeResponse),
          subtotal: parseFloat(subTotalResponse),
        },
      };
    }
  } catch (err) {
    throw err;
  }
};

exports.mockCheckoutServicev2 = async (customer_id, dataObj, req) => {
  try {
    const {
      shipping_type,
      payment_method,
      buildcredit_payment,
      bank_payment,
      voucher_code,
      pickup_date,
      order_instructions,
      agent_code,
      transportify_shipping_fee,
      lalamove_shipping_fee,
      checkoutAddress,
      checkoutLatitude,
      checkoutLongitude,
      bank_transfer_attachment = "",
      suggested_voucher_id,
    } = dataObj;

    // Variables
    const validShippingTypes = [
      "Standard Shipping",
      "Pick-up",
      "Transportify",
      "Lalamove",
      "Hardware Shipping",
    ];
    const validPaymentMethods = [
      "RPAF",
      "Build Credit",
      "Bank Transfer",
      "Bank Cheque",
      "Split",
      "Hardware Credit",
      "Credit Card",
      "Online Payment",
      "Yield",
      "QR PH",
    ];
    let buildCreditDetail = null;
    let hardwareCreditDetail = null;
    let yieldCreditDetail = null;

    let checkoutDifferentAddress = false;

    let splitPaymentRecordId = null;
    if (
      checkoutAddress &&
      checkoutAddress !== null &&
      checkoutAddress !== "" &&
      checkoutLatitude &&
      checkoutLatitude !== null &&
      checkoutLatitude !== "0" &&
      checkoutLongitude &&
      checkoutLongitude !== null &&
      checkoutLongitude !== "0"
    ) {
      checkoutDifferentAddress = true;
    }

    const customerPromise = Customers.findByPk(customer_id);
    const userCartPromise = UserCart.findAll({
      where: {
        user_id: customer_id,
      },
      include: [
        {
          model: Products,
          as: "product",
          include: [
            {
              model: SellersCompany,
              as: "seller",
            },
            {
              model: ProductVariation,
              as: "product_variations",
              include: [
                {
                  model: ProductSubVariation,
                  as: "ProductSubVariations",
                },
              ],
            },
          ],
        },
      ],
    });

    const [customer, userCart] = await Promise.all([
      customerPromise,
      userCartPromise,
    ]);

    // Validations
    if (
      !customer ||
      !userCart ||
      !(Array.isArray(userCart) && userCart.length > 0)
    ) {
      return { error: "Undefined customer or user cart do not exist." };
    }
    if (
      !validShippingTypes.includes(shipping_type) ||
      !validPaymentMethods.includes(payment_method)
    ) {
      return { error: "Undefined shipping type or payment method." };
    }

    if (
      payment_method === "Build Credit" ||
      payment_method === "RPAF" ||
      payment_method === "Split"
    ) {
      buildCreditDetail = await getBuildCreditBalance(customer_id);

      if (payment_method === "Split") {
        if (
          !buildcredit_payment ||
          buildcredit_payment === "" ||
          !bank_payment ||
          bank_payment === ""
        ) {
          return {
            error:
              "buildcredit_payment or bank_payment is either empty or not defined.",
          };
        }
      }
    }

    if (payment_method === "Hardware Credit") {
      hardwareCreditDetail = await getHardwareCreditCheckout(customer_id);
    }

    if (payment_method === "Yield") {
      yieldCreditDetail = await getYieldAvailableCredit(req, customer_id, {
        yieldCode: customer.yield_code,
      });
    }

    const todayDate = new Date().toISOString().split("T")[0];
    if (pickup_date === todayDate) {
      return { error: "Cannot set pickup date today's date." };
    }

    let orderStatus = "Verified";
    if (payment_method === "Online Payment" || payment_method === "Yield")
      orderStatus = "To Pay";
    if (
      payment_method === "Bank Transfer" ||
      payment_method === "Split" ||
      payment_method === "QR PH"
    )
      orderStatus = "Pending";

    const sellers = userCart
      .map((cartItem) => cartItem.product?.seller?.id)
      .filter(Boolean);
    const sellerIds = new Set(sellers);

    const responseItems = [];
    let shippingFeeResponse = 0;
    let subTotalResponse = 0;
    let cartAmountResponse = 0;
    let voucherResponse = 0;
    let grandTotalResponse = 0;

    if (sellerIds && sellerIds.size > 0) {
      for (const seller of sellerIds) {
        let voucherDetail = null;
        let isVoucherInPercent = false;
        let voucherAmount = 0;
        let suggestedVoucherIdUsed = null;

        const enabledSellerPO = await sellerEnabledPurchaseOrders(seller);

        const filteredCart = userCart.filter(
          (cart) => cart.product.seller.id === seller
        );

        // MOCK CHECKOUT VAR
        let subTotal = 0;
        let cartAmount = 0;
        let grandQuantity = 0;
        let grandTotal = 0;
        const cartItems = [];
        // MOCK CHECKOUT VAR

        for (const cart of filteredCart) {
          const {
            menu_id: product_id,
            quantity,
            price,
            has_sub_variation_chosen,
            product_variation_id,
            product_sub_variation_id,
          } = cart;

          grandQuantity += parseFloat(quantity);

          let productId = product_id;
          let productVariationId = null;
          let productSubVariationId = null;
          let productPromise = Products.findOne({
            where: {
              id: productId,
            },
            include: [
              {
                model: ProductImages,
                as: "product_images",
              },
              {
                model: Products,
                as: "parent",
                include: [
                  {
                    model: ProductImages,
                    as: "product_images",
                  },
                  {
                    model: Products,
                    as: "parent",
                    include: [
                      {
                        model: ProductImages,
                        as: "product_images",
                      },
                    ],
                  },
                ],
              },
            ],
          });
          if (has_sub_variation_chosen === "true") {
            if (product_variation_id && !product_sub_variation_id) {
              productId = product_variation_id;
              productVariationId = product_variation_id;
              productPromise = ProductVariation.findByPk(productId);
            }
            if (product_variation_id && product_sub_variation_id) {
              productId = product_sub_variation_id;
              productSubVariationId = product_sub_variation_id;
              productPromise = ProductSubVariation.findByPk(productId);
            }
          }

          const [product] = await Promise.all([productPromise]);

          let itemStocks = parseFloat(product.stocks);

          if (enabledSellerPO) {
            const poItemStock = await checkPOItemStock(product.id);
            if (poItemStock) {
              itemStocks = poItemStock.availableStock;
            }
          }

          if (itemStocks < parseFloat(quantity)) {
            return {
              itemStockError: true,
              error: `Insufficient stock for ${product.menu}. Available stock is ${itemStocks}.`,
            };
          }

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

          let itemPrice = discountedPrice ? discountedPrice : regularPrice;

          const itemTotal = parseFloat(itemPrice) * parseFloat(quantity);
          subTotal += parseFloat(itemTotal);
          cartAmount += itemTotal;
          cartAmountResponse += itemTotal;
          subTotalResponse += itemTotal;

          const parentChain = [];
          let current = product;

          if (current.parent) {
            parentChain.push(current.parent);
            if (current.parent.parent) {
              parentChain.push(current.parent.parent);
            }
          }

          const lastParent =
            parentChain.length > 0
              ? parentChain[parentChain.length - 1]
              : product;

          const productImages = [];

          if (
            lastParent.product_images &&
            Array.isArray(lastParent.product_images) &&
            lastParent.product_images.length > 0
          ) {
            for (const image of lastParent.product_images) {
              productImages.push({
                id: image.id,
                url: sellerProductImageBuilder(image.file_name, true),
                is_thumbnail: image.is_thumbnail,
              });
            }
          }

          if (product.photo === null || product.photo === "") {
            const mainImage = productImages.find((p) => p.is_thumbnail);

            if (mainImage) {
              product.photo = mainImage.url;
            }
          } else {
            product.photo = sellerProductImageBuilder(
              product.photo,
              product.seller_dashboard_src
            );
          }

          const buildParentTree = (p) => {
            if (!p) return null;
            return {
              id: p.id,
              name: p.menu,
              parent_id: p.parent_id,
              product_images: p.product_images?.map((img) => ({
                id: img.id,
                url: sellerProductImageBuilder(img.file_name, true),
                is_thumbnail: img.is_thumbnail,
              })),
              parent: buildParentTree(p.parent),
            };
          };

          cartItems.push({
            product_id: productId,
            name: product.menu,
            photo: product.photo,
            item_price: itemPrice,
            quantity,
            item_regular_price: itemPrice,
            item_total_price: itemTotal,
            parent: buildParentTree(product.parent),
          });
        }

        // Get Delivery Fee for this Order
        const finalCustomerLatitude = checkoutDifferentAddress
          ? checkoutLatitude
          : customer.latitude;
        const finalCustomerLongitude = checkoutDifferentAddress
          ? checkoutLongitude
          : customer.longitude;

        let _shippingService = null;
        if (shipping_type !== "Pick-up") {
          _shippingService = await shippingService(customer_id, {
            latitude: finalCustomerLatitude,
            longitude: finalCustomerLongitude,
          });
        }

        let shippingFee = 0;
        let shippingDistance = 0;
        if (_shippingService && _shippingService.error) {
          return { error: _shippingService.error };
        }
        if (shipping_type === "Standard Shipping" && _shippingService) {
          shippingFeeResponse = parseFloat(
            _shippingService.standard_shipping_fee.fee
          );

          shippingFee =
            parseFloat(_shippingService.standard_shipping_fee.fee) /
            parseFloat(sellerIds.size);
          shippingDistance = parseFloat(
            _shippingService.standard_shipping_fee.total_distance_to_seller
          );
        }
        if (shipping_type === "Hardware Shipping" && _shippingService) {
          shippingFeeResponse = parseFloat(
            _shippingService.hardware_shipping.fee
          );

          shippingFee = parseFloat(_shippingService.hardware_shipping.fee);
          shippingDistance = parseFloat(
            _shippingService.hardware_shipping.total_distance_to_seller
          );
        }

        // Lalamove & Transportify
        if (shipping_type === "Lalamove") {
          if (!lalamove_shipping_fee)
            return {
              error: "Lalamove shipping fee is either undefined or missing.",
            };
          shippingFee = parseFloat(lalamove_shipping_fee) || 0;
          shippingFeeResponse = parseFloat(lalamove_shipping_fee) || 0;
        }
        if (shipping_type === "Transportify") {
          if (!transportify_shipping_fee)
            return {
              error:
                "Transportify shipping fee is either undefined or missing.",
            };
          shippingFee = parseFloat(transportify_shipping_fee) || 0;
          shippingFeeResponse = parseFloat(transportify_shipping_fee) || 0;
        }

        // Get Voucher Amount
        let totalVoucherAmount = 0;

        // subTotal += parseFloat(Math.round(shippingFee));

        // VOUCHER
        if (voucher_code && suggested_voucher_id) {
          return {
            error:
              "Sorry, you can only have one voucher applied. Remove applied voucher or suggested voucher to continue.",
          };
        }
        if (voucher_code && voucher_code !== "") {
          voucherDetail = await voucherService(
            voucher_code,
            seller,
            null,
            subTotal
          );
        }

        if (voucherDetail) {
          if (voucherDetail.in_percent === "Yes") {
            voucherAmount = voucherDetail.amount_in_percent;
            isVoucherInPercent = true;
          } else {
            voucherAmount = voucherDetail.amount;
          }
        }

        if (suggested_voucher_id) {
          const suggestedVoucher = await suggestedVoucherHelper(
            { customerId: customer_id },
            suggested_voucher_id
          );

          if (suggestedVoucher) {
            const {
              success: suggestedVoucherSuccess,
              voucherAmount: suggestedVoucherAmount,
            } = suggestedVoucher;

            if (!suggestedVoucherSuccess)
              return {
                error:
                  "There's a problem with your suggested voucher. Either you don't meet the spending requirement or the voucher is not valid.",
              };

            voucherAmount = suggestedVoucherAmount;
            suggestedVoucherIdUsed = suggested_voucher_id;
          }
        }
        // VOUCHER

        // subTotalResponse += parseFloat(Math.round(shippingFee));

        voucherAmount = parseFloat(voucherAmount) / parseFloat(sellerIds.size);
        if (isVoucherInPercent) {
          totalVoucherAmount = parseFloat(subTotal) * parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        } else {
          totalVoucherAmount = parseFloat(voucherAmount);
          grandTotal = parseFloat(subTotal) - parseFloat(totalVoucherAmount);
        }
        voucherResponse += totalVoucherAmount;

        grandTotal += parseFloat(Math.round(shippingFee));

        // Check for Build Credit Balance is greater than order total amount.
        if (
          payment_method === "Split" ||
          payment_method === "Build Credit" ||
          payment_method === "RPAF"
        ) {
          if (!buildCreditDetail) {
            return { error: "Build Credit Balance insufficient." };
          }

          if (payment_method === "Split") {
            if (
              parseFloat(buildcredit_payment) > buildCreditDetail.current_bal
            ) {
              return { error: "Build Credit Balance insufficient." };
            }
          } else {
            if (grandTotal > buildCreditDetail.current_bal) {
              return { error: "Build Credit Balance insufficient." };
            }
          }
        }

        if (payment_method === "Hardware Credit") {
          if (hardwareCreditDetail && hardwareCreditDetail.status) {
            const hardwareCreditBalance = parseFloat(
              hardwareCreditDetail.current_bal
            );
            if (grandTotal > hardwareCreditBalance) {
              return { error: "Hardware Credit Balance insufficient." };
            }
          } else {
            return { error: "Hardware Credit Balance insufficient." };
          }
        }

        if (payment_method === "Yield") {
          if (yieldCreditDetail && yieldCreditDetail.status) {
            const yieldCreditBalance = parseFloat(
              yieldCreditDetail.current_balance
            );
            if (grandTotal > yieldCreditBalance) {
              return { error: "Yield Credit Balance insufficient." };
            }
          } else {
            return { error: "Yield Credit Balance insufficient." };
          }
        }

        grandTotalResponse += parseFloat(grandTotal);

        responseItems.push({
          seller: {
            id: seller,
            name:
              (filteredCart[0].product.seller.shop_name &&
                filteredCart[0].product.seller.shop_name !== null) ||
              filteredCart[0].product.seller.shop_name !== ""
                ? filteredCart[0].product.seller.shop_name
                : filteredCart[0].product.seller.company_name,
          },
          cart_items: cartItems,
          fees: {
            cart_items: parseFloat(cartAmount),
            voucher: parseFloat(totalVoucherAmount),
            total: parseFloat(grandTotal),
          },
        });
      }
      return {
        response: responseItems,
        fees: {
          cart_items: parseFloat(cartAmountResponse),
          shipping: Math.round(shippingFeeResponse),
          subtotal: parseFloat(subTotalResponse),
          voucher: parseFloat(voucherResponse),
          grand_total: parseFloat(grandTotalResponse),
        },
      };
    }
  } catch (err) {
    throw err;
  }
};

exports.checkoutPaymentFallbackService = async (customer_id, reference_no) => {
  const transaction = await sequelizeConnect.transaction();
  try {
    const orderForm = await OrderForm.findOne({
      where: {
        reference_no: reference_no,
        customer_id: customer_id,
      },
      include: [
        {
          model: OrderFormDetails,
          as: "order_form_details",
        },
      ],
      transaction,
    });

    if (
      orderForm &&
      orderForm.order_form_details &&
      Array.isArray(orderForm.order_form_details)
    ) {
      await Promise.all(
        orderForm.order_form_details.map((orderDetail) =>
          orderDetail.destroy({ transaction })
        )
      );

      await orderForm.destroy({ transaction });

      const userCart = [];
      const currentDateTime = new Date();

      for (const orderDetail of orderForm.order_form_details) {
        const { product_id, quantity, price } = orderDetail;

        const userCartInsert = UserCart.create({
          user_id: customer_id,
          menu_id: product_id,
          quantity: quantity,
          price: price,
          has_sub_variation_chosen: "false",
          product_variation_id: null,
          product_sub_variation_id: null,
          created_at: currentDateTime,
          transaction,
        });
        userCart.push(userCartInsert);
      }

      await Promise.all(userCart);

      await transaction.commit();

      return { success: true };
    }
  } catch (err) {
    await transaction.rollback();
    throw err;
  }
};

async function orderMailer(reference_nos, customer) {
  try {
    const mailerPromises = [];
    for (const reference_no of reference_nos) {
      const orderForm = await OrderForm.findOne({
        where: {
          reference_no,
        },
        attributes: [
          "customer_id",
          "name",
          "reference_no",
          "date_created",
          "voucher_id_used",
          "delivery_fee",
          "total_amount",
          "seller_id",
          "shipping_type",
          "address",
        ],
        include: [
          {
            model: OrderFormDetails,
            as: "order_form_details",
            attributes: [
              "product_id",
              "quantity",
              "discounted_price",
              "price",
              "amount",
            ],
            include: [
              {
                model: Products,
                as: "product",
                attributes: ["menu", "photo", "discounted_price", "price"],
              },
            ],
          },
          {
            model: SellersCompany,
            as: "sellers_company_details",
            attributes: [
              "company_name",
              "shop_name",
              "shop_location_municipality",
              "shop_location_province",
              "address",
              "emailAddress",
            ],
          },
        ],
      });

      if (!orderForm) throw new Error("Order Form not found");

      const orderSummary = {
        date_created: orderForm.date_created,
        voucher_amount: orderForm.voucher_amount,
        shipping_fee: orderForm.delivery_fee,
        shipping_type: orderForm.shipping_type,
        total_amount: orderForm.total_amount,
        seller_name:
          orderForm.sellers_company_details.shop_name === "" ||
          orderForm.sellers_company_details.company_name === null
            ? orderForm.sellers_company_details.company_name
            : orderForm.sellers_company_details.shop_name,
        seller_address: orderForm.sellers_company_details.address,
        seller_location: `${orderForm.sellers_company_details?.shop_location_municipality}, ${orderForm.sellers_company_details?.shop_location_province}`,
        customer_address: orderForm.address,
        name: orderForm.name,
      };

      const productDetails = [];

      for (const orderFormDetail of orderForm.order_form_details) {
        let __productPrice = orderFormDetail.product.price;
        if (
          orderFormDetail.product.discounted_price &&
          orderFormDetail.product.discounted_price > 0
        ) {
          __productPrice = orderFormDetail.product.discounted_price;
        }
        productDetails.push({
          photo: orderFormDetail.product.photo,
          menu: orderFormDetail.product.menu,
          qty: orderFormDetail.quantity,
          price: __productPrice,
        });
      }

      const receivers = [customer.email];
      const ccs = [orderForm.sellers_company_details.emailAddress];

      const info = emailBuilder(
        receivers,
        ccs,
        "Buildhub - Order Placed",
        true,
        orderPlacedTemplate(reference_no, orderSummary, productDetails),
        []
      );

      mailerPromises.push(info);
    }
    await Promise.all(mailerPromises);
  } catch (err) {
    throw err;
  }
}

async function orderText(reference_nos, customer) {
  try {
    const textPromises = [];
    for (const reference_no of reference_nos) {
      const orderForm = await OrderForm.findOne({
        where: {
          reference_no: reference_no,
        },
        include: [
          {
            model: SellersCompany,
            as: "sellers_company_details",
          },
        ],
      });
      const willSendMsg =
        orderForm.payment_method !== "Bank Transfer" &&
        orderForm.payment_method !== "Split" &&
        orderForm.payment_method !== "Yield" &&
        orderForm.payment_method !== "Online Payment";

      if (willSendMsg) {
        const customerSmsTemplate = smsTemplates.orderVerified(
          `${customer.first_name} ${customer.last_name}`,
          reference_no
        );
        const smsTemplateSeller =
          smsTemplates.sellerWarehouseMenSmsTemplateOrderPlaced(
            `${customer.first_name} ${customer.last_name}`,
            customer.hardware_name,
            reference_no,
            formatDate12Hour(new Date()),
            orderForm.shipping_type === "Pick-up" ? false : true
          );
        const customerPhones = filterAndFormatPhones([
          customer.phone,
          customer.phone_2,
          customer.phone_3,
        ]);

        const sellerCompanyPhone1 =
          orderForm.sellers_company_details.phone_number_primary;
        const sellerCompanyPhone2 =
          orderForm.sellers_company_details.phone_number_optional;
        const sellerCompanyPhone3 =
          orderForm.sellers_company_details.phone_number_optional_2;

        const sellerPhones = filterAndFormatPhones([
          sellerCompanyPhone1,
          sellerCompanyPhone2,
          sellerCompanyPhone3,
        ]);

        if (customerPhones.length > 0) {
          const customerTextReceivers = customerPhones.join(",");
          const whispirText = whispir.messaging.singleMessage(
            {
              recipientNumber: customerTextReceivers,
              customTemplate: customerSmsTemplate,
            },
            "custom"
          );
          textPromises.push(whispirText);
        }
        if (sellerPhones.length > 0) {
          const sellerTextReceivers = sellerPhones.join(",");
          const whispirText = whispir.messaging.singleMessage(
            {
              recipientNumber: sellerTextReceivers,
              customTemplate: smsTemplateSeller,
            },
            "custom"
          );
          textPromises.push(whispirText);
        }
      }
    }

    await Promise.all(textPromises);
  } catch (err) {
    throw err;
  }
}

async function buildResponse(reference_nos) {
  try {
    const checkoutResponse = [];
    for (const reference_no of reference_nos) {
      const orderForm = await OrderForm.findOne({
        where: {
          reference_no,
        },
        include: [
          {
            model: SellersCompany,
            as: "sellers_company_details",
          },
          {
            model: Customers,
            as: "customer_detail",
          },
          {
            model: OrderFormDetails,
            as: "order_form_details",
            include: [
              {
                model: Products,
                as: "product",
              },
              {
                model: ProductVariation,
                as: "variation",
              },
              {
                model: ProductSubVariation,
                as: "sub_variation",
              },
            ],
          },
        ],
      });

      const orderResponse = {
        id: orderForm?.id,
        reference_no: orderForm?.reference_no,
        paynamics_reference_no: orderForm?.paynamics_reference_no,
        total_qty: parseFloat(orderForm?.total_qty),
        sub_total: parseFloat(orderForm?.subtotal_amount),
        grand_total: parseFloat(orderForm?.total_amount),
        customer: {
          id: orderForm?.customer_detail?.id,
          first_name: orderForm?.customer_detail?.first_name,
          last_name: orderForm?.customer_detail?.last_name,
          email: orderForm?.email,
          phone: orderForm?.contact_number,
          address: orderForm?.address,
          agent_code: orderForm?.agentCode,
          latitude: orderForm?.latitude,
          longitude: orderForm?.longitude,
        },
        shipping: {
          shipping_type: orderForm?.shipping_type,
          total_distance: orderForm?.total_distance,
          fee: parseFloat(orderForm?.delivery_fee),
          share_link: orderForm.lalamove_share_link,
          order_id: orderForm.lalamove_order_id,
        },
        payment: {
          method: orderForm?.payment_method,
          voucher: {
            id: orderForm?.voucher_id_used,
            amount: parseFloat(orderForm?.voucher_amount),
          },
          attachment: customerAttachmentProofBuilder(orderForm?.note),
          gateway: {
            id: orderForm?.third_party_payment_id,
            order_id: orderForm?.third_party_payment_order_id,
            payment_link: orderForm?.third_party_payment_payment_link,
          },
        },
        seller: {
          name: orderForm?.sellers_company_details?.shop_name?.trim()
            ? orderForm.sellers_company_details.shop_name
            : orderForm?.sellers_company_details?.company_name,
          address: orderForm?.sellers_company_details?.address,
        },
        details: [],
      };

      if (
        orderForm &&
        Array.isArray(orderForm.order_form_details) &&
        orderForm.order_form_details.length > 0
      ) {
        for (const orderFormDetail of orderForm.order_form_details) {
          let product = null;
          if (orderFormDetail) {
            if (orderFormDetail.product) {
              product = {
                id: orderFormDetail?.product?.id,
                name: orderFormDetail?.product?.menu,
                price:
                  orderFormDetail && orderFormDetail.discounted_price
                    ? parseFloat(orderFormDetail?.discounted_price)
                    : parseFloat(orderFormDetail?.price),
              };
            }
            if (orderFormDetail.variation) {
              product = {
                id: orderFormDetail?.variation?.id,
                name: orderFormDetail?.variation?.variation,
                price:
                  orderFormDetail && orderFormDetail.discounted_price
                    ? parseFloat(orderFormDetail?.discounted_price)
                    : parseFloat(orderFormDetail?.price),
              };
            }
            if (orderFormDetail.sub_variation) {
              product = {
                id: orderFormDetail?.sub_variation?.id,
                name: orderFormDetail?.sub_variation?.variation,
                price:
                  orderFormDetail && orderFormDetail.discounted_price
                    ? parseFloat(orderFormDetail?.discounted_price)
                    : parseFloat(orderFormDetail?.price),
              };
            }
          }
          const detailsResponse = {
            id: orderFormDetail?.id,
            product: product,
            quantity: parseFloat(orderFormDetail?.quantity),
            total_amount: parseFloat(orderFormDetail?.amount),
          };

          orderResponse.details.push(detailsResponse);
        }
      }
      checkoutResponse.push(orderResponse);
    }

    return checkoutResponse;
  } catch (err) {
    throw err;
  }
}

const getAvailablePaymentMethods = async () => {
  try {
    const paymentMethods = await PaymentMethods.findAll({
      where: {
        status: true,
      },
    });
    return paymentMethods;
  } catch (err) {
    return { error: err };
  }
};

const getYieldAvailableCredit = async (req, customer_id, dataObj) => {
  try {
    if (dataObj && dataObj.yieldCode) {
      const yieldCredit = await req.yieldClient.findCustomerByCode({
        customerCode: dataObj.yieldCode,
      });

      let yieldResponse = {
        status: false,
        current_balance: 0,
      };
      if (
        yieldCredit &&
        yieldCredit.items &&
        Array.isArray(yieldCredit.items)
      ) {
        const yieldResult = yieldCredit.items;
        const yieldAccount =
          yieldResult && Array.isArray(yieldResult) && yieldResult.length > 0
            ? yieldResult[0]
            : null;

        if (yieldAccount) {
          const yieldCreditLine = yieldAccount.creditLine;
          const yieldCreditLimit = yieldCreditLine.creditLimit.value;
          const yieldCreditAvailable = parseFloat(
            yieldCreditLine.amountAvailable.value
          );
          const yieldCustomerId = yieldAccount.id;

          yieldResponse.status = yieldCreditAvailable > 0;
          yieldResponse.current_balance = yieldCreditAvailable;
          yieldResponse.id = yieldCustomerId;
        }
      }

      return yieldResponse;
    }
    return null;
  } catch (err) {
    return { error: err };
  }
};

async function validatePaymentMethod(payment_method) {
  const availablePaymentMethods = await getAvailablePaymentMethods();

  if (
    !Array.isArray(availablePaymentMethods) ||
    availablePaymentMethods.length === 0
  ) {
    return false;
  }

  return availablePaymentMethods.some((p) => p.code === payment_method);
}

exports.availablePaymentMethodService = async (req, customer_id, dataObj) => {
  try {
    const promises = [
      getHardwareCreditCheckout(customer_id),
      getBuildCreditBalance(customer_id),
      getAvailablePaymentMethods(),
    ];

    if (dataObj.yieldCode) {
      if (req.yieldClient) {
        promises.push(getYieldAvailableCredit(req, customer_id, dataObj));
      }
    }
    let [hardwareCredit, buildCredit, paymentMethods, yieldCredit] =
      await Promise.all(promises);

    if (yieldCredit && yieldCredit.error) {
      yieldCredit = { status: false, current_balance: 0 };
    }
    return {
      credit: {
        hardware_credit: hardwareCredit,
        build_credit: buildCredit,
        yield_credit: yieldCredit,
      },
      payment_methods: paymentMethods,
    };
  } catch (err) {
    throw err;
  }
};
