const OrderForm = require("../models/OrderForm");
const Voucher = require("../models/Vouchers");
const Products = require("../models/Products");
const ProductMenu = require("../models/ProductMenu");
const SplitPayments = require("../models/SplitPayments");
const OrderFormDetails = require("../models/OrderFormDetails");
const Sellers = require("../models/Seller");
const SellersCompany = require("../models/SellersCompany");
const Customers = require("../models/Customers");
const Fees = require("../models/Fees");
const UserCart = require("../models/UserCart");
const errorHandler = require("../util/errorHandler");
const computeDistance = require("../helpers/computeDistance");
const axios = require("axios");
const ProductVariation = require("../models/ProductVariation");
const ProductSubVariation = require("../models/ProductSubVariation");
const formData = require("form-data");
const emailBuilder = require("../helpers/transporter");
const {
  orderPlacedTemplate,
} = require("../helpers/email-templates/html-bodys-new");
const whispir = require("../helpers/whispir");
const smsTemplates = require("../helpers/sms-no-templates/sms-no-templates");
const { getBuildCreditBalance } = require("../helpers/buildcredit");
const {
  filterAndFormatPhones,
  formatDate12Hour,
  generateReferenceNumber,
} = require("../helpers/common");
const { getHardwareCreditCheckout } = require("../helpers/hardwarecredit");
const { suggestedVoucherHelper } = require("./v3/suggested-voucher.controller");
const { Op } = require("sequelize");
const { sellerEnabledPurchaseOrders, checkPOItemStock } = require("../services/purchase-order.service");
exports.checkout = async (req, res, next) => {
  let finalDistance = 0;

  try {
    const loggedInCustomerId = req.customerId;

    const loggedInCustomer = await Customers.findByPk(loggedInCustomerId, {
      attributes: ["id", "agent_code", "latitude", "longitude"],
    });

    if (!loggedInCustomer) {
      return errorHandler("Logged-in customer not found", 404, next);
    }

    const { data, customerId } = req.body;

    const customer = await Customers.findByPk(
      customerId || loggedInCustomerId,
      {
        attributes: [
          "id",
          "first_name",
          "last_name",
          "hardware_name",
          "email",
          "phone",
          "phone_2",
          "phone_3",
          "address",
          "agent_code",
          "latitude",
          "longitude",
          "is_completed_profile",
        ],
      },
    );

    if (!customer) {
      console.log(
        `Customer with ID ${
          customerId || loggedInCustomerId
        } not found. Proceeding with the logged-in customer.`,
      );
    }

    const {
      phone: phoneCheck,
      address: addressCheck,
      latitude: latitudeCheck,
      longitude: longitudeCheck,
      is_completed_profile,
    } = customer;

    if (
      !phoneCheck ||
      !addressCheck ||
      !latitudeCheck ||
      !longitudeCheck ||
      latitudeCheck === 0 ||
      longitudeCheck === 0 ||
      latitudeCheck === "" ||
      longitudeCheck === "" ||
      addressCheck === "" ||
      !is_completed_profile
    )
      return errorHandler("Please update your profile first!", 400, next);

    const {
      shipping_type,
      payment_method,
      voucher_code,
      pickup_date,
      rpaf_payment,
      bank_payment,
      order_instructions,
      agent_code,
      suggested_voucher_id,
    } = data;
    let { lalamove_shipping_fee = 0, transportify_shipping_fee = 0 } = data;

    let {
      checkoutAddress = "",
      checkoutLatitude = "0",
      checkoutLongitude = "0",
    } = data;
    let isCheckoutDifferentAddress = false;

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

    // QUICK FIX
    // isCheckoutDifferentAddress = false;

    const { note: proofOfPaymentImage, po_attachment } = req.files;

    if (
      payment_method === "Bank Transfer" ||
      payment_method === "Bank Cheque" ||
      payment_method === "Split"
    ) {
      if (!proofOfPaymentImage)
        return errorHandler("Missing bank attachment", 400);
    }

    if (
      shipping_type !== "Standard Shipping" &&
      shipping_type !== "Pick-up" &&
      shipping_type !== "Transportify" &&
      shipping_type !== "Lalamove" &&
      shipping_type !== "Hardware Shipping"
    ) {
      return errorHandler("Invalid shipping_type", 400, next);
    }

    const allowedPaymentMethods = [
      "RPAF",
      "Build Credit",
      "Bank Transfer",
      "Bank Cheque",
      "Split",
      "Hardware Credit",
      "Credit Card",
      "Online Payment",
    ];
    if (!allowedPaymentMethods.includes(payment_method)) {
      return errorHandler("Invalid payment_method", 400, next);
    }

    let voucherApplied = false;
    let voucherIdUsed = null;
    let suggestedVoucherIdUsed = null;
    let voucherAmountUsed = 0;
    let isVoucherInPercent = false;

    if (voucher_code && suggested_voucher_id) {
      return res.status(400).json({
        success: false,
        message:
          "Sorry, you can only have one voucher applied. Remove applied voucher or suggested voucher to continue.",
      });
    }
    if (voucher_code) {
      const voucher = await Voucher.findOne({
        where: { voucher_code },
        attributes: ["id", "amount", "amount_in_percent", "in_percent"],
      });

      if (!voucher) {
        return errorHandler("Invalid voucher code", 400, next);
      }

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

      voucherApplied = true;
      voucherIdUsed = voucher.id;
    }

    if (suggested_voucher_id) {
      const suggestedVoucher = await suggestedVoucherHelper(
        req,
        suggested_voucher_id,
      );

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

        if (!suggestedVoucherSuccess)
          return res.status(400).json({
            success: false,
            message:
              "There's a problem with your suggested voucher. Either you don't meet the spending requirement or the voucher is not valid.",
          });
        voucherApplied = true;
        voucherAmountUsed = suggestedVoucherAmount;
        suggestedVoucherIdUsed = suggested_voucher_id;
      }
    }

    const today = new Date().toISOString().split("T")[0];
    if (pickup_date === today) {
      return errorHandler("Cannot set pickup date to today's date", 400, next);
    }

    const userCartItems = await UserCart.findAll({
      where: { user_id: loggedInCustomerId },
      attributes: [
        "menu_id",
        "quantity",
        "price",
        "has_sub_variation_chosen",
        "product_variation_id",
        "product_sub_variation_id",
      ],
      include: [
        {
          model: Products,
          as: "product",
          include: [{ model: SellersCompany, as: "seller" }],
        },
      ],
    });

    if (userCartItems.length === 0) {
      return errorHandler("User's cart is empty", 400, next);
    }

    let totalQuantity = 0;
    const orderSummary = await Promise.all(
      userCartItems.map(async (item) => {
        const product = await Products.findByPk(item.menu_id, {
          attributes: ["menu"],
        });
        const subtotal = item.price * item.quantity;
        // const subtotal = item.price;
        totalQuantity += item.quantity;

        let variationDetails = null;
        let subVariationDetails = null;

        if (item.has_sub_variation_chosen && item.product_variation_id) {
          const variation = await ProductVariation.findByPk(
            item.product_variation_id,
          );
          if (variation) {
            variationDetails = {
              id: variation.id,
              product_id: variation.product_id,
              variation_Name: variation.variation,
              description: variation.description,
              price: variation.price,
              discounted_price: variation.discounted_price,
              hasSubVariation: variation.hasSubVariation,
            };
          }
        }

        if (item.has_sub_variation_chosen && item.product_sub_variation_id) {
          const subVariation = await ProductSubVariation.findByPk(
            item.product_sub_variation_id,
          );
          if (subVariation) {
            subVariationDetails = {
              id: subVariation.id,
              product_variation_id: subVariation.product_variation_id,
              subVariation_Name: subVariation.custom,
              description: subVariation.description,
              price: subVariation.price,
              discounted_price: subVariation.discounted_price,
            };
          }
        }

        return {
          menu_id: item.menu_id,
          product_name: product.menu, // Add product_name to the order summary
          quantity: item.quantity,
          price: item.price,
          subtotal: subtotal,
          has_sub_variation_chosen: item.has_sub_variation_chosen,
          product_variation_id: item.product_variation_id,
          product_sub_variation_id: item.product_sub_variation_id,
          variation: variationDetails,
          sub_variation: subVariationDetails,
        };
      }),
    );

    let total = orderSummary.reduce((acc, item) => acc + item.subtotal, 0);

    if (isVoucherInPercent) {
      voucherAmountUsed = total * parseFloat(voucherAmountUsed);
      total -= voucherAmountUsed;
    } else {
      total -= voucherAmountUsed;
    }

    const proof_of_payment = order_instructions;

    let splitPaymentId = null;

    if (
      payment_method === "Split" ||
      payment_method === "Build Credit" ||
      payment_method === "RPAF"
    ) {
      const buildCreditDetail = await getBuildCreditBalance(loggedInCustomerId);
      const { status: buildCreditStatus, current_bal: buildCreditBalance } =
        buildCreditDetail;

      let __orderTotal = total;

      if (payment_method === "Split") {
        __orderTotal = rpaf_payment;
      }

      const isBalanceGreaterThanOrderTotal = buildCreditBalance >= __orderTotal;

      if (!buildCreditStatus || !isBalanceGreaterThanOrderTotal) {
        return res.status(401).json({
          success: false,
          message: "Insufficient Buildcredit Balance.",
        });
      }
    }

    if (payment_method === "Split") {
      // Check if rpaf_payment or bank_payment is equal to 0 or null
      if (
        rpaf_payment === null ||
        bank_payment === null ||
        rpaf_payment === 0 ||
        bank_payment === 0
      ) {
        return res.status(400).json({
          success: false,
          message:
            "rpaf_payment and bank_payment cannot be null or equal to 0 for Split payment.",
        });
      }

      // Create the split payment record
      const splitPayment = await SplitPayments.create({
        customer_id: customer.id,
        rpaf_payment,
        bank_payment,
      });
      splitPaymentId = splitPayment.id;
    } else {
      // For other payment methods, rpaf_payment and bank_payment can be null
      if (rpaf_payment !== 0 || bank_payment !== 0) {
        return res.status(400).json({
          success: false,
          message:
            "rpaf_payment and bank_payment must be 0 for payment methods other than Split.",
        });
      }
    }

    if (payment_method === "Hardware Credit") {
      const hardware = await getHardwareCreditCheckout(loggedInCustomerId);
      if (hardware && hardware.status) {
        const hardwareCreditBalance = parseFloat(hardware.current_bal);
        if (total > hardwareCreditBalance) {
          return errorHandler("Hardware Credit Balance insufficient.", 404);
        }
      } else {
        return errorHandler("Hardware Credit is not available.", 404);
      }
    }

    if (shipping_type === "Pick-up" && !pickup_date) {
      return res.status(400).json({
        success: false,
        message: "pickup_date is required for Pick-up shipping.",
      });
    }

    var customerLat,
      customerLng,
      sellerCompanyId,
      sellerCompanyEmailAddress,
      sellerCompanyPhone1,
      sellerCompanyPhone2,
      sellerCompanyPhone3,
      sellerLat,
      sellerLng,
      productMenuCategory,
      compututationMethod,
      smallItemPerKm,
      smallItemFixed,
      bigItemPerKm,
      bigItemFixed,
      flagdownBig,
      flagdownSmall,
      inHouseSmallPerKm,
      inHouseSmallFixed,
      inHouseBigPerKm,
      inHouseBigFixed,
      inHouseFlagdownBig,
      inHouseFlagdownSmall,
      defaultShippingFee,
      customerDistanceKm;

    var standardShippingFee, standardShippingRate, standardShippingFlagdown;
    var hardwareShippingFee, hardwareShippingRate, hardwareShippingFlagdown;

    const { customerId: _customerId } = req;

    const userCartDetail = await UserCart.findAll({
      where: {
        user_id: _customerId,
      },
      attributes: [
        "menu_id",
        "quantity",
        "price",
        "has_sub_variation_chosen",
        "product_variation_id",
        "product_sub_variation_id",
      ],
      include: [
        {
          model: Products,
          as: "product",
          include: [
            { model: SellersCompany, as: "seller" },
            {
              model: ProductMenu,
              as: "menus",
            },
          ],
        },
      ],
    });

    if (userCartDetail.length === 0) {
      return res
        .status(200)
        .json({ success: false, msg: "User has empty cart!" });
    }

    sellerCompanyPhone1 =
      userCartDetail[0]?.product?.seller?.phone_number_primary;
    sellerCompanyPhone2 =
      userCartDetail[0]?.product?.seller?.phone_number_optional;
    sellerCompanyPhone3 =
      userCartDetail[0]?.product?.seller?.phone_number_optional_2;

    if (
      shipping_type === "Standard Shipping" ||
      shipping_type === "Hardware Shipping"
    ) {
      try {
        const defaultShipping = await Fees.findOne({
          where: {
            fee: "Shipping",
          },
        });

        defaultShippingFee = parseFloat(defaultShipping.amount);

        const customerDetail = await Customers.findByPk(_customerId);

        const { latitude, longitude } = customerDetail;
        if (!latitude || !longitude) {
          return res
            .status(200)
            .json({ success: false, msg: "Customer location not set!" });
        }

        customerLat = latitude;
        customerLng = longitude;

        if (isCheckoutDifferentAddress) {
          customerLat = checkoutLatitude;
          customerLng = checkoutLongitude;
        }

        productMenuCategory = userCartDetail[0].product.menus.size_category;

        sellerCompanyId = userCartDetail[0].product.seller.id;
        sellerCompanyEmailAddress =
          userCartDetail[0].product.seller.emailAddress;

        sellerLat = userCartDetail[0].product.seller.latitude;
        sellerLng = userCartDetail[0].product.seller.longitude;
        compututationMethod =
          userCartDetail[0].product.seller.computation_method;
        smallItemFixed = userCartDetail[0].product.seller.small_item_fee_fixed;
        smallItemPerKm = userCartDetail[0].product.seller.small_item_fee_perkm;
        bigItemFixed = userCartDetail[0].product.seller.big_item_fee_fixed;
        bigItemPerKm = userCartDetail[0].product.seller.big_item_fee_perkm;
        flagdownBig = userCartDetail[0].product.seller.flagdownBigKM;
        flagdownSmall = userCartDetail[0].product.seller.flagdownSmallKM;
        inHouseBigFixed = userCartDetail[0].product.seller.in_house_big_fixed;
        inHouseBigPerKm = userCartDetail[0].product.seller.in_house_big_per_km;
        inHouseSmallFixed =
          userCartDetail[0].product.seller.in_house_small_fixed;
        inHouseSmallPerKm =
          userCartDetail[0].product.seller.in_house_small_per_km;
        inHouseFlagdownBig =
          userCartDetail[0].product.seller.in_house_flagdown_big_km;
        inHouseFlagdownSmall =
          userCartDetail[0].product.seller.in_house_flagdown_small_km;

        if (!sellerLat || !sellerLng) {
          return res
            .status(200)
            .json({ success: false, msg: "Seller location not set!" });
        }

        customerDistanceKm = await computeDistance(
          `${customerLat},${customerLng}`,
          `${sellerLat},${sellerLng}`,
        );

        switch (compututationMethod.toLowerCase()) {
          case "perkm":
            if (productMenuCategory.toLowerCase() === "small item") {
              // Standard Shipping
              standardShippingFee =
                parseFloat(smallItemPerKm) * customerDistanceKm +
                parseFloat(flagdownSmall);
              standardShippingRate = parseFloat(smallItemPerKm);
              standardShippingFlagdown = parseFloat(flagdownSmall);

              // Hardware Shipping
              hardwareShippingFee =
                parseFloat(inHouseSmallPerKm) * customerDistanceKm +
                parseFloat(inHouseFlagdownSmall);
              hardwareShippingRate = parseFloat(inHouseSmallPerKm);
              hardwareShippingFlagdown = parseFloat(inHouseFlagdownSmall);
            } else if (productMenuCategory.toLowerCase() === "large item") {
              // Standard Shipping
              standardShippingFee =
                parseFloat(bigItemPerKm) * customerDistanceKm +
                parseFloat(flagdownBig);
              standardShippingRate = parseFloat(bigItemPerKm);
              standardShippingFlagdown = parseFloat(flagdownBig);

              // Hardware Shipping
              hardwareShippingFee =
                parseFloat(inHouseBigPerKm) * customerDistanceKm +
                parseFloat(inHouseFlagdownBig);
              hardwareShippingRate = parseFloat(inHouseBigPerKm);
              hardwareShippingFlagdown = parseFloat(inHouseFlagdownBig);
            }
            break;
          case "fixed":
            if (productMenuCategory.toLowerCase() === "small item") {
              // Standard Shipping
              standardShippingFee =
                parseFloat(smallItemFixed) + parseFloat(flagdownSmall);
              standardShippingRate = parseFloat(smallItemFixed);
              standardShippingFlagdown = parseFloat(flagdownSmall);

              // Hardware Shipping
              hardwareShippingFee =
                parseFloat(inHouseSmallFixed) +
                parseFloat(inHouseFlagdownSmall);
              hardwareShippingRate = parseFloat(inHouseSmallFixed);
              hardwareShippingFlagdown = parseFloat(inHouseFlagdownSmall);
            } else if (productMenuCategory.toLowerCase() === "large item") {
              // Standard Shipping
              standardShippingFee =
                parseFloat(bigItemFixed) + parseFloat(flagdownBig);
              standardShippingRate = parseFloat(bigItemFixed);
              standardShippingFlagdown = parseFloat(flagdownBig);

              // Hardware Shipping
              hardwareShippingFee =
                parseFloat(inHouseBigFixed) + parseFloat(inHouseFlagdownBig);
              hardwareShippingRate = parseFloat(inHouseBigFixed);
              hardwareShippingFlagdown = parseFloat(inHouseFlagdownBig);
            }
            break;
          default:
            standardShippingFee = defaultShippingFee;
            standardShippingRate = defaultShippingFee;
            standardShippingFlagdown = 0;
            break;
        }
      } catch (err) {
        next(err);
      }
    }

    if (isNaN(hardwareShippingFee)) hardwareShippingFee = 0;

    let finalShippingFee =
      shipping_type === "Standard Shipping"
        ? standardShippingFee
        : hardwareShippingFee;
    let finalShippingFeeRate =
      shipping_type === "Standard Shipping"
        ? standardShippingRate
        : hardwareShippingRate;

    if (shipping_type === "Standard Shipping") {
      finalShippingFee = standardShippingFee;
      finalShippingFeeRate = standardShippingRate;
    } else if (shipping_type === "Hardware Shipping") {
      finalShippingFee = hardwareShippingFee;
      finalShippingFeeRate = hardwareShippingRate;
    } else if (shipping_type === "Lalamove") {
      finalShippingFee = lalamove_shipping_fee;
      finalShippingFeeRate = 0;
    } else if (shipping_type === "Transportify") {
      finalShippingFee = transportify_shipping_fee;
      finalShippingFeeRate = 0;
    }

    total += finalShippingFee ? Math.round(finalShippingFee) : 0;

    // const reference_no =
    //   "ORD" + Math.random().toString(36).substring(2, 10).toUpperCase();
    const reference_no = await generateReferenceNumber();
    const orderForm = await OrderForm.create({
      customer_id: customer.id,
      name: `${customer.first_name} ${customer.last_name}`,
      email: customer.email,
      contact_number: customer.phone,
      address: isCheckoutDifferentAddress ? checkoutAddress : customer.address,
      longitude: customerLng,
      latitude: customerLat,
      agentCode: agent_code || "",
      delivery_fee: Math.round(finalShippingFee),
      shipping_type,
      pickup_date,
      payment_method,
      proof_of_payment,
      note:
        payment_method === "Bank Transfer" ||
        payment_method === "Split" ||
        payment_method === "Bank Cheque"
          ? proofOfPaymentImage[0]?.filename
          : null,
      status:
        payment_method === "Bank Transfer" ||
        payment_method === "Split" ||
        payment_method === "Online Payment" ||
        payment_method === "Bank Cheque"
          ? "Pending"
          : "Verified",
      voucher_id_used: voucherIdUsed,
      suggested_voucher_id_used: suggestedVoucherIdUsed,
      total_amount: total,
      total_qty: totalQuantity,
      has_sub_variation_chosen: userCartItems[0].has_sub_variation_chosen,
      product_variation_id: userCartItems[0].product_variation_id,
      product_sub_variation_id: userCartItems[0].product_sub_variation_id,
      split_payment_id: splitPaymentId,
      seller_id: userCartItems[0].product.seller.id,
      distance: shipping_type === "Standard Shipping" ? finalDistance : null,
      reference_no: reference_no,
      is_v2_order: true,
      voucher_amount: voucherAmountUsed,
      po_attachment:
        po_attachment &&
        Array.isArray(po_attachment) &&
        po_attachment.length > 0
          ? po_attachment[0].filename
          : null,
    });

    for (const item of orderSummary) {
      const product = await Products.findByPk(item.menu_id);
      await product.update({ stocks: product.stocks - item.quantity });
      await OrderFormDetails.create({
        order_form_id: orderForm.id,
        product_id: item.menu_id,
        quantity: item.quantity,
        price: item.price,
        amount: item.subtotal,
        variant: "",
        has_sub_variation_chosen: item.has_sub_variation_chosen,
        product_variation_id: item.product_variation_id,
        product_sub_variation_id: item.product_sub_variation_id,
        reference_no: reference_no,
      });
    }

    await UserCart.destroy({
      where: { user_id: loggedInCustomerId },
    });

    const responseData = {
      success: true,
      message: "Order placed successfully",
      orderFormId: orderForm.id,
      referenceNo: reference_no,
      customer: {
        customer_Id: customer.id,
        firstName: customer.first_name,
        lastName: customer.last_name,
        email: customer.email,
        phone: customer.phone,
        address: isCheckoutDifferentAddress
          ? checkoutAddress
          : customer.address,
        agentCode: agent_code || "",
        latitude: customerLat,
        longitude: customerLng,
      },
      shipping: {
        shippingType: shipping_type,
        finalDistance: `${customerDistanceKm} km`,
        shippingFeePerKm: finalShippingFeeRate,
        totalShippingFee: Math.round(finalShippingFee),
      },
      payment: {
        paymentMethod: payment_method,
        voucherApplied: voucherApplied,
        voucherIdUsed: voucherIdUsed,
        suggestedVoucherIdUsed: suggestedVoucherIdUsed,
        voucherAmountUsed: voucherAmountUsed,
        rpafPayment: rpaf_payment,
        bankPayment: bank_payment,
        proofOfPayment: proofOfPaymentImage
          ? proofOfPaymentImage[0].filename
          : null,
      },
      orderSummary: orderSummary.map((item) => ({
        product_Id: item.menu_id,
        product_name: item.product_name,
        quantity: item.quantity,
        price: item.price,
        subtotal: item.subtotal,
        hasSubVariationChosen: item.has_sub_variation_chosen,
        variation: item.variation,
        subVariation: item.sub_variation,
      })),
      total_Price: total,
      totalQuantity: totalQuantity,
    };

    // EMAIL
    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: Voucher,
          as: "voucher_details",
          attributes: ["amount", "amount_in_percent"],
          required: false,
        },
        {
          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");

    let voucherAmount = 0;
    if (_orderForm.voucher_details) {
      const voucherDetail = _orderForm.voucher_details;

      if (voucherDetail.amount_in_percent) {
        const totalAmount = _orderForm.total_amount;
        const percent = parseFloat(voucherDetail.amount_in_percent);
        voucherAmount = (totalAmount * percent) / 100;
      } else {
        voucherAmount = parseFloat(voucherDetail.amount);
      }
    }

    const _orderSummary = {
      date_created: _orderForm.date_created,
      voucher_amount: voucherAmount,
      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,
      });
    }
    // EMAIL

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

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

    // Text Message

    const willSendMsg =
      payment_method !== "Bank Transfer" &&
      payment_method !== "Split" &&
      payment_method !== "Online Payment" &&
      payment_method !== "Bank Cheque";

    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()),
          shipping_type === "Pick-up" ? false : true,
        );
      const customerPhones = filterAndFormatPhones([
        customer.phone,
        customer.phone_2,
        customer.phone_3,
      ]);
      const sellerPhones = filterAndFormatPhones([
        sellerCompanyPhone1,
        sellerCompanyPhone2,
        sellerCompanyPhone3,
      ]);
      if (customerPhones.length > 0) {
        const customerTextReceivers = customerPhones.join(",");
        const whispirText = await whispir.messaging.singleMessage(
          {
            recipientNumber: customerTextReceivers,
            customTemplate: customerSmsTemplate,
          },
          "custom",
        );
      }
      if (sellerPhones.length > 0) {
        const sellerTextReceivers = sellerPhones.join(",");
        const whispirText = await whispir.messaging.singleMessage(
          {
            recipientNumber: sellerTextReceivers,
            customTemplate: smsTemplateSeller,
          },
          "custom",
        );
      }
    }

    // Text Message

    res.status(201).json(responseData);
  } catch (error) {
    console.error("Error during checkout:", error);
    next(error);
  }
};

exports.distanceCustomerToSeller = async (req, res, next) => {
  // compute distance from customer to seller
  try {
    const { customerLatitude, customerLongitude, sellerId } = req.body;

    const seller = await Sellers.findOne({ where: { id: sellerId } });

    if (!seller) {
      return res.status(404).json({ error: "Seller not found" });
    }

    try {
      const distance = await computeDistance(
        `${customerLatitude},${customerLongitude}`,
        `${seller.lat},${seller.long}`,
      );

      const absoluteDistance = Math.abs(distance); // Ensure distance is positive
      const roundedDistance = Number(absoluteDistance.toFixed(2));

      // If decimal part is 0.5 or greater, round to the nearest whole number
      const finalDistance =
        roundedDistance % 1 >= 0.5
          ? Math.ceil(roundedDistance)
          : roundedDistance;

      res.json({
        distance: `${distance} km`,
        roundedOffDistance: `${finalDistance} km`,
      });
    } catch (error) {
      console.error("Error calculating distance:", error.message);

      if (
        error.message ===
        "No route found between the specified origin and destination."
      ) {
        return res
          .status(400)
          .json({ error: "No route found. Please check your location." });
      } else {
        return res.status(500).json({ error: "Internal Server Error" });
      }
    }
  } catch (error) {
    console.error("Error fetching seller:", error.message);
    res.status(500).json({ error: "Internal Server Error" });
  }
};
exports.getShippingFee = async (req, res, next) => {
  try {
    const loggedInCustomerId = req.customerId;

    // Fetch customer data including latitude and longitude
    const customer = await Customers.findByPk(loggedInCustomerId);

    // Find all items in the user's cart for the logged-in customer
    const userCartItems = await UserCart.findAll({
      where: { user_id: loggedInCustomerId },
      attributes: [
        "menu_id",
        "quantity",
        "price",
        "has_sub_variation_chosen",
        "product_variation_id",
        "product_sub_variation_id",
      ],
      include: [
        {
          model: Products,
          as: "product",
          include: [{ model: SellersCompany, as: "seller" }],
        },
      ],
    });

    let shippingFees = {};
    let totalAmount = 0; // Initialize total amount

    // Calculate total amount based on prices of items in the cart
    userCartItems.forEach((item) => {
      totalAmount += item.quantity * item.price; // Add the price of each item to total amount
    });

    // Calculate shipping fee for each shipping type
    const shippingTypes = [
      "Standard Shipping",
      "Pick-up",
      "Transportify",
      "Lalamove",
      "Hardware Shipping",
    ];

    for (const shipping_type of shippingTypes) {
      let shippingFee = 0;

      if (shipping_type === "Standard Shipping") {
        // Calculate distance between customer and seller
        const sellerLatitude = userCartItems[0].product.seller.latitude;
        const sellerLongitude = userCartItems[0].product.seller.longitude;
        const customerLatitude = customer.latitude;
        const customerLongitude = customer.longitude;

        // Ensure coordinates are valid numbers
        console.log(customerLatitude);
        console.log(customerLongitude);
        console.log(sellerLatitude);
        console.log(sellerLongitude);
        if (
          !isNaN(customerLatitude) &&
          !isNaN(customerLongitude) &&
          !isNaN(sellerLatitude) &&
          !isNaN(sellerLongitude)
        ) {
          let finalDistance = await computeDistance(
            `${customerLatitude},${customerLongitude}`,
            `${sellerLatitude},${sellerLongitude}`,
          );

          const absoluteDistance = Math.abs(finalDistance); // Ensure distance is positive
          const roundedDistance = Number(absoluteDistance.toFixed(2));

          finalDistance =
            roundedDistance % 1 >= 0.5
              ? Math.ceil(roundedDistance)
              : roundedDistance;

          console.log("Customer Latitude:", customerLatitude);
          console.log("Customer Longitude:", customerLongitude);
          console.log("Seller Latitude:", sellerLatitude);
          console.log("Seller Longitude:", sellerLongitude);
          console.log("Computed Distance:", finalDistance);

          const product = userCartItems[0].product;
          const productMenu = await ProductMenu.findByPk(product.menu_id);

          if (!productMenu) {
            throw new Error("Product menu not found");
          }

          const productSizeCategory = productMenu.size_category;

          console.log("Product Menu Size Category:", productMenu.size_category);

          let shippingFeePerKm = 0;

          if (productSizeCategory.toLowerCase() === "large item") {
            const seller = userCartItems[0].product.seller;

            if (seller) {
              const sellerCompany = await SellersCompany.findByPk(seller.id);
              if (sellerCompany) {
                shippingFeePerKm = sellerCompany.big_item_fee_perkm;
                console.log(
                  "Shipping Fee Per Km (Large Item):",
                  shippingFeePerKm,
                );
              } else {
                throw new Error("Seller company not found");
              }
            } else {
              throw new Error("Seller not found");
            }
          } else if (productSizeCategory.toLowerCase() === "small item") {
            const seller = userCartItems[0].product.seller;

            if (seller) {
              const sellerCompany = await SellersCompany.findByPk(seller.id);

              if (sellerCompany) {
                shippingFeePerKm = sellerCompany.small_item_fee_perkm;
                console.log(
                  "Shipping Fee Per Km (Small Item):",
                  shippingFeePerKm,
                );
              } else {
                throw new Error("Seller company not found");
              }
            } else {
              throw new Error("Seller not found");
            }
          } else {
            throw new Error("Invalid product size category");
          }

          shippingFee = finalDistance * shippingFeePerKm;
          console.log("Total Shipping Fee:", shippingFee);
        } else {
          // throw new Error("Invalid coordinates");
          return null;
        }
      } else if (shipping_type === "Pick-up") {
        shippingFee = 0;
      } else if (shipping_type === "Hardware Shipping") {
        // Calculate distance between customer and seller
        const sellerLatitude = userCartItems[0].product.seller.latitude;
        const sellerLongitude = userCartItems[0].product.seller.longitude;
        const customerLatitude = customer.latitude;
        const customerLongitude = customer.longitude;

        // Ensure coordinates are valid numbers
        if (
          !isNaN(customerLatitude) &&
          !isNaN(customerLongitude) &&
          !isNaN(sellerLatitude) &&
          !isNaN(sellerLongitude)
        ) {
          let finalDistance = await computeDistance(
            `${customerLatitude},${customerLongitude}`,
            `${sellerLatitude},${sellerLongitude}`,
          );

          const absoluteDistance = Math.abs(finalDistance); // Ensure distance is positive
          const roundedDistance = Number(absoluteDistance.toFixed(2));

          finalDistance =
            roundedDistance % 1 >= 0.5
              ? Math.ceil(roundedDistance)
              : roundedDistance;

          console.log("Customer Latitude:", customerLatitude);
          console.log("Customer Longitude:", customerLongitude);
          console.log("Seller Latitude:", sellerLatitude);
          console.log("Seller Longitude:", sellerLongitude);
          console.log("Computed Distance:", finalDistance);

          const product = userCartItems[0].product;
          const productMenu = await ProductMenu.findByPk(product.menu_id);

          if (!productMenu) {
            throw new Error("Product menu not found");
          }

          const productSizeCategory = productMenu.size_category;

          console.log("Product Menu Size Category:", productMenu.size_category);

          let shippingFeePerKm = 0;

          if (productSizeCategory.toLowerCase() === "large item") {
            const seller = userCartItems[0].product.seller;

            if (seller) {
              const sellerCompany = await SellersCompany.findByPk(seller.id);

              if (sellerCompany) {
                shippingFeePerKm = sellerCompany.in_house_big_per_km;
                console.log(
                  "Shipping Fee Per Km (Large Item):",
                  shippingFeePerKm,
                );
              } else {
                throw new Error("Seller company not found");
              }
            } else {
              throw new Error("Seller not found");
            }
          } else if (productSizeCategory.toLowerCase() === "small item") {
            const seller = userCartItems[0].product.seller;

            if (seller) {
              const sellerCompany = await SellersCompany.findByPk(seller.id);

              if (sellerCompany) {
                shippingFeePerKm = sellerCompany.in_house_small_per_km;
                console.log(
                  "Shipping Fee Per Km (Small Item):",
                  shippingFeePerKm,
                );
              } else {
                throw new Error("Seller company not found");
              }
            } else {
              throw new Error("Seller not found");
            }
          } else {
            throw new Error("Invalid product size category");
          }

          // Calculate total shipping fee by multiplying finalDistance with shippingFeePerKm
          shippingFee = finalDistance * shippingFeePerKm;
          console.log("Total Shipping Fee:", shippingFee);
        } else {
          // throw new Error("Invalid coordinates");
          return null;
        }
      } else if (shipping_type === "Transportify") {
        try {
          const transportifyAPI =
            "https://buildhub.ph/includes/functions/get-shipping-fee-transportify.php";
          const _formData = new formData();

          _formData.append("sID", "9");
          _formData.append("customerLat", "14.575047707070325");
          _formData.append("customerLng", "121.08433722380371");
          _formData.append("customerAddress", "");
          _formData.append("itemCategory", "");
          _formData.append("lalamove_ship", "10WHEEL_TRUCK");
          _formData.append("transportify_ship", "229");

          const response = await axios.post(transportifyAPI, _formData, {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          });

          // console.log (response);

          const responseData = response.data;
          const { data } = responseData;
          // console.log (responseData);

          const wingVan = data.filter((vehicleTypes) =>
            vehicleTypes.vehicle_type_name.includes("10w-Wing-Van"),
          );
          const shippingPrice = wingVan[0].total_fees;
          console.log("Transportify shipping fee:", shippingPrice);
          shippingFee = shippingPrice;
        } catch (error) {
          console.error("Error with Transportify API:", error.message);
        }
      } else if (shipping_type === "Lalamove") {
        try {
          const LalamoveAPI =
            "https://buildhub.ph/includes/functions/get-shipping-fee-lalamove.php";
          const _formData = new formData();

          _formData.append("sID", "9");
          _formData.append("customerLat", "14.575047707070325");
          _formData.append("customerLng", "121.08433722380371");
          _formData.append(
            "customerAddress",
            "6XFP+V46, Tacloban City, Leyte, Philippines",
          );
          _formData.append("itemCategory", "Large Item");
          _formData.append("lalamove_ship", "10WHEEL_TRUCK");
          _formData.append("transportify_ship", "229");

          const response = await axios.post(LalamoveAPI, _formData, {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          });

          const responseData = JSON.parse(response.data);
          console.log("Lalamove API Response Data:", responseData);

          const totalString = responseData.data.priceBreakdown.total;
          const shippingPrice = parseInt(totalString);
          console.log("Lalamove shipping fee:", shippingPrice);
          shippingFee = shippingPrice;
        } catch (error) {
          console.error("Error with Lalamove API:", error.message);
        }
      }
      shippingFees[shipping_type] = shippingFee;
    }

    const responseData = {
      userCartItems,
      totalAmount,
      shippingFees,
    };

    res.status(200).json({ success: true, responseData });
  } catch (error) {
    console.error("Error fetching user's cart:", error);
    next(error);
  }
};

exports.getPaymentMethods = async (req, res, next) => {
  const { customerId } = req;

  const hardwareCredit = await getHardwareCreditCheckout(customerId);
  const __buildCredit = await getBuildCreditBalance(customerId);
  res.status(200).json({
    success: true,
    payment_methods: {
      buildCredit: __buildCredit,
      hardwareCredit,
    },
  });
};

// const getBuildCreditBalance = async (customerId) => {
//   try {
//     let ___creditLimit = 0,
//       ___orderFormTotal = 0,
//       ___orderFormSplitTotal = 0,
//       ___rpafPaymentTotal = 0,
//       ___overAllTotal = 0;
//     const returnedResponse = {
//       credit_terms: "",
//       approved_credit_limit: 0,
//       used_credit_limit: 0,
//       current_bal: 0,
//       status: false,
//     };

//     const buildCredit = await Rpaf.findOne({
//       where: {
//         customer_id: customerId,
//         status: {
//           [Op.in]: ["Approved", "Case to case"],
//         },
//       },
//     });

//     if (!buildCredit) return returnedResponse;

//     const creditLimit = parseFloat(buildCredit.credit_limit.replace(/,/g, ""));
//     if (creditLimit) ___creditLimit = creditLimit;

//     const _orderForms = await OrderForm.findAll({
//       attributes: [[Sequelize.fn("SUM", Sequelize.col("total_amount")), "totalAmount"]],
//       where: {
//         customer_id: customerId,
//         status: {
//           [Op.notIn]: ["Cancelled", "Denied"],
//         },
//         payment_method: {
//           [Op.in]: ["RPAF", "Build Credit", "BUILDCREDIT INTEREST", "EOS ORDER"],
//         },
//       },
//     });
//     if (_orderForms && _orderForms[0] && _orderForms[0].dataValues.totalAmount)
//       ___orderFormTotal = _orderForms[0].dataValues.totalAmount;

//     const __orderFormsSplit = await OrderForm.findAll({
//       attributes: ["id", "split_payment_id"],
//       where: {
//         customer_id: customerId,
//         status: {
//           [Op.notIn]: ["Cancelled", "Denied"],
//         },
//         payment_method: {
//           [Op.in]: ["Split"],
//         },
//       },
//     });

//     const orderFormIds = __orderFormsSplit.map((form) => form.split_payment_id);

//     const _splitPayments = await SplitPayments.findAll({
//       attributes: [[Sequelize.fn("SUM", Sequelize.col("rpaf_payment")), "totalAmount"]],
//       where: {
//         id: {
//           [Op.in]: orderFormIds,
//         },
//       },
//     });

//     if (_splitPayments && _splitPayments[0] && _splitPayments[0].dataValues.totalAmount)
//       ___orderFormSplitTotal = _splitPayments[0].dataValues.totalAmount;

//     const _rpafPayments = await RpafPayment.findAll({
//       where: {
//         customer_id: customerId,
//         status: "Verified",
//       },
//       attributes: [[Sequelize.fn("SUM", Sequelize.col("amount_paid")), "total_amount_paid"]],
//     });

//     if (_rpafPayments && _rpafPayments[0] && _rpafPayments[0].dataValues.total_amount_paid)
//       ___rpafPaymentTotal = _rpafPayments[0].dataValues.total_amount_paid;

//     // Buildcredit Beginning Balance
//     const customerDetail = await Customers.findOne({
//       where: {
//         id: customerId,
//       },
//       attributes: ["buildcredit_beginning_balance"],
//     });
//     const buildcreditBeginningBalance =
//       customerDetail?.buildcredit_beginning_balance != null
//         ? parseFloat(customerDetail.buildcredit_beginning_balance)
//         : 0;

//     const orderFormTotal =
//       parseFloat(___orderFormTotal) + parseFloat(___orderFormSplitTotal) + buildcreditBeginningBalance;
//     const orderFormSubTotal = parseFloat(orderFormTotal) - parseFloat(___rpafPaymentTotal);
//     ___overAllTotal = parseFloat(___creditLimit - orderFormSubTotal);

//     if (___overAllTotal < 1) ___overAllTotal = 0;
//     returnedResponse.credit_terms = buildCredit.credit_date_limit;
//     returnedResponse.approved_credit_limit = ___creditLimit;
//     returnedResponse.used_credit_limit = parseFloat(___creditLimit - ___overAllTotal);
//     returnedResponse.current_bal = ___overAllTotal;
//     returnedResponse.status = ___overAllTotal > 0;

//     return returnedResponse;
//   } catch (err) {
//     return err;
//   }
// };

exports.customerOrderAgain = async (req, res, next) => {
  const { customerId } = req;
  const { order_reference_no } = req.body;
  try {
    if (!order_reference_no)
      return res
        .status(400)
        .json({ success: false, message: "Invalid reference no." });

    const orderForm = await OrderForm.findOne({
      where: {
        reference_no: order_reference_no,
        customer_id: customerId,
      },
      include: [
        {
          model: OrderFormDetails,
          as: "order_form_details",
        },
      ],
    });

    if (
      orderForm &&
      orderForm.order_form_details &&
      Array.isArray(orderForm.order_form_details) &&
      orderForm.order_form_details.length > 0
    ) {
      const addToCartPromises = [];

      for (const orderFormDetail of orderForm.order_form_details) {
        // Check product if it is existing
        const product = await Products.findByPk(orderFormDetail.product_id);
        if (!product) continue;
        const sellerEnabledPO = await sellerEnabledPurchaseOrders(product.seller_id);

        let itemStock = parseFloat(product.stocks);

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

        if (parseFloat(orderFormDetail.quantity) > itemStock) continue;

        const addToCartPromise = UserCart.create({
          user_id: customerId,
          menu_id: product.id,
          quantity: parseFloat(orderFormDetail.quantity),
          price:
            product.discounted_price && product.discounted_price > 0
              ? product.discounted_price
              : product.price,
          has_sub_variation_chosen: "false",
          created_at: new Date(),
        });
        addToCartPromises.push(addToCartPromise);
      }

      await Promise.all(addToCartPromises);
      res.status(200).json({ success: true });
    }
  } catch (err) {
    next(err);
  }
};
