const Product = require("../models/Product");
const StockTransaction = require("../models/StockTransaction");

const applyStockMovement = async (productId, transactionType, quantityMoved) => {
  const product = await Product.findById(productId);

  if (!product) {
    throw new Error("Selected product was not found");
  }

  const quantity = Number(quantityMoved);
  const newQuantity =
    transactionType === "Stock In"
      ? product.quantityInStock + quantity
      : product.quantityInStock - quantity;

  if (newQuantity < 0) {
    throw new Error("Stock out quantity cannot be greater than available stock");
  }

  product.quantityInStock = newQuantity;
  await product.save();
};

const reverseStockMovement = async (transaction) => {
  const oppositeType = transaction.transactionType === "Stock In" ? "Stock Out" : "Stock In";
  await applyStockMovement(transaction.product, oppositeType, transaction.quantityMoved);
};

const createTransaction = async (req, res) => {
  try {
    const transaction = new StockTransaction(req.body);
    await transaction.validate();
    await applyStockMovement(req.body.product, req.body.transactionType, req.body.quantityMoved);
    await transaction.save();
    const savedTransaction = await transaction.populate("product warehouse");

    res.status(201).json({
      message: "Stock transaction recorded successfully",
      transaction: savedTransaction
    });
  } catch (error) {
    res.status(400).json({ message: "Transaction was not recorded", error: error.message });
  }
};

const getTransactions = async (req, res) => {
  try {
    const transactions = await StockTransaction.find()
      .populate("product warehouse")
      .sort({ transactionDate: -1, createdAt: -1 });

    res.json(transactions);
  } catch (error) {
    res.status(500).json({ message: "Transactions could not be retrieved", error: error.message });
  }
};

const updateTransaction = async (req, res) => {
  try {
    const transaction = await StockTransaction.findById(req.params.id);

    if (!transaction) {
      return res.status(404).json({ message: "Transaction was not found" });
    }

    const previousTransaction = {
      product: transaction.product,
      transactionType: transaction.transactionType,
      quantityMoved: transaction.quantityMoved
    };

    transaction.product = req.body.product;
    transaction.warehouse = req.body.warehouse;
    transaction.transactionDate = req.body.transactionDate;
    transaction.quantityMoved = req.body.quantityMoved;
    transaction.transactionType = req.body.transactionType;
    await transaction.validate();

    await applyStockMovement(
      previousTransaction.product,
      previousTransaction.transactionType === "Stock In" ? "Stock Out" : "Stock In",
      previousTransaction.quantityMoved
    );

    try {
      await applyStockMovement(req.body.product, req.body.transactionType, req.body.quantityMoved);
    } catch (error) {
      await applyStockMovement(
        previousTransaction.product,
        previousTransaction.transactionType,
        previousTransaction.quantityMoved
      );
      throw error;
    }

    await transaction.save();

    const updatedTransaction = await transaction.populate("product warehouse");
    res.json({ message: "Transaction updated successfully", transaction: updatedTransaction });
  } catch (error) {
    res.status(400).json({ message: "Transaction was not updated", error: error.message });
  }
};

const deleteTransaction = async (req, res) => {
  try {
    const transaction = await StockTransaction.findById(req.params.id);

    if (!transaction) {
      return res.status(404).json({ message: "Transaction was not found" });
    }

    await reverseStockMovement(transaction);
    await StockTransaction.findByIdAndDelete(req.params.id);

    res.json({ message: "Transaction deleted successfully" });
  } catch (error) {
    res.status(400).json({ message: "Transaction was not deleted", error: error.message });
  }
};

module.exports = {
  createTransaction,
  getTransactions,
  updateTransaction,
  deleteTransaction
};
