const Transaction = require('../models/Transaction');
const TransactionDetail = require('../models/TransactionDetail');
const BranchInventory = require('../models/BranchInventory');
const Item= require('../models/Item');
const Order= require('../models/Order');
const PaymentDetail= require('../models/PaymentDetail');
const PaymentHistory=require('../models/PaymentHistory')
exports.createTransaction = async (req, res) => {
  try {
    const { companyId, branchId, transactionType, 
      transactionDate, items, customerId, 
      totalItems, subtotal,orderId,paymentDetail } = req.body;

    // Convert the transactionDate to a Date object
    const date = new Date(transactionDate);


//console.log("sent data is",items);


    // Step 1: Validate each item's stock quantity before proceeding with the transaction
    if (transactionType === 'selling'||transactionType === 'using'|| transactionType==='ordering') {
    for (const item of items) {
      const branchInventory = await BranchInventory.findOne({ branchId, itemId: item.itemId });
       console.log("branch id is",branchInventory );
      // Check inventory only for selling transactions
    
        if (!branchInventory || branchInventory.quantity < item.quantity) {
          return res.status(400).json({
            success: false,
            message: `Insufficient stock for item ${item.name}. Available: ${branchInventory ? branchInventory.quantity : 0}, Requested: ${item.quantity}`,
          });
        }
  
    }
        }//

    // Step 2: Create a new transaction with a custom date


    const { cash, bank, credit, other, description } = paymentDetail

    const newPaymentDetail = new PaymentDetail({
      cash,
      bank,
      credit,
      other,
      description,
    });

    const savedPaymentDetail = await newPaymentDetail.save();
  
let savedTransaction;
    if(transactionType==='ordering')
    {
// include order Id

      const newOrderTransaction = new Transaction({
        companyId,
        branchId,
        orderId,// only for ordering...
        paymentId:savedPaymentDetail._id,
        customerId,
        totalItems,
        subtotal,
        transactionType,
        createdAt: date,
        updatedAt: date,
      });
  
       savedTransaction = await newOrderTransaction.save();

// update the order satus to served or true
 const updatedOrder = await Order.findByIdAndUpdate(
  orderId,
  { 
    status:true
  });



    }
    else
    {
    const newTransaction = new Transaction({
      companyId,
      branchId,
      customerId,
      paymentId:savedPaymentDetail._id,
      totalItems,
      subtotal,
      transactionType,
      createdAt: date,
      updatedAt: date,
    });

   savedTransaction = await newTransaction.save();
  }
    // Step 3: Save transaction details with avg_price and custom date
    const transactionDetailsPromises = items.map(async (item) => {
      // Find the item's avg_price from the Item collection

      const foundItem = await Item.findById(item.itemId);
      if (!foundItem) {
        throw new Error(`Item with ID ${item.itemId} not found.`);
      }

      // Calculate the profit as price - avg_price
      const profit = item.price - foundItem.avg_price;
      const profitMargin = ((profit / item.price) * 100).toFixed(2);

      return {
        transactionId: savedTransaction._id,
        companyId,
        branchId,
        itemId: item.itemId,
        name: item.name,
        code: item.code,
        quantity: item.quantity,
        balance: item.balance,
        price: item.price,
        avg_price: foundItem.avg_price, // Include avg_price
        profit, // Calculate profit
        profitMargin,
        total: item.total,
        transactionType: transactionType, // Include transaction type
        createdAt: date,
        updatedAt: date,
      };
    });

    const transactionDetails = await Promise.all(transactionDetailsPromises);
    await TransactionDetail.insertMany(transactionDetails);

    // Step 4: Update branch inventory for each item
    for (const item of items) {
      const updateOperation =( transactionType === 'ordering'|| transactionType === 'selling' ||transactionType === 'using')? -item.quantity : item.quantity;

      const inventoryUpdate = await BranchInventory.findOneAndUpdate(
        { branchId, itemId: item.itemId },
        { $inc: { quantity: updateOperation } },
        { new: true }
      );

      // If inventory doesn't exist, create it for the first time (only for purchasing and producing cases)
      if (!inventoryUpdate && (transactionType === 'purchasing'||transactionType === 'producing')) {
        await BranchInventory.create({
          companyId,
          branchId,
          itemId: item.itemId,
          quantity: item.quantity,
        });
      }
// add expire date if necessary 
if(item.expDate){
await Item.findByIdAndUpdate(
    item.itemId,
    { $push: { expDates: item.expDate } },

);}

    }

    // finally save customer paid and credit amount
    const totalAmount=cash+bank+other+credit;// this totally will be considerder as credit
    const customerPayment = new PaymentHistory({
     
    
      customerId,
      transactionId: savedTransaction._id,
      paid:(cash+bank+other),// paid amount sum of all this
    //  credit:credit,//
     credit:totalAmount,// the person purchased this amount of items and considered as credit befor paying
     date:date,
      });

      await customerPayment.save();

    res.status(201).json({ success: true, message: 'Transaction completed successfully!' });
  } catch (error) {
    console.error('Error creating transaction:', error);
    res.status(500).json({ message: 'Error creating transaction', error });
  }
};







// Get all transactions (for example)
exports.getTransactions = async (req, res) => {
  try {
    const transactions = await Transaction.find();
    res.status(200).json(transactions);
  } catch (error) {
    res.status(500).json({ message: 'Error retrieving transactions', error });
  }
};


// Get all transactions (for example)
exports.getTransaction = async (req, res) => {
  try {
    const transactionId=req.query.transactionId;
    const transaction = await Transaction.findById(transactionId).populate("paymentId");
    res.status(200).json(transaction);
  } catch (error) {
    res.status(500).json({ message: 'Error retrieving transactions', error });
  }
};


// Controller: Update transaction detail and main transaction in a single request
exports.updateTransactionDetail = async (req, res) => {
  try {
    // Call the reusable function to handle transaction detail updates
    const result = await exports.update_Transaction_Detail(req.body);

    // Respond with success
    res.status(200).json({ success: true, message: result.message });
  } catch (error) {
    console.error('Error updating transaction detail and summary:', error.message);
    res.status(500).json({ message: 'Error updating transaction detail and summary', error: error.message });
  }
};

exports.update_Transaction_Detail = async (data) => {
  try {
    const {
      //paymentId,
      _id, // ID of the transaction detail to be updated
      transactionId,
      itemId,
      branchId,
      updatedQuantity,
      updatedPrice,
      previousQuantity,
      transactionType, // 'selling', 'purchasing', 'using', or 'producing'
      updatedPaymentDetail 
    } = data;

const transaction=await Transaction.findById({_id:transactionId});


const paymentId=transaction.paymentId;

    // Calculate the difference in quantity
    const quantityDifference = updatedQuantity - previousQuantity;

    // Fetch branch inventory for the item
    const branchInventory = await BranchInventory.findOne({ branchId, itemId });
    if (!branchInventory) throw new Error('Branch inventory not found');

    // Find the transaction detail
    const transactionDetail = await TransactionDetail.findById(_id);
    if (!transactionDetail) throw new Error('Transaction detail not found');

    // Find the item for average price and profit calculation
    const foundItem = await Item.findById(itemId);
    if (!foundItem) throw new Error('Item not found');

    // Variables for profit and profit margin
    let updatedProfit = 0;
    let updatedProfitMargin = 0;

    // Handle 'selling' or 'using' transactions
    if (['selling', 'using'].includes(transactionType)) {
      updatedProfit = parseFloat((updatedPrice - foundItem.avg_price).toFixed(2));
      updatedProfitMargin = parseFloat(((updatedProfit / updatedPrice) * 100).toFixed(2));

      // Check inventory before updating
      if (quantityDifference > 0 && branchInventory.quantity < quantityDifference) {
        throw new Error(`Insufficient stock for item. Available quantity: ${branchInventory.quantity}`);
      }

      // Decrease inventory for 'selling' or 'using'
      await BranchInventory.findOneAndUpdate(
        { branchId, itemId },
        { $inc: { quantity: -quantityDifference } },
        { new: true }
      );
    } else if (['purchasing', 'producing'].includes(transactionType)) {
      // Increase inventory for 'purchasing' or 'producing'
      await BranchInventory.findOneAndUpdate(
        { branchId, itemId },
        { $inc: { quantity: quantityDifference } },
        { new: true }
      );
    }


// store values before update  for reverse case if neessary
 //   let {quantity,price,total,profit,profitMargin}=transactionDetail;

    // Update the transaction detail
    transactionDetail.quantity = updatedQuantity;
    transactionDetail.price = updatedPrice;
    transactionDetail.total = updatedQuantity * updatedPrice;
    transactionDetail.profit = transactionType === 'selling' || transactionType === 'using' ? updatedProfit : 0;
    transactionDetail.profitMargin = transactionType === 'selling' || transactionType === 'using' ? updatedProfitMargin : 0;
   

    await transactionDetail.save();

    // Fetch all transaction details for the main transaction
    const allTransactionDetails = await TransactionDetail.find({ transactionId });


    // Calculate updated totals
    const updatedTotalItems = allTransactionDetails.reduce((acc, detail) => acc + detail.quantity, 0);
    const updatedSubtotal = allTransactionDetails.reduce((acc, detail) => acc + detail.total, 0);


// check  updatedsubtotal with payment detail 

const { cash, bank, credit, other,  description} =updatedPaymentDetail ;

// let payment=cash+bank+credit+other;


// if (parseInt(payment, 10) !== parseInt(updatedSubtotal, 10)) 
// {
// //reverese and return
// // what about reversing inventory quantity and other issues?
// transactionDetail.quantity = quantity;// previous or orginal quantity
// transactionDetail.price = price;
// transactionDetail.total = total ;
// transactionDetail.profit = profit 
// transactionDetail.profitMargin = profitMargin;
// //    first 600, 100 kenese, mehon yalebt totalu 500
// //
// //

// await transactionDetail.save();

// return { message: 'subtotal did not much with total payment in payment detail' };
// }




// update payment detail after insuring all necessary checking


    // Update the main transaction
 await Transaction.findByIdAndUpdate(transactionId, {
      totalItems: updatedTotalItems,
      subtotal: updatedSubtotal,
      updatedAt: new Date(),
    });




    if(paymentId){
    await PaymentDetail.findByIdAndUpdate(paymentId,{
      cash,
      bank,
      credit,
      other,
      description,
    });
    
  }




    return { message: 'Transaction detail and summary updated successfully' };
  } catch (error) {
    console.error('Error updating transaction detail:', error.message);
    throw new Error(error.message || 'Failed to update transaction detail');
  }
};





//  // Calculate the difference in quantity
//  const quantityDifference = updatedQuantity - previousQuantity;

//  // Fetch branch inventory for the item
//  const branchInventory = await BranchInventory.findOne({ branchId, itemId });

//  if (!branchInventory) {
//    return res.status(404).json({ message: 'Branch inventory not found' });
//  }

//  // Find and update transaction detail
//  const transactionDetail = await TransactionDetail.findById(_id);
//  if (!transactionDetail) {
//    return res.status(404).json({ message: 'Transaction detail not found' });
//  }

//  // Find the item to get avg_price for calculating profit and profit margin
//  const foundItem = await Item.findById(itemId);
//  if (!foundItem) {
//    return res.status(404).json({ message: 'Item not found' });
//  }

//  // Initialize variables for profit and profit margin
//  let updatedProfit, updatedProfitMargin;

//  // Logic for selling transactions
//  if (transactionType === 'selling'||transactionType === 'using') {
//    updatedProfit = (updatedPrice - foundItem.avg_price) 
//    updatedProfitMargin = ((updatedProfit / updatedPrice) * 100).toFixed(2);

//    // Check inventory before updating (only for selling transactions)
//    if (quantityDifference > 0 && branchInventory.quantity < quantityDifference) {
//      return res.status(400).json({ message: `Insufficient stock for item. Available quantity: ${branchInventory.quantity}` });
//    }

//    // Adjust branch inventory (decrease for selling)
//    await BranchInventory.findOneAndUpdate(
//      { branchId, itemId },
//      { $inc: { quantity: -quantityDifference } },
//      { new: true }
//    );
//  }

//  // Logic for purchasing transactions
//  else if (transactionType === 'purchasing'||transactionType === 'producing') {
//    // Adjust branch inventory (increase for purchasing)
//    await BranchInventory.findOneAndUpdate(
//      { branchId, itemId },
//      { $inc: { quantity: quantityDifference } },
//      { new: true }
//    );

//    // Set profit and profit margin to null or 0 as they are not needed for purchasing
//    updatedProfit = 0;
//    updatedProfitMargin = 0;
//  }

//  // Update the transaction detail
//  transactionDetail.quantity = updatedQuantity;
//  transactionDetail.price = updatedPrice;
//  transactionDetail.total = updatedQuantity * updatedPrice;

//  // Only set profit and profit margin for selling transactions
//  if (transactionType === 'selling') {
//    transactionDetail.profit = updatedProfit;
//    transactionDetail.profitMargin = updatedProfitMargin;
//  } else {
//    transactionDetail.profit = 0;
//    transactionDetail.profitMargin = 0;
//  }

//  await transactionDetail.save();

//  // Fetch all updated transaction details linked to the main transaction
//  const allTransactionDetails = await TransactionDetail.find({ transactionId });

//  // Calculate updated total items and subtotal
//  const updatedTotalItems = allTransactionDetails.reduce((acc, detail) => acc + detail.quantity, 0);
//  const updatedSubtotal = allTransactionDetails.reduce((acc, detail) => acc + detail.total, 0);

//  // Update the main transaction with new totals
//  await Transaction.findByIdAndUpdate(transactionId, {
//    totalItems: updatedTotalItems,
//    subtotal: updatedSubtotal,
//    updatedAt: new Date(),
//  });





// // Controller: Update transaction detail and main transaction in a single request
// exports.updateTransactionDetail = async (req, res) => {
//   try {
//     const {
//       _id, // ID of the transaction detail to be updated
//       transactionId,
//       itemId,
//       branchId,
//       updatedQuantity,
//       updatedPrice,
//       previousQuantity,
//       previousPrice,
//     } = req.body;

//     // Calculate the difference in quantity
//     const quantityDifference = updatedQuantity - previousQuantity;

//     // Fetch branch inventory for the item
//     const branchInventory = await BranchInventory.findOne({ branchId, itemId });

//     if (!branchInventory) {
//       return res.status(404).json({ message: 'Branch inventory not found' });
//     }

//     // Check inventory before updating (only for selling transactions)
//     if (quantityDifference > 0 && branchInventory.quantity < quantityDifference) {
//       return res.status(400).json({ message: `Insufficient stock for item. Available quantity: ${branchInventory.quantity}` });
//     }

//     // Find and update transaction detail
//     const transactionDetail = await TransactionDetail.findById(_id);
//     if (!transactionDetail) {
//       return res.status(404).json({ message: 'Transaction detail not found' });
//     }

//     // Find the item to get avg_price for calculating profit and profit margin
//     const foundItem = await Item.findById(itemId);
//     if (!foundItem) {
//       return res.status(404).json({ message: 'Item not found' });
//     }

//     // Calculate profit and profit margin based on updated price
//     const updatedProfit = (updatedPrice - foundItem.avg_price) * updatedQuantity;
//     const updatedProfitMargin = ((updatedProfit / (updatedPrice * updatedQuantity)) * 100).toFixed(2);

//     // Update the transaction detail
//     transactionDetail.quantity = updatedQuantity;
//     transactionDetail.price = updatedPrice;
//     transactionDetail.total = updatedQuantity * updatedPrice;
//     transactionDetail.profit = updatedProfit; // Update profit
//     transactionDetail.profitMargin = updatedProfitMargin; // Update profit margin

//     await transactionDetail.save();

//     // Adjust branch inventory
//     await BranchInventory.findOneAndUpdate(
//       { branchId, itemId },
//       { $inc: { quantity: -quantityDifference } },
//       { new: true }
//     );

//     // Fetch all updated transaction details linked to the main transaction
//     const allTransactionDetails = await TransactionDetail.find({ transactionId });

//     // Calculate updated total items, subtotal, total profit, and profit margin for the main transaction
//     const updatedTotalItems = allTransactionDetails.reduce((acc, detail) => acc + detail.quantity, 0);
//     const updatedSubtotal = allTransactionDetails.reduce((acc, detail) => acc + detail.total, 0);
   
//     // Update the main transaction with new totals
//     await Transaction.findByIdAndUpdate(transactionId, {
//       totalItems: updatedTotalItems,
//       subtotal: updatedSubtotal,
    
//       updatedAt: new Date()
//     });

//     res.status(200).json({ success: true, message: 'Transaction detail and summary updated successfully!' });
//   } catch (error) {
//     console.error('Error updating transaction detail and summary:', error);
//     res.status(500).json({ message: 'Error updating transaction detail and summary', error });
//   }
// };


