const moment = require("moment");
const JobCost = require("../models/jobCost");
const Admin = require("../models/admin");
const Products = require("../models/product");
const { empty } = require("../Helpers/Common");
const Projects = require("../models/Projects");
const Teams = require("../models/teams");
const ProjectTasks = require("../models/projectTask");
const CustomerOrderProduct = require("../models/customerOrderProduct.js");
const CustomerOrder = require("../models/customerOrder.js");
const Recipe=require("../models/recipe");
const Request=require("../models/request");
const Driver = require('../models/driver')
let currentDate = moment().unix();
const {
  clientId,
  clientSecret,
  redirectUri,
  authCode,
  companyId,
  accessToken,
  refreshToken,
  getNewAccessToken,
  realmId,
  // findCustomerIdByName,
  // findItemIdByName,
  ensureValidAccessToken,
  PRODUCTION,
  discountAccRefId,
  getAccounts,
  materialExpAccId,
  materialAssetAccId,
  materialIncAccId,
  serviceIncAccId,
  serviceExpAccId,
  catalogIncAccId,
  catalogExpAccId,
  findAccountIdByAcctNum,
  departmentId
} = require('../quickbook/quickbook.js');
const axios = require('axios');
const { parse } = require("dotenv");
const { filteredSignwiseInstalations } = require("../Helpers/SplitManagementHelper.js");
const RequestActivity = require("../models/RequestActivity.js");
const { FACILITY_ID } = require("../config/SplitManagementDb.js");


///////////////////////////QB

const sanitizeLog = (s) => s.replace(/\u2192/g, '->');

const addJournalEntryToQuickBooks = async ({ amount, requestId, journalEntryValue,description,
        debitAccount,debitAccountId,creditAccount,creditAccountId,projectTypeQuickBookId,docNumber }) => {
  console.log('amountamountamount',amount,journalEntryValue)
  const token = await getNewAccessToken();
  const apiUrl = PRODUCTION
    ? `https://quickbooks.api.intuit.com/v3/company/${realmId}`
    : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}`;

  const date = moment().format('YYYY-MM-DD');

const transactionCount = await Projects.getTransactionCountByProjectId(null,requestId);

let futureTransactionCount = Number(transactionCount);
// let journalNumber = null;
// if(transactionCount == 0 || !transactionCount){
//   journalNumber = docNumber;
// }else{
  futureTransactionCount = Number(futureTransactionCount) + 1;
  let journalNumber = docNumber + '-' + futureTransactionCount;
// }

  const journalEntryData = {
    DocNumber: journalNumber,
    Line: [
      {
        Id: "1",
        Description: description,
        Amount: amount,
        DetailType: "JournalEntryLineDetail",
        JournalEntryLineDetail: {
          PostingType: "Debit",
          AccountRef: { value: debitAccountId, name: debitAccount },
          DepartmentRef: { value: departmentId },
          ClassRef: { value: projectTypeQuickBookId },
        }
      },
      {
        Id: "2",
        Description: description,
        Amount: amount,
        DetailType: "JournalEntryLineDetail",
        JournalEntryLineDetail: {
          PostingType: "Credit",
          AccountRef: { value: creditAccountId, name: creditAccount },
          DepartmentRef: { value: departmentId },
          ClassRef: { value: projectTypeQuickBookId },
        }
      }
    ],
    TxnDate: date,
    PrivateNote: description
  };
try{
  const response = await axios.post(`${apiUrl}/journalentry`, journalEntryData, {
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json',
      'Content-Type': 'application/json'
    }
  });
  console.log('joCostData=== job progress ✅ Journal entry posted:', response.data);
  const updateProject = await Projects.updateProjectByRequestId(requestId, { qb_transaction_count: futureTransactionCount });

}catch(error){
  console.log('error in addJournalEntryToQuickBooks', error);
}
};

// const addJournalEntryToQuickBooksJobCompleted = async ({
//   amountMaterials,
//   amountLabor,
//   requestId,
//   joCostData
// }) => {
//   try{

  
//   const token = await getNewAccessToken();
//   const apiUrl = PRODUCTION
//     ? `https://quickbooks.api.intuit.com/v3/company/${realmId}`
//     : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}`;

//   const date = moment().format('YYYY-MM-DD');

//   // Total amount = materials + labor
//   const totalAmount = parseFloat(amountMaterials) + parseFloat(amountLabor);
//    const description = `Job "${joCostData.name}" has been updated with an amount of $${totalAmount}.`;
//    const MaterialDescription = `Job "${joCostData.name}" has been updated with a product amount of $${amountMaterials}.`;
//    const ServiceDescription = `Job "${joCostData.name}" has been updated with a labor amount of $${amountLabor}.`;

//    let finishedGoodsInvAccountId = await findAccountIdByAcctNum(1014300); // Finished Goods Inventory
//   //  let wipMaterialAccountId = await findAccountIdByAcctNum(1014000) // WIP – Materials
//   //  let wipLaborAccountId = await findAccountIdByAcctNum(1014000) // WIP – Labor
//    let workInProgressAccountId = await findAccountIdByAcctNum(1014000)

//   const journalEntryData = {
//     Line: [
//       {
//         Id: "1",
//         Description: description,
//         Amount: totalAmount,
//         DetailType: "JournalEntryLineDetail",
//         JournalEntryLineDetail: {
//           PostingType: "Debit",
//           AccountRef: { value:finishedGoodsInvAccountId },
//           DepartmentRef: { value: departmentId },
//         }
//       },
//       {
//         Id: "2",
//         Description: MaterialDescription,
//         Amount: parseFloat(amountMaterials),
//         DetailType: "JournalEntryLineDetail",
//         JournalEntryLineDetail: {
//           PostingType: "Credit",
//           AccountRef: { value:workInProgressAccountId },
//           DepartmentRef: { value: departmentId },
//         }
//       },
//       // {
//       //   Id: "3",
//       //   Description: ServiceDescription,
//       //   Amount: parseFloat(amountLabor),
//       //   DetailType: "JournalEntryLineDetail",
//       //   JournalEntryLineDetail: {
//       //     PostingType: "Credit",
//       //     AccountRef: { value:wipLaborAccountId || "1150040010", name: "WIP – Labor" },
//       //     DepartmentRef: { value: departmentId },
//       //   }
//       // }
//     ],
//     TxnDate: date,
//     PrivateNote: description
//   };

//   const response = await axios.post(`${apiUrl}/journalentry`, journalEntryData, {
//     headers: {
//       Authorization: `Bearer ${token}`,
//       Accept: 'application/json',
//       'Content-Type': 'application/json'
//     }
//   });

//   console.log('joCostData=== job completed✅ Journal entry posted:', response.data);
// } catch (error) {
//   console.log("Error creating journal entry for job completed", error);
// }
// };

const addJournalEntryToQuickBooksJobCompleted = async ({
  amountMaterials,
  amountLabor,
  requestId,
  joCostData
}) => {
  try {
    const token = await getNewAccessToken();
    const apiUrl = PRODUCTION
      ? `https://quickbooks.api.intuit.com/v3/company/${realmId}`
      : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}`;

    const date = moment().format('YYYY-MM-DD');

    const totalAmount = parseFloat(amountMaterials) + parseFloat(amountLabor);
    const description = `Job "${joCostData?.name}" has been updated with an amount of $${totalAmount}.`;
    const MaterialDescription = `Job "${joCostData?.name}" has been updated with a product amount of $${amountMaterials}.`;
    const ServiceDescription = `Job "${joCostData?.name}" has been updated with a labor amount of $${amountLabor}.`;

    let finishedGoodsInvAccountId = await findAccountIdByAcctNum(1014300); // Finished Goods Inventory
    let workInProgressAccountId = await findAccountIdByAcctNum(1014000); // WIP – Materials

    console.log('Finished Goods Account ID:', finishedGoodsInvAccountId);
    console.log('WIP Account ID:', workInProgressAccountId);
    let docNumber = joCostData.doc_number;
    let transactionCount = await Projects.getTransactionCountByProjectId(null,requestId);
    
    let futureTransactionCount = Number(transactionCount) + 1;
    let journalNumber = docNumber + '-' + futureTransactionCount;

    const journalEntryData = {
      DocNumber: journalNumber,
      Line: [
        {
          Id: "1",
          Description: description,
          Amount: parseFloat(totalAmount),
          DetailType: "JournalEntryLineDetail",
          JournalEntryLineDetail: {
            PostingType: "Debit",
            AccountRef: { value: finishedGoodsInvAccountId },
            DepartmentRef: { value: departmentId },
            ClassRef: { value: joCostData.projectTypeQuickBookId },
          }
        },
        {
          Id: "2",
          Description: MaterialDescription,
          Amount: parseFloat(totalAmount),
          DetailType: "JournalEntryLineDetail",
          JournalEntryLineDetail: {
            PostingType: "Credit",
            AccountRef: { value: workInProgressAccountId },
            DepartmentRef: { value: departmentId },
            ClassRef: { value: joCostData.projectTypeQuickBookId },
          }
        },
      ],
      TxnDate: date,
      PrivateNote: description
    };

    const response = await axios.post(`${apiUrl}/journalentry`, journalEntryData, {
      headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
        'Content-Type': 'application/json'
      }
    });

    console.log('Job completed ✅ Journal entry posted:', response.data);
    const updateProject = await Projects.updateProjectByRequestId(requestId, { qb_transaction_count: futureTransactionCount });
  } catch (error) {
    console.error("Error creating journal entry for job completed", error.response?.data || error.message);
    if (error.response?.data?.Fault) {
      console.error("QuickBooks Fault:", JSON.stringify(error.response.data.Fault, null, 2));
    }
  }
};

// (async () => {
//   const response = await addJournalEntryToQuickBooksJobCompleted({
//     amountMaterials :100,
//     amountLabor :100,
//     requestId:1,
//     joCostData:{name:"Test Job"},
//     projectTypeQuickBookId:"1149228"
//   })
//   console.log('response', response)
// })()

const hanldeMaterialJobCost =async(joCostData,productTotal,previosProductTotal,requestId,journalEntryValueMain,total)=>{
    if(Number(productTotal) > Number(previosProductTotal)){
      let amount = parseFloat(productTotal - previosProductTotal).toFixed(2);
      //for 0 - 100% completion of a job
      let  journalEntryValue =1
      const description = `Job "${joCostData.name}" has been updated with an amount of $${amount}.`;

  
   let debitAccount = "Work In Progress";
   let creditAccount = "Inventory";
   let debitAccountId =await findAccountIdByAcctNum(1014000)
   let creditAccountId =await findAccountIdByAcctNum(1013000)


      await addJournalEntryToQuickBooks({
        amount,
        requestId,
        journalEntryValue,
        description,
        debitAccount,
        debitAccountId,
        creditAccount,
        creditAccountId,
        projectTypeQuickBookId:joCostData.projectTypeQuickBookId,
        docNumber:joCostData.doc_number
      });

    }else{
      console.log("Already journal entry created -no change in material job cost 1");
    }
}

const hanldeServiceJobCost =async(joCostData,serviceTotal,previosServiceTotal,requestId,journalEntryValueMain,total)=>{
    if(Number(serviceTotal) > Number(previosServiceTotal)){
      let amount = parseFloat(serviceTotal - previosServiceTotal).toFixed(2);
      //for 0 - 100% completion of a job
      let  journalEntryValue =1
      const description = `Job "${joCostData.name}" has been updated with an amount of $${amount}.`;
    
   let debitAccount = "Work In Progress";
   let creditAccount = "Split Labor";
   let debitAccountId = await findAccountIdByAcctNum(1014000)
   let creditAccountId =await findAccountIdByAcctNum(5081000)

      await addJournalEntryToQuickBooks({
        amount,
        requestId,
        journalEntryValue,
        description,
        debitAccount,
        debitAccountId,
        creditAccount,
        creditAccountId,
        projectTypeQuickBookId:joCostData.projectTypeQuickBookId,
        docNumber:joCostData.doc_number
      });


    }else{
      console.log("Already journal entry created -no change in service job cost");
    }
}

const createJornalEntryForJobCost = async(requestId,previosJobCostTotal,previosProductTotal,previosServiceTotal) => {
  try {
    console.log('joCostData=== requestId',requestId)
    let joCostData = await Request.getJobCostDetailsForMaterials(requestId);
    
    console.log('joCostData=== 1 joCostData',joCostData)
    
    const journalEntryValueMain = (joCostData.everyProductTaken === 1 && joCostData.everyServiceTaken === 1) ? 2 : 1;
    console.log('joCostData=== 2 journalEntryValue',journalEntryValueMain)
    const productTotal = parseFloat(Number(joCostData.productTotal) || 0).toFixed(2);
    const serviceTotal = parseFloat(Number(joCostData.serviceTotal) || 0).toFixed(2);
    const total = parseFloat(Number(productTotal) + Number(serviceTotal) || 0).toFixed(2);
    console.log('joCostData=== 3 productTotal',previosProductTotal,productTotal)
    console.log('joCostData=== 4 serviceTotal',previosServiceTotal,serviceTotal)
      
    if(joCostData.syncWithQuickbooks == 1){
    const materialResponse = await hanldeMaterialJobCost(joCostData,productTotal,previosProductTotal,requestId,journalEntryValueMain,total);
    const serviceResponse = await hanldeServiceJobCost(joCostData,serviceTotal,previosServiceTotal,requestId,journalEntryValueMain,total);
    }
    if(journalEntryValueMain == 2 && joCostData.syncWithQuickbooks == 1){
      if(Number(total) > Number(previosJobCostTotal)){
      const completedResponse = await addJournalEntryToQuickBooksJobCompleted({
            amountMaterials :productTotal,
            amountLabor :serviceTotal,
            requestId,
            joCostData
          })
         }else{
            console.log("Already journal entry created -no change in job cost");
         }
        }

 
  } catch (error) {
    console.log("Error creating journal entry for materials", error);
    
  }
}

//////////////////////////////

const addJobCost = async (req, reply) => {
  try {
    let { values,serviceValues, userId,isReview, projectId,recipe,selectedServices,stockProducts,requestId,scanQr, taskId } = req.body;
    let allPayOut=await JobCost.fetchAllPayOutByProjectId(projectId, userId);
    let insertedstatus = false;
    let reduceStockResult, deleted;
    let flag = 0
    let jobCostChangeMessages = [];
    // return
    let projectData = await Projects.getProjectById(projectId)
    let joCostData = await Request.getJobCostDetailsForMaterials(projectData?.request_id);


    const previosProductTotal =(projectData?.project_category == 12 && values.length > 0) ? 0 : parseFloat(Number(joCostData?.productTotal) || 0).toFixed(2) 
    const previosServiceTotal =(projectData?.project_category == 12 && values.length == 0) ? 0 : parseFloat(Number(joCostData?.serviceTotal) || 0).toFixed(2) 
    const previosJobCostTotal = parseFloat(Number(previosProductTotal) + Number(previosServiceTotal) || 0).toFixed(2);


    let selectedMaterials = await JobCost.fetchAllJobCostByProjectId(projectId, userId,recipe);
    console.log('selectedMaterials',selectedMaterials)
    let initialMaterials = await JobCost.fetchAllJobCostByProjectId(projectId, userId,recipe);
    let initialMaterialProductIds = (initialMaterials || []).map(item => String(item.product_id || item.id));
    console.log('initialMaterials',initialMaterials)
    let initialRequestServices = [];
    try {
      initialRequestServices = await Request.getRequestServices(projectData?.request_id, false, false, false, projectData?.project_category) || [];
    } catch (e) { initialRequestServices = []; }
    let initialServiceIds = (initialRequestServices || []).map(s => String(s.labour_cost_service_id));
    console.log('initialServiceIds',initialServiceIds)
  
    // if(requestId){
    //   let deleteServices=await Request.deleteRequestServicesWithRequestId(requestId)
    //   console.log('deleteServicessssss', deleteServices)

    // }
    let requestProduct = {}
    // if(selectedServices?.length>0){
    //   console.log('selectedServicessssssssss 1', selectedServices)
    //   for (const row of selectedServices) {
    //     console.log('selectedServicessssssssss 2', row)
    //      let unitCost = parseFloat(row.unit_cost).toFixed(2) 
    //     row.unit_cost=row.originalCost+(row.markup*row.originalCost/100)
    //     let rowQuantity = row.quantity ? row.quantity : 1;
    //     requestProduct['request_id'] = requestId
    //     requestProduct['labour_cost_service_id'] = row.labour_cost_service_id||row.id,
    //     requestProduct['recipe_id'] = row.recipe_id || null,
    //     requestProduct['qty'] = row.qty,
    //     requestProduct['taken'] = row.taken,
    //     requestProduct['unit_cost'] = row.unit_cost ,
    //     requestProduct['markup'] = row.markup,
    //     requestProduct['total_cost'] = row.unit_cost*row.qty
    //     requestProduct['job_cost'] = 0
    //     requestProduct['jobcost_unit_cost'] = row.unit_cost || 0
    //     requestProduct['jobcost_quantity'] = row.jobcost_quantity || row.qty || 0
    //     requestProduct['jobcost_total_cost'] =  unitCost * Number(row.jobcost_quantity) || row.unit_cost*row.qty || 0
    //     let response = await Request.addRequestServices(requestProduct)
    //     console.log('responseeeeeeeeeeeeee', response)

    //   }
    // }

    if(selectedServices?.length>0){
      console.log('selectedServicessssssssss 1', selectedServices)
      for (const row of selectedServices) {
        // if (row.taken !== 1) continue;
        console.log('selectedServicessssssssss 2', row)
        //  let unitCost = parseFloat(row.unit_cost).toFixed(2) 
        const servicePayOutTotal = allPayOut?.reduce((acc, item) => {
          return item.service_id === row.id ? acc + (item.amount || 0) : acc;
        }, 0);

        // const unitCost = 
        //   parseFloat(row.jobcost_unit_cost) > 0
        //     ? parseFloat(row.jobcost_unit_cost)
        //     : parseFloat(row.originalCost) || 0;
        const unitCost = (isReview && row.labour_cost_service_id == 10) ? parseFloat(row.jobcost_unit_cost) : parseFloat(row.originalCost) || 0;
        // Quantity: keep whatever is in jobcost_quantity—even 0 / "0.00"
        const jobQty =
          row.jobcost_quantity != null && row.jobcost_quantity !== ''
            ? parseFloat(row.jobcost_quantity)            // "0.00" → 0
            : parseFloat(row.qty) || 0;   
            console.log('selectedServicessssssssss 3', unitCost ,jobQty ) 
            console.log('selectedServicessssssssss 4', Number((unitCost * jobQty).toFixed(2)) ) 
            console.log('selectedServicessssssssss 5', servicePayOutTotal ) 
        requestProduct['taken'] = row.taken,
        requestProduct['jobcost_unit_cost']  = unitCost.toFixed(2);         
        requestProduct['jobcost_quantity']   = jobQty;                       
        requestProduct['jobcost_total_cost'] = (servicePayOutTotal > 0) ? servicePayOutTotal : Number((unitCost * jobQty).toFixed(2));
        // requestProduct['jobcost_unit_cost'] = unitCost || 0
        // requestProduct['jobcost_quantity'] = row.jobcost_quantity || row.qty || 0
        // requestProduct['jobcost_total_cost'] =  unitCost * Number(row.jobcost_quantity) || 0
        console.log('selectedServicessssssssss 6', requestProduct)
        if(projectData?.project_category == 12 && row.labour_cost_service_id == 10){
          requestProduct['qty']   = jobQty;
        }else{
          requestProduct['qty']   = row?.qty;
        }
        console.log('requestProduct------********', requestProduct)
        let response = await Request.updateRequestServices(requestProduct,row?.id,requestId)
        console.log('responseeeeeeeeeeeeee', response)
        // if (!initialServiceIds.includes(String(row?.labour_cost_service_id))) {
        //   const serviceName = row?.name || row?.service_name || 'Service';
        //   jobCostChangeMessages.push(`Service '${serviceName}' has been added to the job through job cost.`);
        // }

      }
    }
    if (selectedMaterials?.filter((item)=>item.rfp != 1)?.length > 0) {
      for (const element of selectedMaterials) {
        const material = await Products.getMaterialById(element?.product_id)
        if(material?.length > 0){
          const materialData = material[0];
          let materialMessage = "Stock is lesser than entered qty";
          if (materialData?.name) materialMessage += ` for ${materialData.product_name}`;
          if (materialData?.barcode) materialMessage += ` (${materialData.barcode})`;

          const matchingValue = values?.find(val => val?.productId === material[0]?.id);
          // let newQty = material[0]?.qty + element.actual_quantity //quantity
          // let newQty = material[0]?.qty + (scanQr ? 0 : (element?.quantity != 0 ? element?.quantity : element?.actual_quantity));
          let newQty = material[0]?.qty + (scanQr ? 0 : element?.quantity);
          let totalCost = material[0]?.unit_cost * newQty
          console.log('element?.quantity===',element?.quantity,'element?.actual_quantity===',element?.actual_quantity)
          console.log(material[0].qty,'newQty===',newQty,'matchingValue.quantity===',matchingValue?.quantity)
          if ((projectData?.project_category == 12 || projectData?.job_category_name == 'Time & Material') ? true : (matchingValue ? newQty >= matchingValue.quantity : true)) {
            if (newQty >= parseInt(material[0].qty)) {
              const data = { 
                qty : newQty,
                total_cost : totalCost
              };
              const updated = await Products.updateMaterialStock(element.product_id,data)
              console.log('updated===',updated,element.product_id)
              if(updated){
                if(!scanQr){
                  deleted = await JobCost.deleteJobCost(element.id,recipe);
                  console.log('deleted 1', deleted)
                }
              }else{
                console.log('Failed to update stock');
                reply.send({ status: 0, message:'Failed to update stock' });
                return;
              }
            }else{
              reply.send({ status: 0, message: materialMessage,resultId:material[0].id });
              return;
            }
          }else{
            const finishedProducts = await Products.getAllFinishedProductsByProductId(material[0]?.material_id)
            const newMatchingProduct = finishedProducts.find(fProduct => fProduct.qty >= newQty);
            console.log('newMatchingProduct===',newMatchingProduct);

            if(newMatchingProduct) {
              const data = { 
                qty : newQty,
                total_cost : totalCost
              };
              const updated = await Products.updateMaterialStock(newMatchingProduct.id,data)
              if(updated){
                if(!scanQr){
                  deleted = await JobCost.deleteJobCost(element.id,recipe);
                  console.log('deleted 2', deleted)
                }
              }else{
                console.log('Failed to update stock');
                reply.send({ status: 0, message:'Failed to update stock' });
              }
            }else{
              reply.send({ status: 0, message: `Stock is lesser than entered qty`,resultId:material[0].id });
              return;
            }
          }
        // }
        }
      }
      flag = 1
    }
    console.log('flagflagflagflagflag',flag,deleted)
    const getCustomerOrder = await CustomerOrder.getCustomerOrderRequestId(projectData?.request_id)
    if((flag === 1 && (deleted || scanQr)) || (flag === 0)){
      console.log('valuesvaluesvalues',values)
      for (let i = 0; i < values.length; i++) {
        if(!empty(values[i].rfp)){
          deleted = await JobCost.deleteJobCost(values[i].productId,recipe);
        }
      }
      for (let i = 0; i < values.length; i++) {
        if(!empty(values[i].rfp)){
          console.log("###########RFpppppppp",values[i]);
          // let jobCostData = {
          //   product_id: values[i].productId,
          //   project_id: values[i].projectId,
          //   quantity: values[i].quantity,
          //   unit_price: values[i].unitPrice,
          //   total: values[i].total,
          //   taken: (recipe==0) ? 1 : values[i].taken,
          //   recipe:recipe,
          //   recipe_name:null,
          //   timestamp: moment().unix(),
          //   added_by: userId,
          //   rfp:1
          // };
          // insertedstatus = await JobCost.updateJobCost({taken:values[i].taken},values[i].productId);

          let jobCostData = {
            product_id: values[i].id,
            project_id: values[i].projectId,
            actual_quantity: values[i]?.actual_quantity || 0,
            actual_unit_price: values[i]?.actual_unit_price || 0,
            actual_total: values[i]?.actual_total || 0,
            quantity: values[i].quantity,
            unit_price: values[i].unitPrice,
            total: values[i].total,
            taken: values[i].taken,
            recipe:recipe,
            rfp:1,
            // recipe_name:values[i].recipeName,
            timestamp: moment().unix(),
            added_by: userId,
            customer_order_product_id: values[i]?.customer_order_product_id,
          };
          insertedstatus = await JobCost.addJobCost(jobCostData);
          if (!initialMaterialProductIds.includes(String(values[i].id))) {
            const rfpProductName = values[i].product_name || values[i].material_name || values[i].name || 'Product';
            const productType = values[i].isMaterial === 1 ? 'material' : 'catalog';
            jobCostChangeMessages.push(`${productType} '${rfpProductName}'  has been added to the job through job cost.`);
          }
        }
        else{
          // console.log("###########NotRFpppppppp",values[i]);
          const materialData = await Products.getMaterialById(values[i].productId)
          if(materialData){
            const material = materialData[0];
            let materialMessage = "Stock is lesser than entered qty";
            if (material?.name) materialMessage += ` for ${material.name}`;
            if (material?.barcode) materialMessage += ` (${material.barcode})`;
            // let newQty = materialData[0].qty - values[i].quantity      //actual_quantityquantity 
            // let newQty = materialData[0]?.qty - (scanQr ? values[i]?.quantity : values[i]?.quantity != 0 ? values[i]?.quantity : values[i]?.actual_quantity);   
            let newQty = materialData[0]?.qty - (scanQr ? values[i]?.quantity : values[i]?.quantity);   
            console.log('reduced qty----',newQty)
            console.log('reduced values[i]----',values[i])
            console.log('reduced materialData[0]?.qty----',materialData[0]?.qty)
            if(newQty >= 0){
              let unitPrice = values[i].unitPrice || values[i]?.actual_unit_price || values[i]?.actual_unit_cost || 0
              let totalCost = unitPrice * newQty
              let data = {};
              data['qty'] = newQty
              data['total_cost'] = totalCost
              let jobCostData = {
                product_id: values[i].productId,
                project_id: values[i].projectId,
                actual_quantity: values[i]?.actual_quantity || 0,
                quantity: values[i].quantity,
                actual_unit_price: values[i]?.actual_unit_price || values[i]?.actual_unit_cost || values[i].unitPrice || 0,
                unit_price: unitPrice || 0,
                actual_total: values[i]?.actual_total || 0,
                total: values[i].total || 0.00,
                taken: (recipe==0) ? 1 : values[i].taken,
                task_id : taskId ? Number(taskId) : values[i].task_id || null,
                recipe:recipe,
                recipe_name:values[i].recipeName,
                timestamp: moment().unix(),
                added_by: userId,
                customer_order_product_id: values[i]?.customer_order_product_id,
                for_product : values[i]?.for_product || null,
                for_service : values[i]?.for_service || null,
              };
              console.log('jobCostData---',jobCostData)
              insertedstatus = await JobCost.addJobCost(jobCostData);
              if (!initialMaterialProductIds.includes(String(values[i].productId))) {
                const productName = material?.name || material?.product_name || 'Product';
                const productType = material?.isMaterial === 1 ? 'material' : 'catalog';
                jobCostChangeMessages.push(`${productType} '${productName}' has been added to the job through job cost.`);
              }
              reduceStockResult = await Products.updateMaterialStock(values[i].productId,data)

              // if(projectData?.project_category == 12 && projectData?.isReview == 2 && !recipe && insertedstatus ){
                if(projectData?.project_category == 12 && !recipe && insertedstatus ){
                console.log('jobCostData---t and m',jobCostData)
                if( jobCostData?.customer_order_product_id){
                  let data = {
                  product_qty : values[i].quantity
                  }
                  const productId = jobCostData?.customer_order_product_id
                  console.log('productIdproductId', productId)
                  const updatedCustomerOrderProduct = await CustomerOrderProduct.updateCustomerOrderProduct(data,productId)
                  console.log('updatedCustomerOrderProduct', updatedCustomerOrderProduct)
                }else if (values[i]?.material_id){
                        let requestProduct2 = {}
                        console.log('values[i]values[i]',values[i])
                      if (getCustomerOrder) {
                        requestProduct2['order_id'] = getCustomerOrder?.id
                        requestProduct2['product_id'] = values[i]?.material_id|| null,
                        requestProduct2['product_name'] = values[i]?.material_name|| '',
                        requestProduct2['product_price'] = unitPrice || 0.00,
                        requestProduct2['product_retail_price'] = unitPrice || 0.00
                        requestProduct2['product_qty'] = values[i].quantity || 0,
                        requestProduct2['product_sub_total'] = values[i]?.total,
                        requestProduct2['product_tax'] = 0,
                        requestProduct2['product_total'] = values[i]?.total,
                        requestProduct2['discount'] =0,
                        requestProduct2['status'] = 1
                        requestProduct2['adjustment'] = 0,
                        requestProduct2['timestamp'] = moment().unix(),
                        requestProduct2['rfp'] = 0
                        requestProduct2['material'] = 1
                        requestProduct2['product_markup'] = values[i]?.markup || 0
                        requestProduct2['stock_type'] =values[i]?.partial == 0 ? 1 : 2 
                        requestProduct2['convertion_unit'] = values[i]?.partial == 0 ? null : values[i]?.partial_unit ? Number(values[i]?.partial_unit):null;
                        console.log('requestProduct2--material', requestProduct2)
                        let response = await CustomerOrderProduct.createCustomerOrder(requestProduct2)
                        console.log('responseresponse', response)
                        if(response){
                          let data = {
                            customer_order_product_id:response
                          }
                          const updateJobcostOrderId = await JobCost.updateJobCost(data,insertedstatus);
                          console.log('updateJobcostOrderIdddddd', updateJobcostOrderId)
                        }
                }
                }
              }
              if(newQty == 0){
                if(material?.autofill == 1){
                  const parentFinishedMaterial = await Products.getMaterialById(material?.parent_finished_product_id)
                  console.log('parentFinishedMaterial----',parentFinishedMaterial)
                  console.log('material----',material)
                  if (parentFinishedMaterial.length > 0 && parentFinishedMaterial[0]?.qty > 0) {
                    let reducedQty = parentFinishedMaterial[0]?.qty - 1
                    let parentTotalCost = parentFinishedMaterial[0]?.unit_cost * reducedQty
                    let parentData = {
                      qty: reducedQty,
                      total_cost: parseInt(parentTotalCost)
                    };
                    const reduceFinishedProductStock = await Products.updateMaterialStock(material?.parent_finished_product_id, parentData)
        
                    let addingQty = material?.actual_qty
                    let totalCost = material?.actual_total_cost
                    let autoFilldata = {
                      qty: addingQty,
                      total_cost: totalCost
                    };
                    console.log('autofillPartialStock--',autoFilldata);
                    const autofillPartialStock = await Products.updateMaterialStock(material?.id, autoFilldata);
                  }
                }
              }
            } else{
              reply.send({ status: 0, message: materialMessage,resultId:materialData[0].id });
            }
          }
        }
      }
      if(serviceValues && serviceValues?.length > 0){
        for (let i = 0; i < serviceValues?.length; i++) {
          let servData = {
            taken: serviceValues[i].taken,
          };
        insertedstatus = await Request.updateRequestServices(servData,serviceValues[i].id,serviceValues[i].request_id);
        }
      }
      if (stockProducts?.length > 0) {
        for (const product of stockProducts) {
          if (product.taken === 1) {
            const updateData = {
              id: product.id,
              jobcost_quantity: Number(product.jobcost_quantity),
              jobcost_total_cost: Number(product.jobcost_total_cost),
              taken: product.taken
            };
            try {
              const updateRes = await CustomerOrderProduct.updateCustomerOrderProduct(updateData,product.id);
              console.log('updateRes', updateRes)

              if (updateRes) {
                const remainingStock = Number(product.in_stock_no) - Number(updateData.jobcost_quantity);
                await Products.StockUpdate(remainingStock, product.product_id);
              } else {
                console.warn(`Update skipped for product ID ${product.id}: update failed or returned no success flag.`);
              }

            } catch (error) {
              console.error(`Failed to update product ID ${product.id}:`, error);
            }
          }
        }
      }
      // if (projectData?.project_category == 12 && projectData?.isReview == 2 && values.length > 0) {
        if (projectData?.project_category == 12 &&  values.length > 0) {
        let activeJobCosts = await JobCost.fetchAllJobCostByProjectId(projectId, userId, recipe);

        const activeIds = activeJobCosts
          .map(j => j.customer_order_product_id)
          .filter(id => id != null);
        console.log('activeIds------', activeIds)

        const deleteOrder = await CustomerOrderProduct.deletedCustomerOrderProductById(
          getCustomerOrder?.id,
          activeIds
        );
        console.log('deleteOrder-----', deleteOrder)
      }
      console.log('values?.length',values?.length)
      console.log('insertedstatus',insertedstatus)
      console.log('reduceStockResult',reduceStockResult)
      if ((values?.length === 0) || (insertedstatus || reduceStockResult)) {
        let notificationMsg = `Job cost has been added for job '${projectData?.name}'`;
        if (flag == 1) {
          notificationMsg = `Job cost has been updated for job '${projectData?.name}'`;
        }
        if (jobCostChangeMessages.length > 0) {
          notificationMsg += '. ' + jobCostChangeMessages.join(' ');
        }
        const requestActivity = await RequestActivity.addRequestUpdate({
          request_id: projectData?.request_id,
          activity: notificationMsg,
          added_by: userId,
          timestamp: moment().unix()
        });

        // Fetch the user name using userId
        const userName = await Admin.getUserNameById(userId); // Fetch user name
        // --- BEGIN: Log to JobCostLogs with price changes ---
        const updatedTotals = await Request.getJobCostDetailsForMaterials(projectData?.request_id);

        const newProductTotal = parseFloat(Number(updatedTotals?.productTotal) || 0).toFixed(2);
        const newServiceTotal = parseFloat(Number(updatedTotals?.serviceTotal) || 0).toFixed(2);
        const newJobCostTotal = parseFloat(Number(newProductTotal) + Number(newServiceTotal)).toFixed(2);

        const logMsgParts = [
          `${notificationMsg} by user '${userName}'`
        ];

        await JobCost.addJobCostLog({
          message: sanitizeLog(logMsgParts.join(' | ')),
          user_id: userId,
          project_id: projectId,
          timestamp: moment().unix(),
          status: 1
        });
        // --- END: Log to JobCostLogs with price changes ---

        let notificationUrl = "project/view-project/job-cost/" + projectId;
        const incrementResult_User = await Admin.incrementField(
          userId,
          "noti_count",
          1
        );

        let notificationData_user = {
          user_id: userId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };
        const addNotificationResult_user = await Admin.addNotification(
          notificationData_user
        );
        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};

        for (const adminId of adminIds) {
          if (adminId != userId) {
            const incrementResult = await Admin.incrementField(
              adminId,
              "noti_count",
              1
            );

            notificationData = {
              user_id: adminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        reply.send({ status: 1, message: notificationMsg });
        if(projectData?.syncWithQuickbooks == 1){
          await createJornalEntryForJobCost(projectData?.request_id,previosJobCostTotal,previosProductTotal,previosServiceTotal)
        }
        return;
      } else {
        if (flag === 1) {
          console.log('Failed to update Project cost');
          reply.send({ status: 0, message: " Failed to update Project cost " });
        }
        else {
          console.log('Failed to add Project cost');
          reply.send({ status: 0, message: " Failed to add Project cost " });
        }
      }
    }

  } catch (error) {
    console.log("ERRR", error);
    reply.send({ status: 500, message:'Error',error:error });
  }
};

const fetchAllJobCostByProjectId = async (req, reply) => {
  let { projectId, userId,orderId} = req.body;
  let recipe=0;
  let selectedMaterials = await JobCost.fetchAllJobCostByProjectId(projectId,userId, recipe,true,false);
  recipe=1
  let projects = await Projects.getProjectById(projectId)
  let stockProducts = [];
  if(projects?.project_category !== 15){
    // stockProducts = await JobCost.fetchAllProductsStock(projectId, userId, recipe)
  }else{
    stockProducts =[]
  }
  console.log('stockProducts', stockProducts)
  let materials=await JobCost.fetchAllJobCostByProjectId(projectId,userId, recipe);
  let groupedMaterials = selectedMaterials.reduce((acc, material) => {
    let existing = acc.find(item => item.product_id  === material.product_id);
    if (existing) {
      existing.actual_unit_price = material.actual_unit_price
      existing.quantity += material.quantity
      existing.actual_quantity += material.actual_quantity
      existing.total += material.total;
      existing.actual_total += material.actual_total;
    } else {
      acc.push({
        ...material
      });
    }

    return acc;
  }, []);
  console.log("#####groupedMaterials",groupedMaterials);
  selectedMaterials = groupedMaterials
  let allPayOut=await JobCost.fetchAllPayOutByProjectId(projectId, userId);
  // let projects = await Projects.getProjectById(projectId);
  // let results = await Products.getAllMaterials(true);
  let allMaterials = await Products.getAllMaterials(true)
  let allCatalogs = await Products.getAllProducts(true)
  let allProducts =[]
  if(projects?.project_category === 15){
    allProducts = await Products.getAllLocations(orderId)
  }else{
    allProducts = await Products.getNonStockProducts(orderId)
  }
  console.log('allProducts 5', allProducts)
  const allProductIds = allProducts?.split(',').map(id => parseInt(id, 10));
  console.log('allProductIds', allProductIds)
  // let allProducts=await Products.getAllLocations(orderId)
   let allRecipies = []
  if(allProducts && allProducts != ""){
    allRecipies = await Recipe.getAllReceipesByProjectId(allProducts, orderId);
  }
  let results = await Products.getFinishedProducts();
  let allServices = await Products.getAllLabourCostServices();
  let selectedServices=await Recipe.fetchAllAdditionalServicesByRequest(orderId)
  let services=await Recipe.fetchAllServicesByRequest(orderId)
  const filteredServices = services.filter(service => {
    // If product_id is not null or undefined, include only if it's in allProductIds
    if (service.product_id != null) {
      return allProductIds.includes(service.product_id);
    }
    // return true;
    return service.facility_id == FACILITY_ID || service.facility_id == null;
  });
  console.log('services', services)
  reply.send({ status: 1, selectedMaterials,stockProducts,allServices,services:filteredServices,selectedServices, results, allPayOut,projects, allMaterials,allCatalogs,allRecipies,materials});
};
const fetchDataForPayOut = async (req, reply) => {
  let { userId, userType, hasPermission ,isInstallers} = req.body
  let projects = await Projects.getAllProjects(hasPermission,true, userType, userId);
  let designJobs = await Projects.getAllDesignOrderJobs(hasPermission,true, userType, userId)
  let teamMembers = await Teams.getAllTeams(true, "", userId, userType,null,
    null,
    null,
    null,
    false,
    false,
    false,
    isInstallers);
    let Drivers = []
    if(isInstallers){
      Drivers = await Driver.getAllfilterdDrivers(userId, userType);
    }
  if(userType!=1 && hasPermission === false){
    teamMembers = teamMembers.data.filter(user => user.user_id ===userId);
  }
  reply.send({ status: 1, msg: "data Fetch successfully", projects,designJobs, teamMembers:teamMembers.data, Drivers })
}
const fetchAllProjectTaskById = async (req, reply) => {
  let { id, userId, userType,hasPermission } = req.body
  let projectTask = await ProjectTasks.getAllProjectTasks(id, userType, userId,hasPermission)
  reply.send({ status: 1, msg: "data Fetch successfully", projectTask })

}
const addPayOut = async (req, reply) => {
  let { userId, values,logIdsArray } = req.body
  let data = {
    project_id: values.project.id,
    task_id: values.task.ID,
    log_id: (values.isTimeTracking == 0) ? null : logIdsArray?.join(','),
    team: values.employee.id,
    paid_at: values.paidAt,
    amount: values.amount,
    hours: values.hours || null,
    description:values.description,
    cover:values.cover,
    timestamp: moment().unix(),
    is_time_tracking: values.isTimeTracking,
    added_by: userId,
    status:values.isReimbursement?5:1
  };
  insertedstatus = await JobCost.addPayOut(data)
  if (insertedstatus) {
    if((values.isTimeTracking == 1) && (logIdsArray?.length > 0)){
      for(const data of logIdsArray){
        let updateData = {}
        updateData['status'] = 0
        await ProjectTasks.updateLogStatus(updateData, data)
      }
    }

    const updatedPayoutsCount = values.length;  // Assuming `values` contains the list of updated payouts

    const logMessage = `${updatedPayoutsCount} Pay Out(s) have been updated for project '${values.project.name}'`;
    await JobCost.addJobCostLog({
      message: sanitizeLog(logMessage),
      user_id: userId,
      timestamp: moment().unix(),
      status: 1,
      project_id: values.project.id
    });

    let notificationMsg = `Pay Out has been updated`;
    let notificationUrl = "staff-payout";
    const incrementResult_User = await Admin.incrementField(
      userId,
      "noti_count",
      1
    );

    let notificationData_user = {
      user_id: userId,
      url: notificationUrl,
      timestamp: currentDate,
      message: notificationMsg,
      status: 1,
      from_id: userId,
    };
    const addNotificationResult_user = await Admin.addNotification(
      notificationData_user
    );
    let adminIds = await Admin.getAllAdminIds();
    let notificationData = {};

    for (const adminId of adminIds) {
      if (adminId != userId) {
        const incrementResult = await Admin.incrementField(
          adminId,
          "noti_count",
          1
        );

        notificationData = {
          user_id: adminId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };

        const addNotificationResult = await Admin.addNotification(
          notificationData
        );
      }
    }
    reply.send({ status: 1, message: notificationMsg });
  }
  else {
    reply.send({ status: 0, message: " Failed to add Project cost " });

  }
}
const fetchAllPayOut = async (req, reply) => {
  try{
    let { userId, userType,hasPermission } = req.body
    let payOut = await JobCost.fetchAllPayOut(userType,userId,all=true,hasPermission)
    let designPayOut = await JobCost.fetchAllDesignPayOut(userType,userId,all=true,hasPermission)
    reply.send({ status: 1, msg: "data Fetch successfully", payOut ,designPayOut})
  }
 catch(error){
  reply.send({ status: 0,payOut:[], msg: "Failed to  Fetch successfully"+error })
 }

}
const getPayOutById = async (req, reply) => {
  let { id, userId, userType } = req.body
  let payOut = await JobCost.getPayOutById(id)
  if (!empty(payOut)) {
    reply.send({ status: 1, msg: "data Fetch successfully", payOut })

  }
  else {
    reply.send({ status: 0, msg: "No data found" })
  }

}
const updatePayOut = async (req, reply) => {
  let { userId, values, id,approve, logIdsArray } = req.body

  let data = {
    project_id: values?.project?.id,
    task_id: values?.task?.ID,
    team: values.employee.id,
    paid_at: values.paidAt,
    amount: values.amount,
    hours: values.hours || null,
    log_id: (values.isTimeTracking == 0) ? null : logIdsArray?.join(','),
    description:values.isReimbursement?values.description:"",
    cover:values.isReimbursement?values.cover:"",
    is_time_tracking: values.isTimeTracking,
    timestamp: moment().unix(),
    added_by: userId,
    status : approve ? 1 : (values.isReimbursement ? 5 : 1)
  };
  insertedstatus = await JobCost.updatePayOut(data,id)
  if (insertedstatus) {
    if(logIdsArray?.length > 0){
      for(const data of logIdsArray){
        let updateData = {}
        updateData['status'] = (values.isTimeTracking == 0) ? 1 :0
        await ProjectTasks.updateLogStatus(updateData, data)
      }
    }

    const updatedPayoutsCount = values.length;  // Assuming `values` contains the list of updated payouts

    const logMessage = `${updatedPayoutsCount} Pay Out(s) have been updated for project '${values.project.name}'`;
    await JobCost.addJobCostLog({
      message: sanitizeLog(logMessage),
      user_id: userId,
      timestamp: moment().unix(),
      status: 1,
      project_id: values?.project?.id
    });

    let notificationMsg = `Pay Out has been updated`;


    let notificationUrl = "staff-payout";
    const incrementResult_User = await Admin.incrementField(
      userId,
      "noti_count",
      1
    );

    let notificationData_user = {
      user_id: userId,
      url: notificationUrl,
      timestamp: currentDate,
      message: notificationMsg,
      status: 1,
      from_id: userId,
    };
    const addNotificationResult_user = await Admin.addNotification(
      notificationData_user
    );
    let adminIds = await Admin.getAllAdminIds();
    let notificationData = {};

    for (const adminId of adminIds) {
      if (adminId != userId) {
        const incrementResult = await Admin.incrementField(
          adminId,
          "noti_count",
          1
        );

        notificationData = {
          user_id: adminId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };

        const addNotificationResult = await Admin.addNotification(
          notificationData
        );
      }
    }
    reply.send({ status: 1, message: notificationMsg });
  }
  else {
    reply.send({ status: 0, message: " Failed to add Project cost " });

  }
}

const updateMaterialInJobcost = async (req, reply) => {
  try {
    let { materialBarcode, userId, projectId, taskId ,qty,initialTry,selectedInstallation} = req.body;
   
    const materialData = await Products.getFinishedProductsDataByBarcode(materialBarcode);
    if (!materialData) {
      reply.send({ status: 0, message: "Material not available. Please try again with a valid material." });
      return;
    }
    console.log('materialDatamaterialDatamaterialData',materialData)
    const jobCostResult = await JobCost.fetchJobCostAdditionalMaterialByInventoryId(materialData?.id,projectId);

    const futureInstallationProducts = await JobCost.getFutureInstallationProducts(projectId);
    const futureInstallationServices = await JobCost.getFutureInstallationServices(projectId);
    const futureInstallation = [...futureInstallationProducts, ...futureInstallationServices];
   
    const material = materialData?.name;
    const materialId = materialData?.material_id;

    // Check if material exists in any product formula (recipe)
    const materialInRecipe = await Recipe.checkMaterialInRecipe(materialId);
    console.log('materialInRecipe', materialInRecipe);
    
    let selectedMaterials1 = await JobCost.fetchAllJobCostByProjectandMaterialId(projectId, materialId);
    console.log('selectedMaterials===1',selectedMaterials1)
    let selectedMaterials = selectedMaterials1?.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id) ? [selectedMaterials1.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id)] : [];
    console.log('selectedMaterials===1=taken 0',selectedMaterials)

    if (selectedMaterials.length === 0) {
      const normalize = (value) => value ?? '';
      const newmaterialsss = selectedMaterials1?.find(item => 
        item?.taken == 0 && 
        item?.quantity == 0 && 
        normalize(item?.partial_unit) === normalize(materialData?.partial_unit) && 
        item?.material_id == materialData?.material_id
      ) || null
      console.log('newmaterialsss---',newmaterialsss);
      if(newmaterialsss){
        const foundMaterial = selectedMaterials1?.find(item => 
          item?.taken === 0 &&
          item?.quantity === 0 &&
          normalize(item?.partial_unit) === normalize(materialData?.partial_unit) &&
          item?.material_id === materialData?.material_id
        ) || {};
        selectedMaterials = [{
            ...foundMaterial,
            barcode: materialBarcode,
            material_inventory_id: materialData?.id,
            product_id: materialData?.id,
            material_unit_cost : materialData?.unit_cost,
            unit_price: materialData?.unit_cost,
            actual_unit_price: materialData?.unit_cost,
            unit_cost: materialData?.unit_cost,
        }];
      }
    }

    let projectData = await Projects.getProjectById(projectId);
    const productData = await Products.findProductByName(material)
    let balanceQty =0
   

    if(productData){
      // const materialData = await Products.getFinishedProductsByProductId(productData?.id)
      let insertedstatus = null;
      if(selectedMaterials?.length > 0){
        let flag = 0;
        let selectedmaterialData = null;
        console.log('selectedMaterials===',selectedMaterials)
        for(const selectedMaterial of selectedMaterials){
          if(selectedMaterial?.taken == 1){
            flag = 1
            selectedmaterialData = selectedMaterial
          }else{
            flag = 0
            // if(taskId){
            // let theRealQty=(Number(qty || 1)) > selectedMaterial.actual_quantity?selectedMaterial.actual_quantity :(Number(qty || 1))
              let theRealQty = selectedMaterial.actual_quantity > 0 ? ((Number(qty || 1)) > selectedMaterial.actual_quantity ? selectedMaterial.actual_quantity : (Number(qty || 1))) : Number(qty || 1);
              balanceQty = selectedMaterial.actual_quantity > 0 ? (theRealQty > 0 ? ((Number(qty || 1)) - selectedMaterial.actual_quantity) : 0) : 0
        
              const actualQuantity = Number(selectedMaterial.quantity || 0) + (Number(theRealQty || 1));
              const actualUnitPrice = Number(materialData?.unit_cost || 0);
              const currentTotal = actualUnitPrice * (theRealQty || 1); //actualQuantity
              const prevTotal = Number(selectedMaterial?.total || 0);
              const actualTotal = currentTotal + prevTotal;
              let jobCostData = {
                quantity: actualQuantity,
                unit_price : actualUnitPrice,
                task_id:taskId || null,
                total: actualTotal,
                barcode: selectedMaterial?.barcode,
                product_id: selectedMaterial?.product_id,
                for_product: selectedInstallation?.IsProductInstallation ? selectedInstallation?.location_id : null,
                for_service: selectedInstallation?.IsServiceInstallation ? selectedInstallation?.location_id : null,
              };
              if (actualQuantity >= selectedMaterial.actual_quantity) {
                jobCostData.taken = 1;
              }
              if(initialTry == 1){
                return reply.send({status: 6,message: `The Additional Material was already added to the job cost.Please choose the product/service to continue `,materialData: materialData,jobCostResult,futureInstallation})
              }
              let projectData = await Projects.getProjectById(projectId)
              let joCostData = await Request.getJobCostDetailsForMaterials(projectData?.request_id);

              const previosProductTotal = parseFloat(Number(joCostData?.productTotal) || 0).toFixed(2) 
              const previosServiceTotal = parseFloat(Number(joCostData?.serviceTotal) || 0).toFixed(2) 
              const previosJobCostTotal = parseFloat(Number(previosProductTotal) + Number(previosServiceTotal) || 0).toFixed(2);

              
              insertedstatus = await JobCost.updateJobCost(jobCostData, selectedMaterial?.id);
              await createJornalEntryForJobCost(projectData?.request_id,previosJobCostTotal,previosProductTotal,previosServiceTotal)
              
              const materialStockData = await Products.getMaterialById(selectedMaterial?.material_inventory_id);
              console.log('materialStockData===',materialStockData);
              
              if(materialStockData && materialStockData?.length > 0){
                let newQty = materialStockData[0].qty - Number(theRealQty || 1)
                if (newQty >= 0) {
                  let totalCost = materialStockData[0].unit_cost * newQty
                  let data = {};
                  data['qty'] = newQty
                  data['total_cost'] = parseInt(totalCost)
                  const reduceStockResult = await Products.updateMaterialStock(selectedMaterial?.material_inventory_id, data);
                  // Autofill stock if stock is 0
                  if(newQty <= 0){
                    if(materialStockData[0]?.autofill == 1){
                      const parentFinishedMaterial = await Products.getMaterialById(materialStockData[0]?.parent_finished_product_id)
                      console.log('parentFinishedMaterial----',parentFinishedMaterial)
                      if (parentFinishedMaterial.length > 0 && parentFinishedMaterial[0]?.qty > 0) {
                        let reducedQty = parentFinishedMaterial[0]?.qty - 1
                        let parentTotalCost = parentFinishedMaterial[0]?.unit_cost * reducedQty
                        let parentData = {
                          qty: reducedQty,
                          total_cost: parseInt(parentTotalCost)
                        };
                        const reduceFinishedProductStock = await Products.updateMaterialStock(materialStockData[0]?.parent_finished_product_id, parentData)
        
                        let addingQty = materialStockData[0]?.actual_qty
                        let totalCost = materialStockData[0]?.actual_total_cost
                        let autoFilldata = {
                          qty: addingQty,
                          total_cost: totalCost
                        };
                        console.log('autofillPartialStock--',autoFilldata);
                        const autofillPartialStock = await Products.updateMaterialStock(materialStockData[0]?.id, autoFilldata);
                      }
                    }
                  }
                }else{
                  // Autofill stock if stock is 0
                  if(newQty <= 0){
                    if(materialStockData[0]?.autofill == 1){
                      const parentFinishedMaterial = await Products.getMaterialById(materialStockData[0]?.parent_finished_product_id)
                      console.log('parentFinishedMaterial----',parentFinishedMaterial)
                      if (parentFinishedMaterial.length > 0 && parentFinishedMaterial[0]?.qty > 0) {
                        let reducedQty = parentFinishedMaterial[0]?.qty - 1
                        let parentTotalCost = parentFinishedMaterial[0]?.unit_cost * reducedQty
                        let parentData = {
                          qty: reducedQty,
                          total_cost: parseInt(parentTotalCost)
                        };
                        const reduceFinishedProductStock = await Products.updateMaterialStock(materialStockData[0]?.parent_finished_product_id, parentData)
        
                        let addingQty = materialStockData[0]?.actual_qty
                        let totalCost = materialStockData[0]?.actual_total_cost
                        let autoFilldata = {
                          qty: addingQty,
                          total_cost: totalCost
                        };
                        console.log('autofillPartialStock--',autoFilldata);
                        const autofillPartialStock = await Products.updateMaterialStock(materialStockData[0]?.id, autoFilldata);
                      }
                    }
                  }
                }
              }
            // }
            break;
          }
        }
        if(flag == 1){
          reply.send({ status: 2, message: "Material already taken in this Job. Do you want to add it as additional materials?", materialData : selectedmaterialData });
          return;
        }
      }else{
        // If material is not in any product formula, show the warning popup directly
        if (!materialInRecipe || materialInRecipe.length === 0) {
          reply.send({
            status: 5,
            message: `This material is not included in any product formula. Are you sure you want to add ${qty} quantity of ${material} to additional materials?`,
            materialData: materialData,
            jobCostResult,futureInstallation
          });
          return;
        }

        // Material is in product formula, show normal confirmation
        (projectData?.job_category_name == 'Time & Material') ?
          reply.send({ status: 3, message: `Do you want to add ${qty} quantity of ${material} to materials?`, materialData : materialData })
        :
          reply.send({ status: 3, message: `Do you want to add ${qty} quantity of ${material} to additional materials?`, materialData : materialData,jobCostResult,futureInstallation })
        return;
      }
      if (insertedstatus) {

        // Add log after updating the material
        const updatedMaterial = selectedMaterials[0];  // Assuming the first selected material is updated
        const logMessage = `Material '${updatedMaterial.name}' has been updated in job cost for project '${projectData?.name}'. 
        Updated quantity: ${updatedMaterial.quantity}, Total cost: $${updatedMaterial.total.toFixed(2)}`;
        await JobCost.addJobCostLog({
          message: sanitizeLog(logMessage),
          user_id: userId,
          timestamp: moment().unix(),
          status: 1,
          project_id: projectId,
        });

        const notificationMsg = `Job cost has been updated for job '${projectData?.name}'`;
        let notificationUrl = "project/view-project/job-cost/" + projectId;
        const incrementResult_User = await Admin.incrementField(
          userId,
          "noti_count",
          1
        );

        let notificationData_user = {
          user_id: userId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };
        const addNotificationResult_user = await Admin.addNotification(
          notificationData_user
        );
        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};

        for (const adminId of adminIds) {
          if (adminId != userId) {
            const incrementResult = await Admin.incrementField(
              adminId,
              "noti_count",
              1
            );

            notificationData = {
              user_id: adminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        if (balanceQty > 0) {
          materialData.balanceQty = balanceQty; // Add balanceQty to materialData
          reply.send({
              status: 4,
              message: `The Stock was updated Successfully. Would you like to proceed to add the balance Qty(${balanceQty}) as Additional Material`,
              materialData: materialData
          });
      }else{

        reply.send({ status: 1, message: notificationMsg })
      }

        return;
      } else {
        console.log('Failed to update Job cost');
        reply.send({ status: 0, message: " Failed to update Job cost " });
      }
    }else{
      reply.send({ status: 0, message: "Material not available. Please try again with a valid material." });
    }
  } catch (error) {
    console.log("Error", error);
    reply.send({ status: 500, message:'Error',error:error });
  }
};


const updateProductInJobcost = async (req, reply) => {
  try {
    let { materialBarcode, userId, projectId, taskId ,qty} = req.body;
   
    const materialData = await Products.getFinishedProductsDataByBarcode(materialBarcode);
    if (!materialData) {
      reply.send({ status: 0, message: "Catalog not available. Please try again with a valid Catalog." });
      return;
    }
    console.log('materialDatamaterialDatamaterialData',materialData)
   
    const material = materialData?.name;
    const materialId = materialData?.material_id;

    // Check if material exists in any product formula (recipe)
    const materialInRecipe = await Recipe.checkMaterialInRecipe(materialId);
    console.log('materialInRecipe', materialInRecipe);
    
    let selectedMaterials1 = await JobCost.fetchAllJobCostByProjectandMaterialId(projectId, materialId);
    console.log('selectedMaterials===1',selectedMaterials1)
    let selectedMaterials = selectedMaterials1?.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id) ? [selectedMaterials1.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id)] : [];
    console.log('selectedMaterials===1=taken 0',selectedMaterials)

    const customerOrderProductDetails = await CustomerOrderProduct.getCustomerOrderProductStockCatDetailsByMaterialInvId(projectId,materialData?.id)
    console.log('customerOrderProductDetails', customerOrderProductDetails)

    if (selectedMaterials.length === 0) {
      const normalize = (value) => value ?? '';
      const newmaterialsss = selectedMaterials1?.find(item => 
        item?.taken == 0 && 
        item?.quantity == 0 && 
        normalize(item?.partial_unit) === normalize(materialData?.partial_unit) && 
        item?.material_id == materialData?.material_id
      ) || null
      console.log('newmaterialsss---',newmaterialsss);
      if(newmaterialsss){
        const foundMaterial = selectedMaterials1?.find(item => 
          item?.taken === 0 &&
          item?.quantity === 0 &&
          normalize(item?.partial_unit) === normalize(materialData?.partial_unit) &&
          item?.material_id === materialData?.material_id
        ) || {};
        selectedMaterials = [{
            ...foundMaterial,
            barcode: materialBarcode,
            material_inventory_id: materialData?.id,
            product_id: materialData?.id,
            material_unit_cost : materialData?.unit_cost,
            unit_price: materialData?.unit_cost,
            actual_unit_price: materialData?.unit_cost,
            unit_cost: materialData?.unit_cost,
        }];
      }
    }

    let projectData = await Projects.getProjectById(projectId);
    const productData = await Products.findProductByName(material)
    let balanceQty =0
   

    if(productData){
      // const materialData = await Products.getFinishedProductsByProductId(productData?.id)
      let insertedstatus = null;
      if(selectedMaterials?.length > 0){
        let flag = 0;
        let selectedmaterialData = null;
        console.log('selectedMaterials===',selectedMaterials)
        for(const selectedMaterial of selectedMaterials){
          if(selectedMaterial?.taken == 1){
            flag = 1
            selectedmaterialData = selectedMaterial
          }else{
            flag = 0
            // if(taskId){
            // let theRealQty=(Number(qty || 1)) > selectedMaterial.actual_quantity?selectedMaterial.actual_quantity :(Number(qty || 1))
              let theRealQty = selectedMaterial.actual_quantity > 0 ? ((Number(qty || 1)) > selectedMaterial.actual_quantity ? selectedMaterial.actual_quantity : (Number(qty || 1))) : Number(qty || 1);
              balanceQty = selectedMaterial.actual_quantity > 0 ? (theRealQty > 0 ? ((Number(qty || 1)) - selectedMaterial.actual_quantity) : 0) : 0
        
              const actualQuantity = Number(selectedMaterial.quantity || 0) + (Number(theRealQty || 1));
              const actualUnitPrice = Number(materialData?.unit_cost || 0);
              const currentTotal = actualUnitPrice * (theRealQty || 1); //actualQuantity
              const prevTotal = Number(selectedMaterial?.total || 0);
              const actualTotal = currentTotal + prevTotal;
              let jobCostData = {
                quantity: actualQuantity,
                unit_price : actualUnitPrice,
                task_id:taskId || null,
                total: actualTotal,
                barcode: selectedMaterial?.barcode,
                product_id: selectedMaterial?.product_id
              };
              if (actualQuantity >= selectedMaterial.actual_quantity) {
                jobCostData.taken = 1;
              }
              insertedstatus = await JobCost.updateJobCost(jobCostData, selectedMaterial?.id);

              const materialStockData = await Products.getMaterialById(selectedMaterial?.material_inventory_id);
              console.log('materialStockData===',materialStockData);
              
              if(materialStockData && materialStockData?.length > 0){
                let newQty = materialStockData[0].qty - Number(theRealQty || 1)
                if (newQty >= 0) {
                  let totalCost = materialStockData[0].unit_cost * newQty
                  let data = {};
                  data['qty'] = newQty
                  data['total_cost'] = parseInt(totalCost)
                  const reduceStockResult = await Products.updateMaterialStock(selectedMaterial?.material_inventory_id, data);
                  // Autofill stock if stock is 0
                  if(newQty <= 0){
                    if(materialStockData[0]?.autofill == 1){
                      const parentFinishedMaterial = await Products.getMaterialById(materialStockData[0]?.parent_finished_product_id)
                      console.log('parentFinishedMaterial----',parentFinishedMaterial)
                      if (parentFinishedMaterial.length > 0 && parentFinishedMaterial[0]?.qty > 0) {
                        let reducedQty = parentFinishedMaterial[0]?.qty - 1
                        let parentTotalCost = parentFinishedMaterial[0]?.unit_cost * reducedQty
                        let parentData = {
                          qty: reducedQty,
                          total_cost: parseInt(parentTotalCost)
                        };
                        const reduceFinishedProductStock = await Products.updateMaterialStock(materialStockData[0]?.parent_finished_product_id, parentData)
        
                        let addingQty = materialStockData[0]?.actual_qty
                        let totalCost = materialStockData[0]?.actual_total_cost
                        let autoFilldata = {
                          qty: addingQty,
                          total_cost: totalCost
                        };
                        console.log('autofillPartialStock--',autoFilldata);
                        const autofillPartialStock = await Products.updateMaterialStock(materialStockData[0]?.id, autoFilldata);
                      }
                    }
                  }
                }else{
                  // Autofill stock if stock is 0
                  if(newQty <= 0){
                    if(materialStockData[0]?.autofill == 1){
                      const parentFinishedMaterial = await Products.getMaterialById(materialStockData[0]?.parent_finished_product_id)
                      console.log('parentFinishedMaterial----',parentFinishedMaterial)
                      if (parentFinishedMaterial.length > 0 && parentFinishedMaterial[0]?.qty > 0) {
                        let reducedQty = parentFinishedMaterial[0]?.qty - 1
                        let parentTotalCost = parentFinishedMaterial[0]?.unit_cost * reducedQty
                        let parentData = {
                          qty: reducedQty,
                          total_cost: parseInt(parentTotalCost)
                        };
                        const reduceFinishedProductStock = await Products.updateMaterialStock(materialStockData[0]?.parent_finished_product_id, parentData)
        
                        let addingQty = materialStockData[0]?.actual_qty
                        let totalCost = materialStockData[0]?.actual_total_cost
                        let autoFilldata = {
                          qty: addingQty,
                          total_cost: totalCost
                        };
                        console.log('autofillPartialStock--',autoFilldata);
                        const autofillPartialStock = await Products.updateMaterialStock(materialStockData[0]?.id, autoFilldata);
                      }
                    }
                  }
                }
              }
            // }
            break;
          }
        }
        if(flag == 1){
          reply.send({ status: 2, message: "Catalog already taken in this Job. Do you want to add it as additional catalog?", materialData : selectedmaterialData });
          return;
        }

      }else if(customerOrderProductDetails?.length > 0){
        let incommingQty = qty
        let totalAvailableStock =materialData.qty
        let flag = 0
        let selectedstockCatalogData = []
        for(const stockCatalog of customerOrderProductDetails){
        if(incommingQty > totalAvailableStock){
          reply.send({ status: 0, message: "Catalog is out of stock. Please try again after updating the stock" });
        }else{
          let totalQty = Number(stockCatalog?.jobcost_quantity ?? 0) + incommingQty
          const updateData={
            jobcost_quantity: totalQty,
            jobcost_total_cost: Number(stockCatalog?.product_price ?? 0)  * totalQty,
            taken:totalQty >=stockCatalog.location_quantity ? 1 : 0
          }
          const updateRes = await CustomerOrderProduct.updateCustomerOrderProduct(updateData,stockCatalog.id);
          if(updateRes){
            reply.send({ status: 1,message:"Job cost updated successfully" });
          }else{
            reply.send({ status: 0, message: "Failed to update Job cost" });
          }
        }
          
        }
      }else{
       

        // Material is in product formula, show normal confirmation
        (projectData?.job_category_name == 'Time & Material') ?
          reply.send({ status: 3, message: `Do you want to add ${qty} quantity of ${material} to Catalog?`, materialData : materialData })
        :
          reply.send({ status: 3, message: `Do you want to add ${qty} quantity of ${material} to Catalog?`, materialData : materialData })
        return;
      }
      if (insertedstatus) {

        // Add log after updating the material
        const updatedMaterial = selectedMaterials[0];  // Assuming the first selected material is updated
        const logMessage = `Catalog '${updatedMaterial.name}' has been updated in job cost for project '${projectData?.name}'. 
        Updated quantity: ${updatedMaterial.quantity}, Total cost: $${updatedMaterial.total.toFixed(2)}`;
        await JobCost.addJobCostLog({
          message: sanitizeLog(logMessage),
          user_id: userId,
          timestamp: moment().unix(),
          status: 1,
          project_id: projectId,
        });

        const notificationMsg = `Job cost has been updated for job '${projectData?.name}'`;
        let notificationUrl = "project/view-project/job-cost/" + projectId;
        const incrementResult_User = await Admin.incrementField(
          userId,
          "noti_count",
          1
        );

        let notificationData_user = {
          user_id: userId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };
        const addNotificationResult_user = await Admin.addNotification(
          notificationData_user
        );
        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};

        for (const adminId of adminIds) {
          if (adminId != userId) {
            const incrementResult = await Admin.incrementField(
              adminId,
              "noti_count",
              1
            );

            notificationData = {
              user_id: adminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        if (balanceQty > 0) {
          materialData.balanceQty = balanceQty; // Add balanceQty to materialData
          reply.send({
              status: 4,
              message: `The Stock was updated Successfully. Would you like to proceed to add the balance Qty(${balanceQty}) `,
              materialData: materialData
          });
      }else{

        reply.send({ status: 1, message: notificationMsg })
      }

        return;
      } else {
        console.log('Failed to update Job cost');
        reply.send({ status: 0, message: " Failed to update Job cost " });
      }
    }else{
      reply.send({ status: 0, message: "Catalog not available. Please try again with a valid catalog." });
    }
  } catch (error) {
    console.log("Error", error);
    reply.send({ status: 500, message:'Error',error:error });
  }
};

// const updateProductInJobcost = async (req, reply) => {
//   try {
//     let { materialBarcode, userId, projectId, taskId, qty } = req.body;
//     const qtyNum = Number(qty) || 0;
//     let projectData = await Projects.getProjectById(projectId);
//     console.log('projectData', projectData)
//     const request_id = projectData.request_id || null
//     const Product = await Products.getProductByBarcode(materialBarcode);
//     console.log('Productsss', Product)
//     if (!Product) {
//       reply.send({ status: 0, message: "Product not available. Please try again with a valid product." });
//       return;
//     }
//     const ProductData = await Products.getProductDataByBarcode(materialBarcode, request_id);
//     if (!ProductData) {
//       reply.send({ status: 0, message: "Product not available in jobcost. Please try again with a available product." });
//       return;
//     }
//     console.log('ProductDataProductDataProductData', ProductData)
//     const isStock = qtyNum <= Number(ProductData?.in_stock_no ?? 0)
//     if (isStock) {
//       if (ProductData?.taken !== 1) {
//         const updateData = {
//           id: ProductData.id,
//           // jobcost_quantity: Number(ProductData.jobcost_quantity) + qtyNum,
//           // jobcost_total_cost: Number(ProductData.jobcost_total_cost) +(Number(ProductData.product_retail_price) * qtyNum),
//           jobcost_quantity: Number(ProductData.jobcost_quantity ?? 0) + qtyNum,
//           jobcost_total_cost:
//             Number(ProductData.jobcost_total_cost ?? 0) +
//             (Number(ProductData.product_retail_price ?? 0) * qtyNum),
//           taken: 1
//         };
//         console.log('updateDataddddddddd', updateData)
//         try {
//           const updateRes = await CustomerOrderProduct.updateCustomerOrderProduct(updateData, ProductData.id);
//           console.log('updateRes', updateRes)

//           if (updateRes) {
//             const remainingStock = Number(ProductData.in_stock_no) - qtyNum;
//             const res = await Products.StockUpdate(remainingStock, ProductData.product_id);
//             console.log(`updated stock ${remainingStock}`, res);
//             reply.send({ status: 1, message: `The Stock was updated Successfully`, });
//           } else {
//             console.warn(`Update skipped for product ID ${ProductData.id}: update failed or returned no success flag.`);
//           }

//         } catch (error) {
//           console.error(`Failed to update product ID ${ProductData.id}:`, error);
//         }
//       } else {
//         reply.send({ status: 0, message: "Product is already taken" });
//       }
//     } else {
//       reply.send({ status: 0, message: "Product is out of stock. Please try again after updating the stock" });
//     }
//     // const material = ProductData?.name;
//     // const materialId = ProductData?.material_id;
//     // let selectedMaterials1 = await JobCost.fetchAllJobCostByProjectandMaterialId(projectId, materialId);
//     // console.log('selectedMaterials===1',selectedMaterials1)
//     // let selectedMaterials = selectedMaterials1?.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id) ? [selectedMaterials1.find(item => item?.taken == 0 && item.material_inventory_id == materialData?.id)] : [];

//     const updatedProduct = ProductData;  // Assuming productData contains the updated product
//     const logMessage = `Product '${updatedProduct.name}' has been updated in job cost for project '${projectData?.name}'. 
//     Updated quantity: ${updatedProduct.quantity}, Total cost: $${updatedProduct.total?.toFixed(2)}`;
//     await JobCost.addJobCostLog({
//       message: sanitizeLog(logMessage),
//       user_id: userId,
//       timestamp: moment().unix(),
//       status: 1,
//       project_id: projectId
//     });

//   } catch (error) {
//     console.log("Error", error);
//     reply.send({ status: 500, message: 'Error', error: error });
//   }
// };

const viewAddedMaterialInTask = async (req,res) =>{
  try{
    const {projectId, taskId} = req.body;
    const result = await JobCost.viewAddedMaterialInTask(projectId,taskId);
    if(result){
      res.send({ status:1, result:result, message:'Data fetched successfully' });
    }else{
      res.send({ status:0, message:'Failed to fetch data' });
    }
  }catch(error){
    console.log('Error : ',error);
    res.send({ status:500, message:'Failed to fetch data', error:error })
  }
}

const updateJobCostStatusController = async (req, res) => {
  const { jobCostId, user_id } = req.body;

  if (!jobCostId) {
    return res.send({ status: 0, message: "Job cost ID is required." });
  }

  try {
    const projectAndRecipeDetails = await JobCost.getProjectAndRecipeDetails(jobCostId);

    if (!projectAndRecipeDetails) {
      return res.send({ status: 0, message: "Project, recipe, material, or service not found." });
    }

    const { project_name, material_name, recipe_name, item_type, project_id } = projectAndRecipeDetails;

    // Fetch user name based on the user_id
    const userName = await Admin.getUserNameById(user_id);

    let result = false;
    
    if (item_type === 'service') {
      // For services, update the status in request_services table
      const Request = require("../models/request");
      result = await Request.updateRequestServiceStatus(jobCostId);
    } else {
      // For materials, update the status in job_costs table
      result = await JobCost.updateJobCostStatus(jobCostId);
    }

    if (result) {
      const itemTypeText = item_type === 'service' ? 'service' : 'material';
      const logMessage = `Deleted ${itemTypeText} '${material_name}' from project '${project_name}' by user '${userName}'`;

      const logData = {
        message: logMessage,
        user_id: user_id, 
        timestamp: Math.floor(Date.now() / 1000),
        status: 1,
        project_id: project_id,
      };

      await JobCost.addJobCostLog(logData);

      return res.send({ status: 1, message: `${itemTypeText} status updated successfully.` });
    } else {
      return res.send({ status: 0, message: `Failed to update ${item_type} status.` });
    }
  } catch (error) {
    console.error("Error in updateJobCostStatusController:", error);
    return res.send({ status: 0, message: "Error in updating status." });
  }
};

const addStickyNote = async (req, res) => {
  try {
    const { sticky_note, added_by, project_id } = req.body;  
    if (!sticky_note || !added_by || !project_id) {
      return res.status(400).send({ status: 0, message: "Content, Added By, and Project ID are required" });
    }

    const stickyNoteData = {
      sticky_note,
      added_by,
      project_id,
      status: 1,
      timestamp: Math.floor(Date.now() / 1000),
    };

    const stickyNoteId = await JobCost.addStickyNote(stickyNoteData);

    const userName = await Admin.getUserNameById(added_by);

    const logMessage = `Sticky Note has been added by user '${userName}' with content: '${sticky_note}'`;
    await JobCost.addJobCostLog({
      message: sanitizeLog(logMessage),
      user_id: added_by,
      timestamp: moment().unix(),
      status: 1,
      project_id: project_id,
    });

    res.send({ status: 1, message: "Sticky Note added successfully", id: stickyNoteId });
  } catch (error) {
    console.error('Error adding sticky note:', error);
    res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const editStickyNote = async (req, res) => {
  try {
    const { id, sticky_note, updated_by, project_id } = req.body;

    if (!id || !project_id) {
      return res.status(400).send({ status: 0, message: "ID and Project ID are required" });
    }

    // First verify that the sticky note belongs to the specified project
    const existingNote = await JobCost.getStickyNote(project_id);
    if (!existingNote || existingNote.id != id) {
      return res.status(400).send({ status: 0, message: "Sticky note not found for this project" });
    }

    const stickyNoteData = {
      sticky_note: sticky_note || null,
      updated_by: updated_by || null,
      updated_on: Math.floor(Date.now() / 1000), // Set updated_on here
    };

    const result = await JobCost.editStickyNote(id, stickyNoteData);

    // Fetch the user's name
    const userName = await Admin.getUserNameById(updated_by);

    // Log the sticky note update action
    const logMessage = `Sticky Note has been updated by user '${userName}' with content: '${sticky_note}'`;
    await JobCost.addJobCostLog({
      message: sanitizeLog(logMessage),
      user_id: updated_by,
      timestamp: moment().unix(),
      status: 1,
      project_id: project_id,
    });

    if (result) {
      res.send({ status: 1, message: "Sticky Note updated successfully" });
    } else {
      res.send({ status: 0, message: "Failed to update Sticky Note" });
    }
  } catch (error) {
    console.error('Error editing sticky note:', error);
    res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const fetchStickyNote = async (req, res) => {
  try {
    const { project_id } = req.body;
    
    if (!project_id) {
      return res.status(400).send({ status: 0, message: "Project ID is required" });
    }

    const stickyNote = await JobCost.getStickyNote(project_id);
    if (stickyNote) {
      res.send({ status: 1, data: stickyNote });
    } else {
      res.send({ status: 0, message: "No sticky note found for this project" });
    }
  } catch (error) {
    console.error('Error fetching sticky note:', error);
    res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const addJobCostLogController = async (req, res) => {
  try {
    const { message, user_id } = req.body;
    if (!message || !user_id) {
      return res.status(400).send({ status: 0, message: "message and user_id are required" });
    }

    const data = {
      message,
      user_id,
      timestamp: Math.floor(Date.now() / 1000),
      status: 1
    };

    const id = await JobCost.addJobCostLog(data);
    return res.send({ status: 1, message: "Job cost log added successfully", id });
  } catch (error) {
    console.error("Error adding job cost log:", error);
    return res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const fetchJobCostLogsController = async (req, res) => { 
  try {
    const { projectId, isMirrored, targetFacilityId } = req.body;  // Get projectId from request body
    if (!projectId) {
      return res.status(400).send({ status: 0, message: "Project ID is required" });
    }

    if(isMirrored && targetFacilityId ){
      const targetFacility = filteredSignwiseInstalations.find(
        f => f.id === Number(targetFacilityId)
      );
      if (!targetFacility?.url) return null;
      const projectResponse = await axios.post(
        `${targetFacility.url}project/get-job-cost-logs`,
        {
          projectId: projectId
        }
      );
      if(projectResponse?.data){
        return res.send({ status: 1, data: projectResponse?.data?.data })
      }else{
        return res.send({ status: 0, message: "Failed to fetch users by task" })
      }
    }
    const logs = await JobCost.getJobCostLogs(projectId);  // Pass projectId to the model function
    return res.send({ status: 1, data: logs });
  } catch (error) {
    console.error("Error fetching job cost logs:", error);
    return res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const fetchAllFutureInstallations = async (req, res) => {
  try {
    const {projectId} = req.body;
    const futureInstallationProducts = await JobCost.getFutureInstallationProducts(projectId);
    const futureInstallationServices = await JobCost.getFutureInstallationServices(projectId);
    const futureInstallation = [...futureInstallationProducts, ...futureInstallationServices];
    return res.send({ status: 1,  futureInstallation });

  }catch(error){
    console.error("Error fetching all future installations:", error);
    return res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
}

module.exports = { addJobCost, fetchAllJobCostByProjectId, fetchDataForPayOut, fetchAllProjectTaskById,fetchAllFutureInstallations, 
  addPayOut,fetchAllPayOut,updatePayOut,getPayOutById, updateMaterialInJobcost, viewAddedMaterialInTask,updateProductInJobcost, updateJobCostStatusController,addStickyNote,editStickyNote, fetchStickyNote, addJobCostLogController, fetchJobCostLogsController};
