const OrderForm = require("../../models/OrderForm");
const OrderFormDetails = require("../../models/OrderFormDetails");
const Vouchers = require("../../models/Vouchers");
const Customers = require("../../models/Customers");
const Product = require("../../models/Products");
const buildCreditService = require("../../helpers/buildcredit");
const SellerBadOrderContainer = require("../../models/SellerBadOrderContainer");

exports.importOrders = async (req, res, next) => {
  try {
    const { customerId, voucherCode, shippingMethod, jsonData } = req.body;

    const customerPromise = Customers.findByPk(customerId);
    const voucherPromise = Vouchers.findOne({
      where: {
        voucher_code: voucherCode,
      },
    });

    const shippingMethods = ["Standard Shipping", "Pick-up"];

    if (!shippingMethods.includes(shippingMethod))
      return res
        .status(400)
        .json({ success: false, message: "Invalid Shipping Method" });

    const [customer, voucher] = await Promise.all([
      customerPromise,
      voucherPromise,
    ]);

    if (!customer)
      return res
        .status(400)
        .json({ success: false, message: "Invalid Customer" });

    const buildCredit = await buildCreditService.getBuildCreditBalance(
      customer.id
    );

    if (buildCredit && buildCredit.current_bal === 0) {
      return res.status(400).json({
        success: false,
        message: "No Buildcredit found for this Customer",
      });
    }
    if (voucherCode) {
      if (!voucher)
        return res
          .status(400)
          .json({ success: false, message: "Invalid Voucher Code" });
    }

    let successCount = 0;
    let failedCount = 0;
    if (jsonData) {
      const reference_no =
        "ORD-IM" + Math.random().toString(36).substring(2, 10).toUpperCase();

      const orderForm = await OrderForm.create({
        email: customer.email,
        name: `${customer.first_name} ${customer.last_name}`,
        customer_id: customer.id,
        contact_number: customer.contact_number,
        pickup_date: new Date(),
        encode_date: new Date(),
        reference_no: reference_no,
        status: "Verified",
        payment_method: "Build Credit",
        address: customer.address,
        longitude: customer.longitude,
        latitude: customer.latitude,
        date_created: new Date(),
        delivery_fee: 0,
        shipping_type: shippingMethod,
        voucher_id_used: voucher ? voucher.id : null,
      });

      let cleanedOrderDetail = [];
      let orderTotalAmount = 0;
      let orderTotalQty = 0;
      let seller_id = null;
      const parsedJsonData = JSON.parse(jsonData);
      for (const data of parsedJsonData) {
        const { productID, originalPrice, quantity, totalAmount } = data;
        if (!productID || !originalPrice || !quantity || !totalAmount) {
          failedCount += 1;
          await orderForm.destroy();
          return res.status(400).json({
            success: false,
            message:
              "Either ProductID / Original Price / Quantity / Total Amount is empty or invalid.",
            details: `PRODUCT ID: ${productID}, ORIG PRICE: ${originalPrice}, QUANTITY: ${quantity}, TOTAL AMOUNT: ${totalAmount}`,
          });
        }

        const parsedPrice = parseFloat(originalPrice);
        const parsedQuantity = parseFloat(quantity);
        const parsedTotalAmount = parseFloat(totalAmount);

        if (
          isNaN(parsedPrice) ||
          parsedPrice <= 0 ||
          isNaN(parsedQuantity) ||
          parsedQuantity <= 0 ||
          isNaN(parsedTotalAmount) ||
          parsedTotalAmount <= 0
        ) {
          failedCount += 1;
          await orderForm.destroy();
          return res.status(400).json({
            success: false,
            message:
              "Either ProductID / Original Price / Quantity / Total Amount is empty or invalid.",
            details: `PRODUCT ID: ${productID}, PARSED ORIG PRICE: ${parsedPrice}, PARSED QUANTITY: ${parsedQuantity}, PARSED TOTAL AMOUNT: ${parsedTotalAmount}`,
          });
        }

        const product = await Product.findByPk(productID);

        if (!product) {
          failedCount += 1;
          await orderForm.destroy();
          return res.status(400).json({
            success: false,
            message:
              "Either ProductID / Original Price / Quantity / Total Amount is empty or invalid.",
            details: `PRODUCT ID: ${productID}`,
          });
        }

        cleanedOrderDetail.push({
          order_form_id: orderForm.id,
          product_id: productID,
          quantity: parsedQuantity,
          price: parsedPrice,
          amount: parsedTotalAmount,
        });
        orderTotalQty += parsedQuantity;
        orderTotalAmount += parsedTotalAmount;
        seller_id = product.seller_id;
      }

      if (orderTotalAmount > buildCredit.current_bal) {
        await orderForm.destroy();
        return res.status(400).json({
          success: false,
          message: "Buildcredit Balance for this customer is insufficient",
        });
      }
      const orderDetailPromises = await OrderFormDetails.bulkCreate(
        cleanedOrderDetail
      );
      orderForm.subtotal_amount = orderTotalAmount;
      orderForm.total_amount = orderTotalAmount;
      orderForm.total_qty = orderTotalQty;
      orderForm.seller_id = seller_id;
      successCount = cleanedOrderDetail.length;

      await orderForm.save();

      res.status(200).json({
        success: true,
        order: {
          reference_no: orderForm.reference_no,
          total_amount: orderForm.total_amount,
        },
        count: {
          success: successCount,
          failed: failedCount,
        },
      });
    }
  } catch (err) {
    next(err);
  }
};

const fs = require("fs");
const path = require("path");
const csv = require("csv-parser");
const sequelizeConnection = require("../../connection/db");
const SellersCompany = require("../../models/SellersCompany");
const { generateReferenceNumber } = require("../../helpers/common");

exports.keyPairing = [
  async (req, res, next) => {
    const t = await sequelizeConnection.transaction();
    try {
      const { keypairerFile } = req.files;
      if (!keypairerFile) {
        return res.status(400).json({ error: "No file uploaded" });
      }

      const filePath = path.join(keypairerFile[0].path);

      const results = await new Promise((resolve, reject) => {
        const rows = [];

        fs.createReadStream(filePath)
          .pipe(
            csv({
              separator: ",",
              mapHeaders: ({ header }) => header.trim(),
            })
          )
          .on("data", (row) => {
            rows.push({
              id: row.id,
              seller_id: row.seller_id,
              seller_name: row.seller_name,
              thd_id: row.thd_id || null,
              menu: row.menu,
              description: row.description,
              price: parseFloat(row.price) || 0,
              discounted_price: parseFloat(row.discounted_price) || 0,
              quantity_limit: parseInt(row.quantity_limit) || 0,
              stocks: parseInt(row.stocks) || 0,
            });
          })
          .on("end", () => {
            fs.unlinkSync(filePath);
            resolve(rows);
          })
          .on("error", (err) => {
            fs.unlinkSync(filePath);
            reject(err);
          });
      });

      const filteredResults = results.filter((r) => {
        const val = (r.thd_id || "").trim().toUpperCase();
        return val !== "" && val !== "NULL" && val !== "NULL ";
      });

      for (const result of filteredResults) {
        await Product.update(
          { secondary_id: result.thd_id },
          { where: { id: result.id }, transaction: t }
        );
      }

      await t.commit();
      res.json({ data: filteredResults });
    } catch (err) {
      await t.rollback();
      next(err);
    }
  },
];

exports.verifyDataIntegrity = async (req, res, next) => {
  const { data = [], sellerID } = req.body;

  if (!Array.isArray(data)) {
    return res.status(400).json({
      success: false,
      message: "Invalid data format: Expected an array",
    });
  }

  try {
    const results = await Promise.all(
      data.map(async (item) => {
        const { secondaryID } = item;

        const product = await Product.findOne({
          where: { secondary_id: secondaryID, seller_id: sellerID },
          attributes: ["id"],
        });

        return {
          ...item,
          buildhubID: product ? product.id : null,
        };
      })
    );

    res.status(200).json({
      success: true,
      results,
    });
  } catch (err) {
    console.error("Verification failed:", err);
    next(err);
  }
};

exports.importOrders2 = async (req, res, next) => {
  const transaction = await sequelizeConnection.transaction();
  try {
    const {
      customerID,
      sellerID,
      shippingMethod,
      voucherCode,
      agentCode,
      data,
      adminToken,
      orderInstructions,
    } = req.body;

    if (!customerID || !sellerID || !shippingMethod || !data) {
      await transaction.rollback();
      return res.status(400).json({
        success: false,
        message: "Missing required fields",
      });
    }

    const customerPromise = Customers.findByPk(customerID, { transaction });
    const sellerPromise = SellersCompany.findByPk(sellerID, { transaction });
    const voucherPromise = voucherCode
      ? Vouchers.findOne({
          where: { voucher_code: voucherCode },
          transaction,
        })
      : Promise.resolve(null);
    const referenceNoPromise = generateReferenceNumber();

    const [customer, seller, voucher, referenceNo] = await Promise.all([
      customerPromise,
      sellerPromise,
      voucherPromise,
      referenceNoPromise,
    ]);

    if (!customer || !seller) {
      await transaction.rollback();
      return res.status(200).json({
        success: false,
        message: "Invalid Customer or Seller ID",
      });
    }

    const validShippingMethods = ["Standard Shipping", "Pick-up"];
    if (!validShippingMethods.includes(shippingMethod)) {
      await transaction.rollback();
      return res.status(200).json({
        success: false,
        message: "Invalid shipping method",
      });
    }

    if (!Array.isArray(data) || data.length === 0) {
      await transaction.rollback();
      return res.status(200).json({
        success: false,
        message: "Order items are required",
      });
    }

    const orderForm = await OrderForm.create(
      {
        email: customer.email,
        name: `${customer.first_name} ${customer.last_name}`,
        customer_id: customer.id,
        agentCode: agentCode ?? null,
        contact_number: customer.contact_number,
        pickup_date: new Date(),
        encode_date: new Date(),
        reference_no: referenceNo,
        status: "Verified",
        payment_method: "Build Credit",
        address: customer.address,
        longitude: customer.longitude,
        latitude: customer.latitude,
        date_created: new Date(),
        delivery_fee: 0,
        shipping_type: shippingMethod,
        voucher_id_used: voucher ? voucher.id : null,
        seller_id: seller.id,
        is_v2_order: true,
        imported_by_admin_token: adminToken,
        proof_of_payment: orderInstructions || null,
      },
      { transaction }
    );

    const orderFormDetails = [];
    let orderTotalAmount = 0;
    let orderTotalQty = 0;

    for (const d of data) {
      const { buildhubID, qty, price, discountedPrice, totalAmount } = d;

      const parsedQuantity = parseFloat(qty);
      const parsedPrice = parseFloat(price);
      const parsedDiscountedPrice = parseFloat(discountedPrice);
      const parsedTotalAmount = parseFloat(totalAmount);

      await OrderFormDetails.create(
        {
          order_form_id: orderForm.id,
          product_id: buildhubID,
          quantity: parsedQuantity,
          price: parsedPrice,
          discounted_price: parsedDiscountedPrice,
          amount: parsedTotalAmount,
        },
        { transaction }
      );

      orderTotalAmount += parsedTotalAmount;
      orderTotalQty += parsedQuantity;
    }

    await orderForm.update(
      {
        subtotal_amount: orderTotalAmount,
        total_amount: orderTotalAmount,
        total_quantity: orderTotalQty,
      },
      { transaction }
    );

    await transaction.commit();

    return res.status(200).json({
      success: true,
      message: "Order created successfully",
      orderId: orderForm.id,
      referenceNo: orderForm.reference_no,
    });
  } catch (err) {
    await transaction.rollback();
    next(err);
  }
};

exports.updateToBadOrder = async (req, res, next) => {
  try {
    const sellerCompanyContainer = await SellerBadOrderContainer.findOne({
      where: {
        status: true,
      },
    });

    if (!sellerCompanyContainer)
      return res
        .status(200)
        .json({ success: false, message: "No Seller Container Found." });

    const { order_reference_no, admin_token } = req.body;

    if (!order_reference_no)
      return res.status(200).json({
        success: false,
        message: "Order Form Reference No is required.",
      });

    const orderForm = await OrderForm.findOne({
      where: {
        reference_no: order_reference_no,
      },
    });
    if (!orderForm)
      return res.status(200).json({
        success: false,
        message: "Order Form Reference No not found.",
      });

    orderForm.seller_id = sellerCompanyContainer.seller_id;
    orderForm.status = "Bad Order";
    orderForm.admin_remarks = `Executed by: ${admin_token}`;

    await orderForm.save();

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