const { empty, removeNull } = require('../Helpers/Common');
const Project = require('../models/Projects');
const Requests = require('../models/request');
const Admin = require('../models/admin');
const Driver = require('../models/driver');
const Routes = require('../models/routes');
const moment = require('moment');
const Installation = require(`../models/installation`)
const CustomFieldTemplate = require('../models/customFieldTemplate')
const uniqid = require('uniqid');
const ProjectTask=require('../models/projectTask')
const admin = require('firebase-admin');
const { default: axios } = require('axios');
const fs = require('fs');
const path = require('path');
const crypto = require("crypto");
const Route = require('../models/routes')
const Client = require("../models/client");
const installation = require('../routes/installation');
const stripHTMLTags = (str) => str.replace(/<[^>]*>?/gm, '');
const RequestPartner = require('../models/requestPartners');
const RequestUpdates = require('../models/requestUpdates')
const Product = require('../models/product')
const { io: ioClient } = require('socket.io-client');
const { DOMAIN } = require('../constants/constant');
const CustomerOrderProduct = require('../models/customerOrderProduct')
const REST_API_IO = DOMAIN === "localhost" ? "http://localhost:4000" : 'https://socket.signwisesolutions.com';
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 Request = require("../models/request");
const { newEstimateCreatedEmailTemplate, newInstallsCreatedEmailTemplate, finalInvoiceApprovedEmailTemplate, salesOrderMovedToInvoicingEmailTemplate } = require('../constants/emailTemplates');
const { BASE_URL, TWILIO_PHONE, MAPBOX_ACCESS_TOKEN } = require('../constants/constant');
const nodemailer = require('nodemailer');
const { sendMessageToPhoneNumber } = require('./teams');
const { transferProductStockToOtherInstallation, updateMirrorOrderStatusFromOtherInstallations } = require('./SplitManagementController.js');
const SplitManagementModel = require('../models/SplitManagementModel.js');
const { FACILITY_ID } = require('../config/SplitManagementDb.js');
const Settings = require('../models/settings');
const RequestActivity = require('../models/RequestActivity.js');

const transporter = nodemailer.createTransport({
  host: 'mail.signwisesolutions.com', 
  port: 465, 
  secure: true, 
  auth: {
    user: 'noreply@signwisesolutions.com', 
    pass: 'signwise@2024', 
  },
});

// --- Helpers for sendInstallPhotosToEmail ---
function isUrlString(str) {
  return typeof str === 'string' && str.trim().length > 0 && (str.trim().startsWith('http://') || str.trim().startsWith('https://'));
}
async function downloadFileFromUrl(fileUrl, savePath) {
  try {
    const response = await axios.get(fileUrl, { responseType: 'arraybuffer', timeout: 30000 });
    fs.writeFileSync(savePath, response.data);
    return savePath;
  } catch (err) {
    console.error('Error downloading install photo:', err.message);
    return null;
  }
}
function getInstallPhotoExtension(urlOrFile) {
  const url = typeof urlOrFile === 'string' ? urlOrFile : (urlOrFile?.value || urlOrFile?.name || '');
  if (!url) return 'jpg';
  const fileName = url.split('/').pop().split('?')[0];
  const ext = fileName.split('.').pop()?.toLowerCase();
  return ext && /^[a-z0-9]+$/i.test(ext) ? ext : 'jpg';
}
function getInstallPhotoFileName(urlOrFile, index) {
  const url = typeof urlOrFile === 'string' ? urlOrFile : (urlOrFile?.value || urlOrFile?.name || '');
  if (url) {
    const parts = url.split('/');
    const name = parts[parts.length - 1].split('?')[0];
    if (name) return name;
  }
  return `install_photo_${index}.jpg`;
}
function getInstallPhotoContentType(ext) {
  const e = (ext || '').toLowerCase();
  if (e === 'pdf') return 'application/pdf';
  if (['jpg', 'jpeg'].includes(e)) return 'image/jpeg';
  if (e === 'png') return 'image/png';
  if (e === 'gif') return 'image/gif';
  return 'application/octet-stream';
}

/**
 * Send install photos from template submission to company install_address_email.
 * Called after saveInstTemplate succeeds. Does not block or alter response.
 */
const sendInstallPhotosToEmail = async (submitForm, installation_id, installation, currentDate) => {
  try {
    if (!submitForm || typeof submitForm !== 'object') return;
    const profileData = await Settings.getCompanyProfileDetails();
    const installEmail = (profileData && profileData[0] && profileData[0].install_address_email) ? String(profileData[0].install_address_email).trim() : '';
    if (!installEmail) return;

    const photoUrls = [];
    const valueData = removeNull(submitForm);
    for (const [, value] of Object.entries(valueData)) {
      if (value && typeof value === 'object' && 'value' in value) {
        const v = value.value;
        if (isUrlString(v)) photoUrls.push({ url: v.trim(), file: value });
        else if (Array.isArray(v)) {
          v.forEach((item) => {
            const u = item && typeof item === 'object' ? item.value : item;
            if (isUrlString(u)) photoUrls.push({ url: u.trim(), file: item });
          });
        }
      } else if (isUrlString(value)) {
        photoUrls.push({ url: value.trim(), file: { value: value } });
      } else if (value && Array.isArray(value)) {
        value.forEach((item) => {
          const u = item && typeof item === 'object' ? item.value : item;
          if (isUrlString(u)) photoUrls.push({ url: u.trim(), file: item });
        });
      }
    }
    if (photoUrls.length === 0) return;

    const tempDir = path.join(__dirname, '../uploads/temp');
    if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });

    const attachments = [];
    const downloadedFiles = [];
    const timestamp = currentDate || moment().unix();
    for (let i = 0; i < photoUrls.length; i++) {
      const { url, file } = photoUrls[i];
      const ext = getInstallPhotoExtension(file);
      const fileName = getInstallPhotoFileName(file, i + 1);
      const tempFilePath = path.join(tempDir, `install_${timestamp}_${i}_${fileName}`);
      const downloadedPath = await downloadFileFromUrl(url, tempFilePath);
      if (downloadedPath) {
        attachments.push({
          filename: fileName,
          path: downloadedPath,
          contentType: getInstallPhotoContentType(ext),
        });
        downloadedFiles.push(downloadedPath);
      }
    }
    if (attachments.length === 0) return;

    const installationName = installation && (installation[0]?.name || installation[0]?.product_name || installation[0]?.service_name) ? installation[0].name || installation[0].product_name || installation[0].service_name : 'Installation';
    const subject = `Install photos – ${installationName} (ID: ${installation_id})`;
    const emailHtml = `
      <!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="font-family: Arial, sans-serif;">
        <p>Installation template has been submitted.</p>
        <p><strong>Installation:</strong> ${installationName}</p>
        <p><strong>Installation ID:</strong> ${installation_id}</p>
        <p>This email contains ${attachments.length} photo/file(s) as attachments.</p>
      </body></html>`;

    const mailOptions = {
      from: '"SignWise Solutions" <noreply@signwisesolutions.com>',
      to: installEmail,
      subject,
      text: subject,
      html: emailHtml,
      attachments,
    };
    await transporter.sendMail(mailOptions);
    console.log(`Install photos email sent to ${installEmail} for installation_id ${installation_id}`);
    downloadedFiles.forEach((filePath) => {
      try {
        if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
      } catch (e) {
        console.error('Cleanup temp file:', e.message);
      }
    });
  } catch (err) {
    console.error('sendInstallPhotosToEmail error:', err);
  }
};

const addApointment = async (request, reply) => {
  try {
    let flag=0;
    let currentDate = moment().unix();
    let values =request.body
    let userId =request.body.userId
    let locationData=values.locationData
    let i=0
    let data = {};

    console.log('valuesvaluesvalues',values)

    for(let i=0;i<locationData.length;i++){
      data.address = locationData[i].address
      data.city = locationData[i].city
      data.state = locationData[i].state
      data.zipcode = locationData[i].zip
      data.name=values.name
      
      // data.long = values.long
      // data.lat = values.lat
      data.project_id = values.project_id
      data.request_id = values.request_id
      data.product_id = values.product_id
      data.labour_cost_service_id = values.labour_cost_service_id
      data.product_index = locationData[i].product_index
      data.location_id =  locationData[i].id
      data.installation_date = values.installation_date
      data.installation_temp_id = values.installation_temp_id
      data.source = values.source || 1
      data.due_date = values.due_date
      data.team_id = values.team_user_id||values.team.map(driver => driver.user_id).join(",")
      data.driver_id = values.isDriver ?values.team.map(driver => driver.id).join(",") : null
      data.route_id = values.isDriver ? values.route?.id : null
      data.order_information = values.order_information
      data.added_by = userId
      data.timestamp = moment().unix()
      data.status = (values.isDriver && values.route?.id) ? 6 : 1
      data.driver_is_installer = values.isDriver ? 2 : 1
      data.location_quantity = locationData[0]?.location_quantity || 1

      let result = []
      // for(let i=0; i<locationData[0]?.location_quantity;i++ ){
      console.log("dataaaaaaaaaaaaaaaaaaaaa 1",data)
        let resultData = await Installation.addInstallationAppointment(data);
        result.push(resultData)
      // }
      // if (result?.length == locationData[0]?.location_quantity) {
      if (result?.length == 1) {
        flag=1
        let projectData={
          installation_date:values.installation_date, 
        }
        let result = await Project.updateProject(values.project_id, projectData);
          let notificationMsg = `New Appointment to the "${data.address}" has been added.`;
          let notificationUrl = "installation";
        
          const incrementResult_User = await Admin.incrementField(userId, "noti_count", 1);
          console.log("incrementResult--to--user-----------", incrementResult_User)
          let notificationData_user = {
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
          };
          console.log("notificationData--user------------", notificationData_user)
          const addNotificationResult_user = await Admin.addNotification(notificationData_user);
          console.log("addNotificationResult--user-------", addNotificationResult_user)

          // Alert to all admins of new added project

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          console.log("adminIds====", adminIds)
          for (const adminId of adminIds) {
              console.log("adminId----------", adminId)
              if (adminId != userId) {
                  const incrementResult = await Admin.incrementField(adminId, "noti_count", 1);
                  console.log("incrementResult-------------", incrementResult)
                  notificationData = {
                      user_id: adminId,
                      url: notificationUrl,
                      timestamp: currentDate,
                      message: notificationMsg,
                      status: 1,
                      from_id: userId,
                  };
                  console.log("notificationData------------", notificationData)
                  const addNotificationResult = await Admin.addNotification(notificationData);
                  console.log("addNotificationResult-------", addNotificationResult)
              }
          }
          
      }
    }

    if (flag===1) {
      reply.send({ status: 1, message: `New Appointments has been added.` })
    }
    else {
      reply.send({ status: 0, message: "Failed to take an apointment" });
    }
  } catch (error) {
      console.log("Server error", error);
      reply.status(500).send({ message: "Server error"+error });
  }
}

const getAllProjectsInstallation=async(req,reply)=>{
  let{userId,userType}=req.body
  let productData = await Installation.getAllProjects(userType, userId);
  let serviceData = await Installation.getAllServiceProjects(userType, userId);
  let data  = [...productData,...serviceData]
  let TeamMembers= await Project.getTeamMembers(19);
  let allDrivers= await Driver.getAllDrivers();
  let allRoutes = await Routes.getAllRoutes()

  if(data){
    reply.send({ status:1, results:data, TeamMembers, allDrivers, allRoutes, filteredProjects: [],productData,serviceData })
  }
}

const getAllTeamAndDrivers=async(req,reply)=>{
  let TeamMembers= await Project.getTeamMembers(19);
  let allDrivers= await Driver.getAllDrivers();
  reply.send({ status:1, TeamMembers, allDrivers })
}

const getProductsById=async(req,reply)=>{
  let{orderId,requestId}=req.body
  let data=await Installation.getProducts(orderId)
  let serviceData = await Installation.getServices(requestId)

  if(data){
    reply.send({ status:1, results:data ,serviceData})
  }
}
const getLocationsById=async(req,reply)=>{
  let{orderId,productId,serviceId,serviceOrderId}=req.body
  let data= []
  
  if(orderId && productId){
    data = await Installation.getLocations(orderId,productId)
  }
  console.log(serviceOrderId,serviceId,'dataaaaaaaaaaaaaaa')

  let serviceData =[]
  if(serviceOrderId && serviceId){

    serviceData = await Installation.getServiceLocations(serviceOrderId,serviceId)
  }

  if(data){
    reply.send({ status:1, results:data,serviceData })
  }
}
const getTotalPaidAmountByRequestId=async(req,reply)=>{
  let{requestId}=req.body
  let data=await Installation.getTotalPaidAmountByRequestId(requestId)

  if(data){
    reply.send({ status:1, results:data })
  }
}

const getAllCustomerOrders = async (req,reply) => {
  try{
    let data=await Installation.getAllCustomerOrders()
    let allInstallation=await Installation.fetchAllApointments()
    let filteredProjects = data?.filter(project => {
      return !allInstallation.some(installation => installation.project_id === project.id);
    });
    if(data){
      reply.send({ status:1, results:data, filteredProjects:filteredProjects, allInstallation:allInstallation })
    }
  }
  catch(error){
    console.log("getAllCustomerOrders Error - ",error)
  }
}

const fetchAllApointments=async(req,reply)=>{
  try{
     
      const userId = req.body.userId.value
      let page = req.body.page
      let rowsPerPage = req.body.rowsPerPage
      const userType = req.body.userType.value
      const hasPermission = req.body.hasPermission || false
      let sort = req.body.sort
      let fromDate = req?.body?.from
      let toDate = req?.body?.to
      let tab = req?.body?.tab
      let project_id = req?.body?.project_id
      let dueData = req?.body?.dueData;
      let search = req?.body?.search;
      let complete_status= req?.body?.complete_status
      let filterClient = req?.body?.filterClient
      let filterProjectType = req?.body?.filterProjectType
      // let userId=301,userType=19
      let [appointments, totalCount, reviewTotalCount, clients] = await Promise.all([
        Installation.fetchAllApointments(userId,userType,hasPermission,page,rowsPerPage,sort,fromDate,toDate,tab,project_id,dueData,search,complete_status,filterClient, filterProjectType),
        Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,tab,project_id,search,complete_status,filterClient, filterProjectType),
        Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,'Review',project_id,search,complete_status,filterClient, filterProjectType),
        Client.getAllClientsDataFilters(),
      ]);

      let completedTotalCount = 0
      let ongoingTotalCount = 0
      let inTransitTotalCount =0
      let awaitingTotalCount = 0
      let deliveredTotalCount = 0
      let failedTotalCount = 0
      let assignedTotalCount = 0
      let allTotalCount = 0

      // let allAppointments=await Installation.fetchAllApointmentsForFilter(userId,userType,hasPermission,sort,fromDate,toDate,tab,complete_status);
      let allAppointments = [];
      // for (const appointment of appointments) {
      //   if (!allAppointments.some(a => a.project_id === appointment.project_id)) {
      //     allAppointments.push(appointment);
      //   }
      // }
      // Add attachments for each appointment to avoid frontend API calls
      const nonImageExts = new Set(["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt"]);
      const attachmentsCache = new Map();
      const updatesCache = new Map();
      const projectFilesCache = new Map();
      const requestFilesCache = new Map();

      const getCachedPromise = (cache, key, fetcher) => {
        if (!cache.has(key)) {
          cache.set(key, fetcher());
        }
        return cache.get(key);
      };

      await Promise.all(appointments.map(async (appointment) => {
        try {
          const attachmentKey = `${appointment.request_id}:${appointment.isFromDesignOrder ? 1 : 0}`;
          const [attachment, updates, projectFiles, reqAttachmentsFiles] = await Promise.all([
            getCachedPromise(
              attachmentsCache,
              attachmentKey,
              () => Request.getAllRequestAttachmentsForCards(appointment.request_id, appointment.isFromDesignOrder || false)
            ),
            getCachedPromise(
              updatesCache,
              appointment.request_id,
              () => RequestUpdates.fetchAllUpdates(5, appointment.request_id, null, null, userId, userType)
            ),
            getCachedPromise(
              projectFilesCache,
              appointment.project_id,
              () => Installation.getProjectFilesByProjectId(appointment.project_id)
            ),
            getCachedPromise(
              requestFilesCache,
              appointment.project_id,
              () => ProjectTask.fetchAllFilesFromRequest(null, appointment.project_id)
            ),
          ]);

          appointment.attachmentsData = attachment || [];
          appointment.updates = updates || [];
          appointment.projectFiles = projectFiles && projectFiles.length > 0 ? projectFiles : [];

          const files = (reqAttachmentsFiles || []).filter((file) => (
            nonImageExts.has(file.extension?.toLowerCase())
          ));

          appointment.hasProjectFiles = ((projectFiles && projectFiles.length) || files.length) > 0 ? 1 : 0;
        } catch (error) {
          console.log('Error fetching attachments/updates for appointment:', appointment.id, error);
          appointment.attachmentsData = [];
          appointment.updates = [];
          appointment.projectFiles = [];
          appointment.hasProjectFiles = 0;
        }
      }));
      
      reply.send({status:1,appointments,userType,userId,totalCount,reviewTotalCount,completedTotalCount, ongoingTotalCount,
        inTransitTotalCount,awaitingTotalCount,deliveredTotalCount,failedTotalCount,assignedTotalCount,
        allTotalCount,allAppointments, filteredProjects : [] ,clients
      })
  }catch(error){
      console.log("getAllCustomerOrders Error - ",error)
      reply.send({status:500,message:error})
  }
}
const fetchAllApointmentsFilter=async(req,reply)=>{
  try{
      const userId = req.body.userId.value
      const userType = req.body.userType.value
      const hasPermission = req.body.hasPermission || false
      let sort = req.body.sort
      let fromDate = req?.body?.from
      let toDate = req?.body?.to
      let tab = req?.body?.tab
      let complete_status= req?.body?.complete_status
      
      const allAppointments = await Installation.fetchAllApointmentsForFilter(
        userId,
        userType,
        hasPermission,
        sort,
        fromDate,
        toDate,
        tab,
        complete_status
      );

      reply.send({ status:1, allAppointments })
  }catch(error){
      console.log("getAllCustomerOrders Error - ",error)
      reply.send({status:500,message:error})
  }
}
//previos function
// const fetchAllApointmentsCalendar=async(req,reply)=>{
//   try{
     
//       const userId = req.body.userId.value
//       let page = req.body.page
//       let rowsPerPage = req.body.rowsPerPage
//       const userType = req.body.userType.value
//       const hasPermission = req.body.hasPermission || false
//       let sort = req.body.sort
//       let fromDate = req?.body?.from
//       let toDate = req?.body?.to
//       let tab = req?.body?.tab
//       let project_id = req?.body?.project_id
//       let dueData = req?.body?.dueData;
//       let search = req?.body?.search;
//       let complete_status= req?.body?.complete_status
//       let filterClient = req?.body?.filterClient
//       let filterProjectType = req?.body?.filterProjectType
      
//       // Handle month-based filtering for calendar
//       let currentMonth = req?.body?.currentMonth;
//       if (currentMonth) {
//         const moment = require('moment');
//         const currentDate = moment(currentMonth, 'YYYY-MM');
//         const prevMonth = currentDate.clone().subtract(1, 'month');
//         const nextMonth = currentDate.clone().add(1, 'month');
        
//         // Set date range to cover previous, current, and next month
//         fromDate = prevMonth.startOf('month').format('YYYY-MM-DD');
//         toDate = nextMonth.endOf('month').format('YYYY-MM-DD');
//       }
//       // let userId=301,userType=19
//       let appointments=await Installation.fetchAllApointments(userId,userType,hasPermission,page,rowsPerPage,sort,fromDate,toDate,tab,project_id,dueData,search,complete_status,filterClient, filterProjectType);
//       // let totalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,tab,project_id,search,complete_status,filterClient, filterProjectType) 

//       // let completedTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Completed",project_id,search,complete_status) 
//       // let ongoingTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Ongoing",project_id,search,complete_status) 
//       // let inTransitTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"In-transit",project_id,search,complete_status) 
//       // let awaitingTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Awaiting",project_id,search,complete_status) 
//       // let deliveredTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Delivered",project_id,search,complete_status) 
//       // let failedTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Failed",project_id,search,complete_status) 
//       // let assignedTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Assigned",project_id,search,complete_status) 
//       // let allTotalCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"All",project_id,search,complete_status) 

//       // let completedTotalCount = 0
//       // let ongoingTotalCount = 0
//       // let inTransitTotalCount =0
//       // let awaitingTotalCount = 0
//       // let deliveredTotalCount = 0
//       // let failedTotalCount = 0
//       // let assignedTotalCount = 0
//       // let allTotalCount = 0

//       // let allAppointments=await Installation.fetchAllApointmentsForFilter(userId,userType,hasPermission,sort,fromDate,toDate,tab,complete_status);
     
//       let results = await Project.getAllProjects(hasPermission, true, userType, userId,null,'new',fromDate,toDate,false);
//       let allInstalation = await Installation.fetchAllApointments(userId, userType, hasPermission,complete_status)
//       let filteredProjects = results.filter(project => {
//         return !allInstalation.some(installation => installation.project_id === project.id);
//       });
      
//       // Fetch services separately like filteredProjects
//       let servicesData = await Installation.getAllServicesForCalendar(hasPermission, userType, userId, fromDate, toDate);
//       let installServicesData = await Installation.getAllInstallServicesForCalendar(hasPermission, userType, userId, fromDate, toDate);
//       let allInstallationServices = await Installation.fetchAllApointments(userId, userType, hasPermission, complete_status);
//       let filteredServices = servicesData.filter(service => {
//         // if (service.project_category !== 11 && service.labour_cost_service_id == 10) {
//         //   return false; 
//         // }
//         return !allInstallationServices.some(installation => installation.project_id === service.project_id);
//       });
//       let filteredInstallServices = installServicesData.filter(service => {
//         // if (service.project_category !== 11 && service.labour_cost_service_id == 10) {
//         //   return false; 
//         // }
//         return !allInstallationServices.some(installation => installation.project_id === service.project_id);
//       });
      
//       console.log('filteredProjects====',filteredProjects)
//       console.log('filteredServices====',filteredServices)
//       console.log('filteredInstallServices====',filteredInstallServices)
//       console.log('🔍 Sample filteredServices data:', filteredServices[0]);
//       console.log('🔍 Sample filteredInstallServices data:', filteredInstallServices[0]);
//       let request = false;
//       let projectTasks = await Promise.all(
//         filteredProjects.map(async (data) => {
//           const id = data.id
//           let productOrServiceData = [];
//           let result = await Project.findProjectById(id,request);
//             if (false) {
//             // if (result.project_category == 11) { // It was for service only. now service only has products also. Changed by deeraj on 15th oct 2025
//               productOrServiceData = await Installation.getServices(result.request_id);
//               for (let service of productOrServiceData) {
//                 let locationdata = await Installation.getServiceLocations(service.id, result.request_id);
//                 service.locationdata = locationdata;
//               }
//             } else {
//               productOrServiceData = await Installation.getProducts(result.order_id);
//               for (let product of productOrServiceData) {
//                 let locationdata = await Installation.getLocations(product.id, product.product_id);
//                 product.locationdata = locationdata;
//               }
//             }
//             for (let data of productOrServiceData) {
//               let locationData = data.locationdata;
//               for (let i = 0; i < locationData.length; i++) {
//                 data.address = locationData[i].address;
//                 data.city = locationData[i].city;
//                 data.state = locationData[i].state;
//                 data.zipcode = locationData[i].zip;
//                 data.name = result.name;
//                 data.project_id = result.id;
//                 data.status = result.status;
//                 data.request_id = result.request_id;
//                 data.product_id = data?.product_id;
//                 data.labour_cost_service_id = data?.labour_cost_service_id;
//                 data.location_id = locationData[i].id;
//                 data.start_date = result.start_date;
//                 data.installation_date = result.installation_date;
//                 data.due_date = result.installation_date;
//                 data.installation_start_date = result.installation_start_date;
//                 data.installation_end_date = result.installation_end_date;
//                 data.location_quantity = locationData[0]?.location_quantity || 1;

//                 data.doc_number = result.doc_number;
//                 data.client_name = result.client_name;
//                 data.community_name = result.community_name;
//                 data.customer_name = result.client_name;
//               }
//             }
//             return productOrServiceData;
//         })
//       );
//       projectTasks = projectTasks.flat();
      
//       // Group products by order_id and combine product names
//       const groupedProjects = {};
//       projectTasks.forEach(project => {
//         const orderId = project.order_id;
//         if (!groupedProjects[orderId]) {
//           groupedProjects[orderId] = { ...project };
//           groupedProjects[orderId].product_names = [];
//         }
//         if (project.product_name && !project.labour_cost_service_id && !groupedProjects[orderId].product_names.includes(project.product_name)) {
//           groupedProjects[orderId].product_names.push(project.product_name);
//         }
//       });
      
//       // Convert grouped projects back to array with combined product names
//       projectTasks = Object.values(groupedProjects).map(project => ({
//         ...project,
//         product_name: project.product_names.join(', ')
//       }));
      
//       console.log('🔍 Grouped projects with combined product names:', projectTasks[0]?.product_name);
      
//       // Add attachments for each appointment to avoid frontend API calls
//       for (const appointment of appointments) {
//         try {
//           let attachment = await Request.getAllRequestAttachmentsForCards(appointment.request_id, appointment.isFromDesignOrder || false);
//           appointment.attachmentsData = attachment || [];
//         } catch (error) {
//           console.log('Error fetching attachments for appointment:', appointment.id, error);
//           appointment.attachmentsData = [];
//         }
//       }
      
//       // let clients = await Client.getAllClientsDataFilters();
//       reply.send({status:1,appointments,userType,userId,
//         // totalCount,
//         // completedTotalCount, ongoingTotalCount,
//         // inTransitTotalCount,awaitingTotalCount,deliveredTotalCount,failedTotalCount,assignedTotalCount,
//         // allTotalCount,
//         // allAppointments, 
//         filteredProjects : projectTasks, filteredServices : filteredServices, filteredInstallServices : filteredInstallServices, 
//         // clients
//       })
//   }catch(error){
//       console.log("getAllCustomerOrders Error - ",error)
//       reply.send({status:500,message:error})
//   }
// }
//optimized function
const fetchAllApointmentsCalendar = async (req, reply) => {
  try {
    const moment = require('moment');

    const userId = req?.body?.userId?.value;
    let page = req?.body?.page;
    let rowsPerPage = req?.body?.rowsPerPage;
    const userType = req?.body?.userType?.value;
    const hasPermission = req?.body?.hasPermission || false;
    let sort = req?.body?.sort;
    let fromDate = req?.body?.from;
    let toDate = req?.body?.to;
    let tab = req?.body?.tab;
    let project_id = req?.body?.project_id;
    let dueData = req?.body?.dueData;
    let search = req?.body?.search;
    let complete_status = req?.body?.complete_status;
    let filterClient = req?.body?.filterClient;
    let filterProjectType = req?.body?.filterProjectType;

    // Handle month-based filtering for calendar
    let currentMonth = req?.body?.currentMonth;
    if (currentMonth) {
      const currentDate = moment(currentMonth, 'YYYY-MM');
      const prevMonth = currentDate.clone().subtract(1, 'month');
      const nextMonth = currentDate.clone().add(1, 'month');

      // Keeping your existing 3-month behavior unchanged
      // fromDate = prevMonth.startOf('month').format('YYYY-MM-DD');
      // toDate = nextMonth.endOf('month').format('YYYY-MM-DD');
      
      // First day of current month
      fromDate = currentDate.clone().startOf('month').format('YYYY-MM-DD');
      // Last day of current month
      toDate = currentDate.clone().endOf('month').format('YYYY-MM-DD');
    }

    // Run independent queries in parallel
    const [
      appointments,
      results,
      servicesData,
      installServicesData,
      // allInstallations
    ] = await Promise.all([
      Installation.fetchAllApointmentsOptimizedForCalendar(
        userId,
        userType,
        hasPermission,
        page,
        rowsPerPage,
        sort,
        fromDate,
        toDate,
        tab,
        project_id,
        dueData,
        search,
        complete_status,
        filterClient,
        filterProjectType
      ),
      Project.getAllJobsProjectTableData(
        hasPermission,
        true,
        userType,
        userId,
        null,
        'new',
        fromDate,
        toDate,
        false
      ),
      Installation.getAllServicesForCalendar(
        hasPermission,
        userType,
        userId,
        fromDate,
        toDate
      ),
      Installation.getAllInstallServicesForCalendar(
        hasPermission,
        userType,
        userId,
        fromDate,
        toDate
      ),
      // one unpaginated call only for comparison/filtering
      // Installation.fetchAllApointmentsOptimizedForCalendar(
      //   userId,
      //   userType,
      //   hasPermission,
      //   null,
      //   null,
      //   null,
      //   fromDate,
      //   toDate,
      //   'All',
      //   project_id,
      //   dueData,
      //   search,
      //   complete_status,
      //   filterClient,
      //   filterProjectType
      // )
    ]);
    

    // Faster filtering using Set
    const installedProjectIds = new Set(
      // (allInstallations || []).map(item => item.project_id).filter(Boolean)
      (appointments || []).map(item => item.project_id).filter(Boolean)
    );

    const filteredProjects = (results || [])//.filter(
    //   project => !installedProjectIds.has(project.id)
    // );

    const filteredServices = (servicesData || []).filter(
      service => !installedProjectIds.has(service.project_id)
    );

    const filteredInstallServices = (installServicesData || []).filter(
      service => !installedProjectIds.has(service.project_id)
    );



    let request = false;

    // Keeping existing logic, but wrapped cleanly
    let projectTasks = await Promise.all(
      filteredProjects.map(async (projectRow) => {
        const id = projectRow.id;
        let productOrServiceData = [];

        const result = await Project.findProjectById(id, request);

        if (false) {
          // kept exactly as your logic currently behaves
          productOrServiceData = await Installation.getServices(result.request_id);

          await Promise.all(
            productOrServiceData.map(async (service) => {
              const locationdata = await Installation.getServiceLocations(
                service.id,
                result.request_id
              );
              service.locationdata = locationdata || [];
            })
          );
        } else {
          productOrServiceData = await Installation.getProducts(result.order_id);

          await Promise.all(
            productOrServiceData.map(async (product) => {
              const locationdata = await Installation.getLocations(
                product.id,
                product.product_id
              );
              product.locationdata = locationdata || [];
            })
          );
        }

        for (let item of productOrServiceData) {
          const locationData = item.locationdata || [];

          for (let i = 0; i < locationData.length; i++) {
            item.address = locationData[i].address;
            item.city = locationData[i].city;
            item.state = locationData[i].state;
            item.zipcode = locationData[i].zip;
            item.name = result.name;
            item.project_id = result.id;
            item.status = result.status;
            item.request_id = result.request_id;
            item.product_id = item?.product_id;
            item.labour_cost_service_id = item?.labour_cost_service_id;
            item.location_id = locationData[i].id;
            item.start_date = result.start_date;
            item.installation_date = result.installation_date;
            item.due_date = result.installation_date;
            item.installation_start_date = result.installation_start_date;
            item.installation_end_date = result.installation_end_date;
            item.location_quantity = locationData[0]?.location_quantity || 1;
            item.doc_number = result.doc_number;
            item.client_name = result.client_name;
            item.community_name = result.community_name;
            item.customer_name = result.client_name;
          }
        }

        return productOrServiceData;
      })
    );

    projectTasks = projectTasks.flat();

    // Group products by order_id and combine product names
    const groupedProjects = {};
    projectTasks.forEach((project) => {
      const orderId = project.order_id;

      if (!groupedProjects[orderId]) {
        groupedProjects[orderId] = { ...project, product_names: [] };
      }

      if (
        project.product_name &&
        !project.labour_cost_service_id &&
        !groupedProjects[orderId].product_names.includes(project.product_name)
      ) {
        groupedProjects[orderId].product_names.push(project.product_name);
      }
    });

    projectTasks = Object.values(groupedProjects).map((project) => ({
      ...project,
      product_name: project.product_names.join(', ')
    }));

    // Fetch attachments in parallel
    // await Promise.all(
    //   (appointments || []).map(async (appointment) => {
    //     try {
    //       const attachment = await Request.getAllRequestAttachmentsForCards(
    //         appointment.request_id,
    //         appointment.isFromDesignOrder || false
    //       );
    //       appointment.attachmentsData = attachment || [];
    //     } catch (error) {
    //       console.log(
    //         'Error fetching attachments for appointment:',
    //         appointment.id,
    //         error
    //       );
    //       appointment.attachmentsData = [];
    //     }
    //   })
    // );

    return reply.send({
      status: 1,
      appointments,
      userType,
      userId,
      filteredProjects: projectTasks,
      filteredServices,
      filteredInstallServices
    });
  } catch (error) {
    console.log('getAllCustomerOrders Error - ', error);
    return reply.send({ status: 500, message: error });
  }
};

const fetchAllApointmentsCount=async(req,reply)=>{
  try{
     
      const userId = req.body.userId.value
      const userType = req.body.userType.value
      const hasPermission = req.body.hasPermission || false
      const sort = req.body.sort
      const fromDate = req?.body?.from
      const toDate = req?.body?.to
      const project_id = req?.body?.project_id
      const search = req?.body?.search;
      const installsAwaitingCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Awaiting",project_id,search,1)
      const pickupAwaitingCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Awaiting",project_id,search,2)
      const shippingAwaitingCount = await Installation.fetchTotalCount(userId,userType,hasPermission,fromDate,toDate,"Awaiting",project_id,search,3)
      reply.send({status:1,installsAwaitingCount,pickupAwaitingCount,shippingAwaitingCount
      })
  }catch(error){
      console.log("getAllCustomerOrders Error - ",error)
      reply.send({status:500,message:error})
  }
}

const saveProjectOrder = async (req, res) => {
  try {
    const { reorderedItems } = req.body;
    console.log("updatedCardsupdatedCardsupdatedCards",reorderedItems)
    await Installation.updateCardOrderProject(reorderedItems);
    res.status(200).send({ status: 1, message: 'Order saved' });
  } catch (error) {
    console.log('saveReq error : ',error)
    res.status(500).send({ status: 500, message: 'Error saving order', error:error });
  }
}

const fetchApointmentById=async(req,reply)=>{
  let {requestId} = req.body;
  let appointment=await Installation.fetchApointmentById(requestId);
  if (appointment && appointment.length > 0) {
    appointment[0].description = (appointment[0].description || '').replace(/\r?\n/g, '\n');
    appointment[0].description_lines = appointment[0].description ? appointment[0].description.split('\n') : [];
    appointment[0].notes = (appointment[0].notes || '').replace(/\r?\n/g, '\n');
    appointment[0].notes_lines = appointment[0].notes ? appointment[0].notes.split('\n') : [];
  }
  let tasks=[]
  let locations=[]
  let filteredTasks=[]
  let projectMembers = await Request.getAllDesignOrderProjectMembers(appointment[0]?.design_order_id);
  if(appointment[0]){
    tasks=await ProjectTask.getAllProjectTasks(appointment[0].project_id,1,1)
    // locations=await ProjectTask.getAllLocationsForTSInstallation(appointment[0].project_id, true, appointment[0]?.product_id, appointment[0]?.product_index)
    appointment[0]['locations'] = locations
    if(appointment[0].product_id){
      filteredTasks = tasks.filter(task => task.product_id === appointment[0].product_id && task.request_location_id === appointment[0].location_id);
    }else{
      filteredTasks = tasks.filter(task => task.service_id === appointment[0].labour_cost_service_id);
      // filteredTasks = tasks.filter(task => task.name === appointment[0].order_product_name && task.project_id === appointment[0].project_id );
    }
  }
 
  reply.send({status:1,result:appointment,tasks:filteredTasks,tasksas:tasks, projectMembers})
}

const updateProjectInstallationDate = async (request, reply) => {
    try {
      let currentDate = Math.round(moment().valueOf() / 1000);
      let projectId = request.body.projectId;
      let locationId = request.body.locationId;
      let projectData = {};
      projectData.installation_date = request.body.installation_date || null;
      projectData.installation_start_date = request.body.installation_start_date || null;
      projectData.installation_end_date = request.body.installation_end_date || null;
      
      // If installation_start_date is provided but installation_date is null, set installation_date to installation_start_date
      if (projectData.installation_start_date && !projectData.installation_date) {
        projectData.installation_date = projectData.installation_end_date;
      }
        // console.log("$$$$$$$$$$$$$$$$$$$ projectData : ", projectData);
          // let result = await Project.updateProject(projectId, projectData);
          let update=await Installation.updateInstallationDate(projectId,locationId, projectData)
          if (update) {
            let project=await Installation.fetchApointmentById(projectId);
            // 1) Sync Sales Order end date (Requests.participation_ends)
            // if (project?.[0]?.request_id) {
            //   await Requests.updateRequets(project[0].request_id, {
            //     participation_ends: request.body.installation_date != null
            //       ? String(request.body.installation_date)
            //       : null
            //   });
            // }

            // 2) Update Installation.due_date for this location
            console.log('locationId', locationId)
            if (locationId) {
              await Installation.updateDueDate(
                locationId,
                request.body.installation_date ? Number(request.body.installation_date) : null
              );
            }

            // inside updateProjectInstallationDate controller, after fetching `project`
            if (project?.[0]?.request_id) {
              await Project.updateProjectByRequestId(project[0].request_id, {
                installation_date: request.body.installation_date != null
                  ? Number(request.body.installation_date)
                  : null
              });
            }

            let notificationMsg = `The installation date has been updated for job "${project[0].name}".`;
            let notificationUrl = "projects";
  
            // Alert to user of new added project
  
            const incrementResult_User = await Admin.incrementField(
              request.body.added_by,
              "noti_count",
              1
            );
            console.log(
              "incrementResult--to--user-----------",
              incrementResult_User
            );
            let notificationData_user = {
              user_id: request.body.added_by,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: request.body.added_by,
            };
            console.log(
              "notificationData--user------------",
              notificationData_user
            );
            const addNotificationResult_user = await Admin.addNotification(
              notificationData_user
            );
            console.log(
              "addNotificationResult--user-------",
              addNotificationResult_user
            );
  
            // Alert to all admins of new added project
  
            let adminIds = await Admin.getAllAdminIds();
            let notificationData = {};
            console.log("adminIds====", adminIds);
            for (const adminId of adminIds) {
              console.log("adminId----------", adminId);
              if (adminId != request.body.added_by) {
                const incrementResult = await Admin.incrementField(
                  adminId,
                  "noti_count",
                  1
                );
                console.log("incrementResult-------------", incrementResult);
                notificationData = {
                  user_id: request.body.added_by,
                  url: notificationUrl,
                  timestamp: currentDate,
                  message: notificationMsg,
                  status: 1,
                  from_id: request.body.added_by,
                };
                console.log("notificationData------------", notificationData);
                const addNotificationResult = await Admin.addNotification(
                  notificationData
                );
                console.log(
                  "addNotificationResult-------",
                  addNotificationResult
                );
              }
            }
            reply.send({
              status: 1,
              message: notificationMsg,
            });
          } else {
            reply.send({ status: 0, message: "Failed to update the installation date" });
          }
        
    } catch (error) {
      console.log("Server error", error);
      reply.status(500).send({ message: "Server error" + error });
    }
};

const updateProjectInstallationDateInProject = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectId = request.body.projectId;
    let locationId = request.body.locationId;
    let projectData = {};
    projectData.installation_date = request.body.installation_date || null;
    projectData.installation_start_date = request.body.installation_start_date || null;
    projectData.installation_end_date = request.body.installation_end_date || null;
    
    // If installation_start_date is provided but installation_date is null, set installation_date to installation_end_date
    if (projectData.installation_start_date && !projectData.installation_date) {
      projectData.installation_date = projectData.installation_end_date;
    }
    let update=await Project.updateProject(projectId, projectData)
    console.log('update---------------', update)
    if (update) {
      let project=await Project.findProjectById(projectId,false);
      console.log('projectproject==',project)
      // 1) Update Sales Order (requests.participation_ends)
      if (project?.request_id) {
        let data = {}
        data.participation_ends = request.body.installation_date != null
          ? String(request.body.installation_date)
          : null
        if (request?.body.installation_start_date && request?.body.installation_end_date) {
          data.installation_start_date = request?.body?.installation_start_date || null;
          data.installation_end_date = request?.body?.installation_end_date || null;
        }
        console.log('data-----',data)
        await Requests.updateRequets(project.request_id, data);
      }

      // 2) Update Installation.due_date (use the locationId from payload)
      if (request.body.locationId) {
        await Installation.updateDueDate(
          locationId,
          request.body.installation_date != null ? Number(request.body.installation_date) : null
        );
      } 
      
      // inside updateProjectInstallationDate controller, after fetching `project`
      if (project?.[0]?.request_id) {
        await Project.updateProjectByRequestId(project[0].request_id, {
          installation_date: request.body.installation_date != null
            ? Number(request.body.installation_date)
            : null
        });
      } // Added by deeraj sw-623
      let notificationMsg = `The installation date of job "${project.name}" has been updated.`;
      let notificationUrl = "projects";
      // Alert to user of new added project
      const incrementResult_User = await Admin.incrementField(request.body.added_by, "noti_count", 1);
      let notificationData_user = {
        user_id: request.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: request.body.added_by,
      };
      const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      // Alert to all admins of new added project
      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      for (const adminId of adminIds) {
        if (adminId != request.body.added_by) {
          const incrementResult = await Admin.incrementField(adminId,"noti_count",1);
          notificationData = {
            user_id: request.body.added_by,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: request.body.added_by,
          };
          const addNotificationResult = await Admin.addNotification(notificationData);
        }
      }
      reply.send({status: 1,message: notificationMsg});
    } else {
      reply.send({ status: 0, message: "Failed to update the job installation date" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};

const updateInstallationAddress = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let instId = request.body.installation_id;
    let locationId = request.body.locationId;
    let installationData = {};
    installationData.address = request.body.address || null;
    installationData.city = request.body.city || null;
    installationData.state = request.body.state || null;
    installationData.zipcode = request.body.zip || null;
    installationData.serviceOnly = request.body.serviceOnly || 0;

   
    // console.log("$$$$$$$$$$$$$$$$$$$ installationData : ", installationData);
    let update=await Installation.updateInstallationAddress(installationData, instId, locationId)
    installationData.zip = request.body.zip || null;
    let updateLoc=false
    if(installationData.serviceOnly ==1){
      updateLoc=await Requests.updateServiceLocation(installationData, locationId)
      console.log('updateServiceLocationupdateServiceLocation',updateLoc)
    }else{

       updateLoc=await Requests.updateLocation(installationData, locationId)
    }
    if (update && updateLoc) {
      let installation=await Installation.fetchApointmentById(instId);
      let notificationMsg = `Installation Address updated for "${installation[0].name}".`;
      let notificationUrl = "installation";
      // Alert to user of address updation in installation
      const incrementResult_User = await Admin.incrementField(request.body.added_by,"noti_count",1);
      let notificationData_user = {
        user_id: request.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: request.body.added_by,
      };
      const addNotificationResult_user = await Admin.addNotification(notificationData_user);

      // Alert to all admins of new added installation

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      for (const adminId of adminIds) {
        if (adminId != request.body.added_by) {
          const incrementResult = await Admin.incrementField(adminId, "noti_count", 1 );
          notificationData = {
            user_id: request.body.added_by,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: request.body.added_by,
          };
          const addNotificationResult = await Admin.addNotification( notificationData );
        }
      }
      reply.send({ status: 1, message: notificationMsg });
    } else {
      reply.send({ status: 0, message: "Failed to update the installation address" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};

const updateInstallationDataByRequestId = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let {selectedSalesOrder, selectedRoute, selectedDriver} = request.body;
    let installationData = {};
    installationData.route_id = request.body.address || null;
    installationData.driver_id = request.body.city || null;
    let update=await Installation.updateInstallationDataByRequestId(installationData, selectedSalesOrder)
    if (update) {
      let installation=await Installation.fetchApointmentById(instId);
      let notificationMsg = `Installation Address updated for "${installation[0].name}".`;
      let notificationUrl = "installation";
      // Alert to user of address updation in installation
      const incrementResult_User = await Admin.incrementField(request.body.added_by,"noti_count",1);
      let notificationData_user = {
        user_id: request.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: request.body.added_by,
      };
      const addNotificationResult_user = await Admin.addNotification(notificationData_user);

      // Alert to all admins of new added installation

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      for (const adminId of adminIds) {
        if (adminId != request.body.added_by) {
          const incrementResult = await Admin.incrementField(adminId, "noti_count", 1 );
          notificationData = {
            user_id: request.body.added_by,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: request.body.added_by,
          };
          const addNotificationResult = await Admin.addNotification( notificationData );
        }
      }
      reply.send({ status: 1, message: notificationMsg });
    } else {
      reply.send({ status: 0, message: "Failed to update the installation address" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};

const addInstallationNote = async (request,reply) =>{
  try{
    let currentDate = moment().unix();
    const {obj} = request.body;
    // const obj = {note : "Note 234",appointment_id:12,user_id:1}
    const noteData = {};
    noteData['note'] = stripHTMLTags(obj.note) || '';
    noteData['installation_id'] = obj.appointment_id || null;
    noteData['source'] = obj.source;
    noteData['added_by'] = obj.user_id || null;
    noteData['timestamp'] = currentDate;
    noteData['status'] = 1;
    const addResult = await Installation.addInstallationNote(noteData)
    if(addResult){
      const installationData = await Installation.fetchApointmentById(noteData['installation_id'])
      let notificationMsg = `Installation note successfully added for ${installationData[0]?.name}`;
      let notificationUrl = "installation";

      const incrementResult_User = await Admin.incrementField( noteData['added_by'], "noti_count", 1 );
      let notificationData_user = {
        user_id: noteData['added_by'],
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: noteData['added_by'],
      };
      const addNotificationResult_user = await Admin.addNotification( notificationData_user );

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      for (const adminId of adminIds) {
        if (adminId != noteData['added_by']) {
          const incrementResult = await Admin.incrementField( adminId, "noti_count", 1 );
          notificationData = {
            user_id: adminId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: noteData['added_by'],
          };
          const addNotificationResult = await Admin.addNotification( notificationData );
        }
      }
      reply.send({ status: 1, message: notificationMsg, });
    }else{
      reply.send({status:0,message:'Failed to add installation note'})
    }
  }catch(error){
    console.log("addInstallationNote error : ",error);
    reply.send({status:500,message:'Error adding installation note'})
  }
}

const editInstallationNote = async (request,reply) =>{
  try{
    let currentDate = moment().unix();
    const {note,note_id,userId, installation_id} = request.body;
    // const note = "new updated Note 234"
    // const note_id = 2
    // const userId = 1
    // const installation_id = 12
    const noteData = {};
    noteData['note'] = stripHTMLTags(note) || '';
    const editResult = await Installation.editInstallationNote(noteData,note_id)
    if(editResult){
      const installationData = await Installation.fetchApointmentById(installation_id)
      let notificationMsg = `Installation note successfully updated for ${installationData[0]?.name}`;
      let notificationUrl = "installation";

      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 update installation note'})
    }
  }catch(error){
    console.log("error editInstallationNote : ",error);
    reply.send({status:500,message:'Error updating installation note'})
  }
}

const deleteInstallationNote = async (request,reply) =>{
  try{
    let currentDate = moment().unix();
    const {note_id,userId, installation_id} = request.body;
    // const note_id = 2
    // const userId = 1
    // const installation_id = 12
    const deleteResult = await Installation.deleteInstallationNote(note_id)
    if(deleteResult){
      const installationData = await Installation.fetchApointmentById(installation_id)
      let notificationMsg = `Installation note of ${installationData[0]?.name} has been deleted successfully`;
      let notificationUrl = "installation";

      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 delete installation note'})
    }
  }catch(error){
    console.log("error deleteInstallationNote : ",error);
    reply.send({status:500,message:'Error deleting installation note'})
  }
}

const fetchNotesByInstallationId = async (request,reply) =>{
  try{
    const {installation_id} = request.body;
    // const installation_id = 12
    const fetchedData = await Installation.fetchNotesByInstallationId(installation_id)
    if(fetchedData){
      reply.send({ status: 1, message: fetchedData, });
    }else{
      reply.send({status:0,message:'Failed to fetch installation notes'})
    }
  }catch(error){
    console.log("error fetchNotesByInstallationId : ",error);
    reply.send({status:500,message:'Error fetching installation notes'})
  }
}

const addInstallationTemplate = async (req, res) => {
  try {
    let { userId, values, name } = req.body;
    const template = {
      name: name,
      timestamp: moment().unix(),
      updated_on: moment().unix(),
      added_by: req.body.userId,
      status: 6,
    };

    let stageId = uniqid()
    let formFieldId = uniqid()
    template['template_uid'] = formFieldId
    template['stage_uid'] = uniqid()
   
    if (empty(values)) {
      res.status(400).send({ status: 0, message: 'Failed to create new campaign form !' });
      return;
    }
   

    let templateId = await CustomFieldTemplate.addTemplate(template)

    if (templateId) {
      let i = 1;

      for (const row of values) {
        const customFields = {};
        customFields.template_id = templateId;
        customFields.row_id = 'row'+uniqid();
        customFields.column_id = 'column'+uniqid();
        customFields.html_tag = row.type;
        customFields.name = row.type  ;

        if (row.required) {
          customFields.is_required = 1;
        }

        if (row.description) {
          customFields.help_text = row.description;
        }

        customFields.tag_uid = row.type;

        if (!empty(row.label)) {
          customFields.content = row.label.replace(/[\r\n]+/g, '').trim();
        }

        customFields.field_uid = 'field'+uniqid();
        customFields.position_order = i++;

        if (row.placeholder) {
          customFields.placeholder = row.placeholder;
        }

        if (row.date_format) {
          customFields.date_format = row.date_format;
        }

        if (row.pattern) {
          customFields.pattern = row.pattern;
        }

        if (row.href) {
          customFields.a_href = row.href;
        }

        if (row.target) {
          customFields.a_target = row.target;
        }

        if (customFields.tag_uid === 'header') {
          customFields.default_select = 'h1';
          if (row.tag) {
            row.tag.forEach((headerTag) => {
              if (headerTag.selected) {
                customFields.default_select = headerTag.value;
              }
            });
          }
        }

        customFields.timestamp = moment().unix();
        customFields.added_by = userId;
        customFields.status = 1;
       
        if (!empty(row.subtype)) {
          customFields.input_type = row.subtype || 'text';
        }

        const fieldId = await CustomFieldTemplate.addTemplateField(customFields);

        if (row.values) {
          let o = 1;
          for (const fieldOption of row.values) {
           
            const customFieldOptions = {};
            customFieldOptions.field_id = fieldId;
            customFieldOptions.option_name = fieldOption.label;
            customFieldOptions.selected =fieldOption.selected? parseInt(fieldOption.selected):0
            customFieldOptions.position_order = o++;
            customFieldOptions.timestamp = moment().unix();
            customFieldOptions.added_by = userId;
            customFieldOptions.status = 1;

            const fieldOptionId = await CustomFieldTemplate.addTemplateFieldOptions(customFieldOptions);
          }
        }
      }
      let notificationMessage="New Installation Template "+name+" has been created"
      let notificationUrl="installation"      
      const adminIds = await Admin.getAllAdminIds()
      for (let eachadminIds of adminIds) {
        if (eachadminIds != userId) {
        let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
        let addNotification = {
          user_id: eachadminIds,
          url: notificationUrl,
          timestamp: moment().unix(),
          message: notificationMessage,
          status: 1,
          from_id: userId,
        }
        const addNotificationResult = await Admin.addNotification(addNotification);
      }
      }
      const incrementResult_User = await Admin.incrementField(userId, "noti_count", 1);
   
      let notificationData_user = {
          user_id: userId,
          url: notificationUrl,
          timestamp: moment().unix(),
          message: notificationMessage,
          status: 1,
          from_id:userId,
      };
    
      const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      res.send({
        status:1,msg:notificationMessage
    })
    }
    else{
      res.send({
        status:1,msg:"Failed to add installation template"})
    }
  } catch (error) {
    console.error(error);
    res.status(500).send({ message: "Server error"+error });
  }
}
const getAllInstallationTemplate=async(req,res)=>{
  try {
    let {value}=req.body
    console.log("###############Value",value);
   let result = await Installation.getAllInstallationTemplate(value)
   if(!empty(result)){
    res.send({
      status:1 ,result
    })
   }else{
    res.send({
      status:0
    })
   }
  } catch (error) {
    console.log(error)
  }
}
const deleteInstallationTemplate=async(req,res)=>{
  try {
    const {data} = req.body
    let result = await CustomFieldTemplate.deteleCustomTemplateById(data.id)
    if(result===true){ 
      res.status(200).send({
        status:1,message:`Campaign Form ${data.name} has been deleted successfully`
      })
    }else{
      res.status(500).send({
        status:0,message:`Failed to delete ${data.name} `
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const deactivateInstallationTemplate = async (req, res) => {
  try {
    let { templateId, userId, status, userType } = req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    let template = {}
    template['status'] = status
    if (!empty(templateId)) {
      let data = await CustomFieldTemplate.getTemplateByid(templateId)
      let deleted = await CustomFieldTemplate.updateCustomFieldTemplate(templateId, template)

      if (template['status'] == 2) {

        if (deleted) {

          let notificationMsg = `The installation template <strong>".${data['name']}."</strong> has been deleted.`;
          let notificationUrl = "custom-fields";
          if (userType !== 1) {
            Admin.incrementField(userId, 'noti_count', 1);
            Admin.addNotification({
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          let adminId = await Admin.getAllAdminIds()
          for (let eachAdminId of adminId) {
            Admin.incrementField(eachAdminId, 'noti_count', 1);
            Admin.addNotification({
              user_id: eachAdminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          res.send({
            status: 2, message: `The custom field template ${data['name']} has been deleted.`
          })
        }
      } else if (template['status'] == 6) {

        if (deleted) {

          let notificationMsg = `The installation template <strong>".${data['name']}."</strong> has been made active.`;
          let notificationUrl = "custom-fields";
          if (userType !== 1) {
            Admin.incrementField(userId, 'noti_count', 1);
            Admin.addNotification({
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          let adminId = await Admin.getAllAdminIds()
          for (let eachAdminId of adminId) {
            Admin.incrementField(eachAdminId, 'noti_count', 1);
            Admin.addNotification({
              user_id: eachAdminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          res.send({
            status: 1, message: `The custom field template ${data['name']} has been made active.`
          })
        }
      } else if (template['status'] == 7) {

        if (deleted) {

          let notificationMsg = `The installation template <strong>".${data['name']}."</strong> has been made inactive.`;
          let notificationUrl = "custom-fields";
          if (userType !== 1) {
            Admin.incrementField(userId, 'noti_count', 1);
            Admin.addNotification({
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          let adminId = await Admin.getAllAdminIds()
          for (let eachAdminId of adminId) {
            Admin.incrementField(eachAdminId, 'noti_count', 1);
            Admin.addNotification({
              user_id: eachAdminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
          res.send({
            status: 1, message: `The Template ${data['name']} has been made inactive!`
          })
        }
      }
    }
  } catch (error) {
    console.log(error, 'error in delete custom field')
  }
}
const getInstTemplateData=async(req,res)=>{
  try {
    let {id,userId,userType} = req.body
    if(!empty(id)){
       let data = await Installation.getInstTemplateDataById(id)
       if(!empty(data)){
        res.status(200).send({
          status:1,data
        })
       }else{
        res.status(500).send({
          status:0
        })
       }
    }
  } catch (error) {
    console.log(error)
  }
}

/////////////////////////////////////qb
const addJournalEntryForProductInstalled = async (installationCostDataForQb) => {

  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');
  
  let materialAmount =installationCostDataForQb?.productTotal || 0
  let laborAmount =installationCostDataForQb?.serviceTotal || 0
  let additionalMaterialAmount =installationCostDataForQb?.additionalMaterialTotal || 0
  const totalAmount = parseFloat(materialAmount) + parseFloat(laborAmount) + parseFloat(additionalMaterialAmount);
  const totalProductAmount = parseFloat(materialAmount) + parseFloat(additionalMaterialAmount);
      
  let materialDescription = `The installation of "${installationCostDataForQb?.product_name || installationCostDataForQb?.service_name}" for job "${installationCostDataForQb?.job_name}" has been completed. Recognized material cost : $${parseFloat(totalProductAmount)?.toFixed(2)}.`;
  console.log('materialDescription', materialDescription)
  let laborDescription = `The installation of "${installationCostDataForQb?.product_name || installationCostDataForQb?.service_name}" for job "${installationCostDataForQb?.job_name}" has been completed. Recognized labor cost: $${parseFloat(laborAmount)?.toFixed(2)}.`;
  console.log('laborDescription', laborDescription)
  let totalDescription = `The installation of "${installationCostDataForQb?.product_name || installationCostDataForQb?.service_name}" for job "${installationCostDataForQb?.job_name}" has been completed. Transferred total cost (materials + labor): $${totalAmount?.toFixed(2)}.`;
  console.log('totalDescription', totalDescription)

  let COGSMaterialAccountId = await findAccountIdByAcctNum(5041000) 
  let COGSLaborAccountId = await findAccountIdByAcctNum(5081000) 
  let FinishedGoodsInvAccountId = await findAccountIdByAcctNum(1014300) 

  const transactionCount = await Project.getTransactionCountByProjectId(null,installationCostDataForQb?.requestId);
  let futureTransactionCount = Number(transactionCount) + 1;
  let journalNumber = installationCostDataForQb?.doc_number + '-' + futureTransactionCount;

  const journalEntryData = {
    DocNumber: journalNumber,
    Line: [
      {
        Id: "1",
        Description: materialDescription,
        Amount: totalProductAmount,
        DetailType: "JournalEntryLineDetail",
        JournalEntryLineDetail: {
          PostingType: "Debit",
          AccountRef: {
            value:COGSMaterialAccountId 
          },
          DepartmentRef: { value: departmentId },
          ClassRef: { value: installationCostDataForQb?.projectTypeQuickBookId },
        }
      },
      {
        Id: "2",
        Description: laborDescription,
        Amount: parseFloat(laborAmount),
        DetailType: "JournalEntryLineDetail",
        JournalEntryLineDetail: {
          PostingType: "Debit",
          AccountRef: {
            value:COGSLaborAccountId 
          },
          DepartmentRef: { value: departmentId },
          ClassRef: { value: installationCostDataForQb?.projectTypeQuickBookId },
        }
      },
      {
        Id: "3",
        Description: totalDescription,
        Amount: totalAmount,
        DetailType: "JournalEntryLineDetail",
        JournalEntryLineDetail: {
          PostingType: "Credit",
          AccountRef: {
            value:FinishedGoodsInvAccountId 
          },
          DepartmentRef: { value: departmentId },
          ClassRef: { value: installationCostDataForQb?.projectTypeQuickBookId },
        }
      }
    ],
    TxnDate: date,
    PrivateNote: `Auto journal entry for product installed (COGS recognition)`
  };
  try{
    const response = await axios.post(`${apiUrl}/journalentry`, journalEntryData, {
      headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
        'Content-Type': 'application/json'
      }
    });

    console.log('✅ Journal entry posted for product installed:', response.data);
  } catch (error) {
    if (error.response) {
      // Server responded with a status other than 2xx
      console.error("Error Response Data:", JSON.stringify(error.response.data, null, 2));
      console.error("Error Response Status:", error.response.status);
      console.error("Error Response Headers:", JSON.stringify(error.response.headers, null, 2));
    } else if (error.request) {
      console.error("No response received:", error.request);
    } else {
      console.error("Error Message:", error.message);
    }
  }
};
// const saveInstTemplate=async(req,res)=>{
//   try {
//     let currentDate = moment().unix();
//     const {id, submitForm, installation_id, status, userId, userType, socketId} = req.body
//     console.log("dataaaaaaaaaaaaaaaa 1", req.body)

//     // 🚀 PROGRESS TRACKING: Socket progress emission function
//     const emitProgress = (step, message, progress) => {
//       const progressData = {
//         step,
//         message,
//         progress,
//         userId,
//         domain: DOMAIN,
//         timestamp: currentDate,
//         type: 'installation_template_save_progress'
//       };
      
//       // Emit to working socket server (same as chat)
//       console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 📡 Emitting progress to working socket server...`);
//       try {
//         const workingSocket = ioClient(REST_API_IO, {
//           path: '/socket.io',
//           transports: ['websocket', 'polling'],
//           secure: true,
//           timeout: 5000
//         });
        
//         workingSocket.on('connect', () => {
//           console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 🔌 Connected to working socket server`);
//           console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 📊 Emitting progress data:`, progressData);
          
//           // Try emitting as 'message' event (same as chat) to test if socket server handles it
//           workingSocket.emit('message', {
//             ...progressData,
//             type: 'progress',
//             conversationId: `installation_template_save_progress_${userId}`,
//             senderId: 'system'
//           });
          
//           // Also try the original request_progress event
//           workingSocket.emit('request_progress', progressData);
          
//           console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
//           // Disconnect after emitting
//           setTimeout(() => {
//             workingSocket.disconnect();
//           }, 1000);
//         });
        
//         workingSocket.on('connect_error', (error) => {
//           console.error(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ❌ Working socket connection error:`, error);
//         });
        
//       } catch (error) {
//         console.error(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ❌ Error creating working socket connection:`, error);
//       }
//     };

//     // Initial progress
//     console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 🚀 Starting installation template save for user:`, userId);
//     emitProgress('start', `Initializing installation template save...`, 5);
//     if(!empty(submitForm)){
//       emitProgress('processing_form_data', `Processing form data...`, 15);
      
//       const field_value_pairs = [];
//       let valueData = removeNull(submitForm)
//       for (const [key, value] of Object.entries(valueData)) {
//         if (value && typeof value === 'object' && "value" in value) {
//           const formattedValue =
//           value.content === "date" && typeof value.value === 'number' && !isNaN(value.value)
//             ? moment.unix(value.value).format('YYYY-MM-DD')
//             : value.value;
//           field_value_pairs.push({ "field_id": value.field_id, "value": formattedValue,template_id: id, installation_id: installation_id, timestamp: currentDate, status: status,});
//         } else if (value && Array.isArray(value) && value.every(item => typeof item === 'object' && "value" in item)) {
//           for (const item of value) {
//             if(!empty(item.value)){
//               const formattedValue =
//               item.content === "date" && typeof item.value === 'number' && !isNaN(item.value)
//                 ? moment.unix(item.value).format('YYYY-MM-DD')
//                 : item.value;
//               field_value_pairs.push({ "field_id": item.field_id, "value": formattedValue,template_id: id, installation_id: installation_id, timestamp: currentDate, status: status,});
//             }     
//           }
//         }
      
//       }

//       if (!empty(field_value_pairs)) {
//         emitProgress('saving_template_data', `Saving template data to database...`, 25);
        
//         let submissionResponse = await Installation.updateBatchData(
//           "installation_temp_fields",
//           field_value_pairs
//         );
        
//         emitProgress('updating_installation_status', `Updating installation status...`, 35);
        
//         let installationData = {}
//         installationData['status'] = 4
//         let updateInstallationStatus = await Installation.updateInstallationStatus(installationData,installation_id)
            
//         emitProgress('processing_quickbooks', `Processing QuickBooks entries...`, 45);
        
//         const installationCostDataForQb = await Installation.getInstallationCostDetailsForQb(installation_id);
//         console.log("installationCostDataForQb",installationCostDataForQb)
//         await addJournalEntryForProductInstalled(installationCostDataForQb)

//         emitProgress('fetching_installation_data', `Fetching installation and request data...`, 55);

//         const installation = await Installation.fetchApointmentById(installation_id)
//         console.log("installationssssssss",installation)
//         console.log("requestDataa")
//         const requestData = await Requests.getAllRequests(installation[0]?.request_id, 1, 1);
//         console.log("requestDataa 1 ",requestData)
//         console.log("installation[0]?.request_id",installation[0]?.request_id)
//         const requestId = installation[0]?.request_id

//         if (requestData?.data[0]?.project_category == 12 && requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
//           emitProgress('updating_request_review', `Updating request review status...`, 60);
          
//           const data = {
//             isReview: 2
//           }
//           let updated = await Request.updateRequets(requestId, data);
//           console.log('updated sales order----', updated)
//         }

//         if(requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance  == null){
//           emitProgress('updating_tab_counts', `Updating tab counts...`, 70);
//           try {
//             const facilityTypes = (requestData?.data[0]?.facility_type || "")
//               .split(",")
//               .map(v => v.trim())
//               .filter(v => v !== "");
//             const targetFacilityId = facilityTypes.filter(id => id !== String(FACILITY_ID));
//             const originRequestId = requestId || null;
//             const isSplitOrder = requestData?.data[0]?.is_split_order || null;
//             const project_category = requestData?.data[0]?.project_category == 15 ? true : false;
//             const forParentFacility = requestData?.data[0]?.for_parent_facility == 1 ? true : false;
//             const installerFacilityId = installation[0]?.installer_facility_id ?? installation[0]?.service_installer_facility_id;
//             const installStatus = installerFacilityId != FACILITY_ID ? installation[0]?.complete_status : 4;
//             const receivedStatus = installerFacilityId != FACILITY_ID ? 1 : 0;
//             if (isSplitOrder && originRequestId && targetFacilityId && project_category && forParentFacility) {
//               const updateSplitMirrorStatus = await updateMirrorOrderStatusFromOtherInstallations(originRequestId, targetFacilityId, installStatus,receivedStatus);
//               console.log('updateSplitMirrorStatus invoicing', updateSplitMirrorStatus)
//               if (receivedStatus == 1) {
//                 const updateRequestStatus = await Request.updateRequets(requestId, { received_status: receivedStatus });
//                 console.log('updateRequestStatus == current installation', updateRequestStatus)
//               }
//             }
//           } catch (error) {
//             console.log('error updateSplitMirrorStatus invoicing', error)
//           }
          
//           const allUserIds = await Admin.getAllUserIds();
//         // const allUserIds = await Admin.getAllAdminUserIds();
//         // const selectedClientId = values?.clients?.user_id ||null;
//         let PartnerUserIds = await RequestPartner.fetchPartnerUserIds(requestId)
//         const projectResult = await Project.getProjectByRequestId(requestId);
//         console.log("projectResult",projectResult )
//         const usersToUpdate = [...new Set([userId,...PartnerUserIds, ...allUserIds].filter(Boolean))];
//         const updateEditCounts = async (userId) => {
//           await Requests.salesOrderIncrementField(userId, 'installs_count', -1, 'installs_count_ids', requestId, false);
//           await Requests.salesOrderIncrementField(userId, 'invoicing_count', 1, 'invoicing_count_ids', requestId, true);
//           await Project.jobTabIncrementField(userId, 'installs_count', -1, 'installs_count_ids', projectResult, false); 
//           await Project.jobTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', projectResult, true);  
//           // if (installation[0]?.complete_status == 1) {
//           //   await Project.jobTabIncrementField(userId, 'installs_count', -1, 'installs_count_ids', projectResult, false); 
//           // }else if (installation[0]?.complete_status == 2) {
//           //   await Project.jobTabIncrementField(userId, 'pickup_count', -1, 'pickup_count_ids', projectResult, false); 
//           // }else if (installation[0]?.complete_status == 3) {
//           //   await Project.jobTabIncrementField(userId, 'shipping_count', -1, 'shipping_count_ids', projectResult, false); 
//           // }

//           console.log("counts updated successfully.")
//         }

//         await Promise.all(usersToUpdate.map(userId => updateEditCounts(userId)));
//         console.log("Request tab counts updated successfully after edit.");
//         }
        
//           let EstimateData = await Request.getRequestById(requestId);
//           const isSplitOrder = Number(EstimateData[0]?.is_split_order);
//           const isBuildOrder = Number(EstimateData[0]?.for_parent_facility);
//           const productId = installation[0]?.product_id;
//           if(isSplitOrder && isBuildOrder && productId){
//           const parentFacilityId = Number(EstimateData[0]?.origin_facility_id);
//           const originFacilityRequestId = Number(EstimateData[0]?.origin_facility_request_id);
//           // const productId = installation[0]?.product_id;
//           const customerOrderProductData = await CustomerOrderProduct.getCustomerOrderProductsbyProduct(requestId,productId);
//           console.log('customerOrderProductData----', customerOrderProductData)
//           for(let eachProduct of customerOrderProductData){
//             const facilityId = Number(eachProduct.facility_id)
//             let productData ={} 
//             productData =  await Product.getProductDetailsFromId(eachProduct.product_id)
//             console.log("productData",productData)
            
//             const update = await Product.updateCustomerOrderProductTransferStatus(eachProduct.product_id,EstimateData[0]?.id,2)
//             const newProductData = {
//               ...productData,
//               id: null,
//               special_price: null,
//               // formula_cost: null,
//               price: null,
//               recipe_id: null,
//               in_stock_no: Number(eachProduct?.location_quantity),
//               inhouse: 6
//             };
//             const transferResult = await transferProductStockToOtherInstallation(newProductData,null,originFacilityRequestId,parentFacilityId,eachProduct.product_id);
//             console.log('transferResult---', transferResult)
            
//             // If transfer was successful, create a completed task in parent facility
//             if(transferResult && transferResult.success) {
//               try {
//                 const taskResult = await SplitManagementModel.createCompletedTaskInParentFacility(
//                   parentFacilityId, 
//                   originFacilityRequestId, 
//                   productData, 
//                   eachProduct,
//                   facilityId
//                 );
                
//                 if(taskResult.success) {
//                   console.log('Task created successfully in parent facility:', taskResult.data);
//                 } else {
//                   console.error('Failed to create task in parent facility:', taskResult.message);
//                 }
//               } catch (error) {
//                 console.error('Error creating task in parent facility:', error);
//               }
//             }
//           }

//         }

//         const userData = await Admin.getUserById(userId)
//         if(submissionResponse && updateInstallationStatus){
//           emitProgress('processing_notifications', `Processing notifications...`, 80);
          
//           // let installation = installation[0]
//           // Notification
//           let   installationProductName  = installation[0]?.product_name || installation[0]?.service_name;
//           let notificationMsg = `Installation "${installationProductName || installation[0]?.name}" has been completed and published by ${userData[0]?.first_name} ${userData[0]?.last_name}.`;

//           await RequestUpdates.addRequestUpdates({
//             request_id: installation[0]?.request_id,
//             activity: notificationMsg,
//             partner_id: 0,
//             added_by: userId,
//             timestamp: currentDate,
//           });

//           if (requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
//             const isTimeandMaterial = requestData?.data[0]?.project_category == 12 ? true : false
//             await RequestUpdates.addRequestUpdates({
//               request_id: installation[0]?.request_id,
//               activity: isTimeandMaterial ? `The installation has been completed and moved to Review, awaiting Review.` : `The installation has been completed and moved to invoicing, awaiting approval.`,
//               partner_id: 0,
//               added_by: userId,
//               timestamp: currentDate,
//             });
//           } //comment this if QA told the before order is correct
          
//           let notificationUrl = "installation";
//           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 );
//           if(installation[0].driver_userId){
//           if(installation[0].driver_userId!==userId){
//             let notificationData_driver = {
//               user_id:installation[0].driver_userId,
//               url: notificationUrl,
//               timestamp: currentDate,
//               message: notificationMsg,
//               status: 1,
//               from_id: userId
//             }
//             const addNotificationResult_driver = await Admin.addNotification( notificationData_driver );
//           }}
//           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 );    
//               }
//           }
//           const clientId = installation[0]?.customer_id
//           const request_id = installation[0]?.request_id
//           console.log("request_id request_id 1",installation[0])
//           console.log("request_id request_id",request_id)
//           const allUserIds = await Admin.getAllAdminUserIds();
//           const projectResult = await Project.getProjectByRequestId(request_id);
//           console.log("projectResult",projectResult)   
//           const project_members = await Project.getAllMemberUserIdsByProjectId(projectResult)
//           console.log("project_members",project_members)
//           const clientUser = await Client.getClientById(clientId);
//           const selectedClientId = clientUser?.user_id ||null;
//           let allUsersToCheck = [...new Set([userId, selectedClientId,...project_members, ...allUserIds].filter(Boolean))];
//           const installationId = installation[0]?.id

//           const handleTabCountUpdate = async (status, installationId, allUsersToCheck, userType, selectedClientId, allUserIds,published) => {
//             let updateOpenCount;
//             let stagedCountField;
          
//             // Define the logic for each status (1 = installation, 2 = pickup, 3 = shipping)
//             switch (status) {
//               case 1: // Installation
//                 stagedCountField = 'staged_count';
//                 updateOpenCount = async (userId) => {
//                     await Installation.installationTabIncrementField(userId, 'installing_count', -1, 'installing_count_ids', installationId, false);
//                     await Installation.installationTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', installationId, true);
//                 };
//                 break;
          
//               case 2: // Pickup
//                 stagedCountField = 'pickup_count';
//                 updateOpenCount = async (userId) => {
//                     await Installation.installationTabIncrementField(userId, 'staged_count', -1, 'staged_count_ids', installationId, false);
//                     await Installation.installationTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', installationId, true);
//                   }
//                 break;
          
//               case 3: // Shipping
//                 stagedCountField = 'shipping_count';
//                 updateOpenCount = async (userId) => {
//                     await Installation.installationTabIncrementField(userId, 'staged_count', -1, 'staged_count_ids', installationId, false);
//                     await Installation.installationTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', installationId, true);
//                 };
//                 break;
          
//               default:
//                 throw new Error('Invalid status');
//             }
          
//             let usersToUpdate = 
//               // ? [...new Set([userId, selectedClientId, ...allUserIds].filter(Boolean))]
//               [...new Set([selectedClientId,userId,...project_members, ...allUserIds].filter(Boolean))];
          
//             // Update counts for users
//             await Promise.all(usersToUpdate.map(user => updateOpenCount(user)));
          
//             console.log(`Successfully updated ${stagedCountField} for all necessary users.`);
//           };
          
//           if (installation[0]?.complete_status) {
//             emitProgress('updating_installation_counts', `Updating installation tab counts...`, 90);
            
//             // Call the refactored function for updating staged counts based on complete_status
//             await handleTabCountUpdate(installation[0]?.complete_status, installationId, allUsersToCheck, userType, selectedClientId, allUserIds,installation[0]?.published,);
//           } else {
//             console.log("Invalid complete_status");
//           }
          
//           emitProgress('complete', `Installation template saved successfully!`, 100);
//           // Send install photos to company install_address_email (fire-and-forget)
//           sendInstallPhotosToEmail(submitForm, installation_id, installation, currentDate).catch((err) => {
//             console.error('Send install photos email:', err);
//           });
//           res.send({status:1,message:notificationMsg})
//         }else{
//           emitProgress('error', `Failed to submit the report`, 0);
//           res.send({
//             status:0,message:'Failed to submit the report '
//           })
//         }
//       }
//     }else{
//     emitProgress('error', `Failed to submit the template`, 0);
//     res.send({
//         status:0,message:'Failed to submit the template .'
//     })
//     }
//   } catch (error) {
//     console.log(error)
//     res.send({status:500,message:'Error submitting the report .'})
//   }
// }
const saveInstTemplate=async(req,res)=>{
  try {
    let currentDate = moment().unix();
    const {id, submitForm, installation_id, status, userId, userType, socketId} = req.body
    console.log("dataaaaaaaaaaaaaaaa 1", req.body)

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_template_save_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_template_save_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-TEMPLATE-SAVE-PROGRESS] 🚀 Starting installation template save for user:`, userId);
    emitProgress('start', `Initializing installation template save...`, 5);

    if (empty(submitForm)) {
      emitProgress('error', `Failed to submit the template`, 0);
      return res.send({
        status: 0,
        message: 'Failed to submit the template .'
      });
    }

    emitProgress('processing_form_data', `Processing form data...`, 15);

    const field_value_pairs = [];
    const valueData = removeNull(submitForm);

    for (const [key, value] of Object.entries(valueData)) {
      if (value && typeof value === 'object' && "value" in value) {
        const formattedValue =
          value.content === "date" && typeof value.value === 'number' && !isNaN(value.value)
            ? moment.unix(value.value).format('YYYY-MM-DD')
            : value.value;
        field_value_pairs.push({
          field_id: value.field_id,
          value: formattedValue,
          template_id: id,
          installation_id: installation_id,
          timestamp: currentDate,
          status: status,
        });
      } else if (value && Array.isArray(value) && value.every(item => typeof item === 'object' && "value" in item)) {
        for (const item of value) {
          if (!empty(item.value)) {
            const formattedValue =
              item.content === "date" && typeof item.value === 'number' && !isNaN(item.value)
                ? moment.unix(item.value).format('YYYY-MM-DD')
                : item.value;
            field_value_pairs.push({
              field_id: item.field_id,
              value: formattedValue,
              template_id: id,
              installation_id: installation_id,
              timestamp: currentDate,
              status: status,
            });
          }
        }
      }
    }

    if (empty(field_value_pairs)) {
      emitProgress('error', `Failed to submit the template`, 0);
      return res.send({
        status: 0,
        message: 'Failed to submit the template .'
      });
    }

    emitProgress('saving_template_data', `Saving template data to database...`, 25);

    // const installationData = { status: 4, pending_review: 1 };
    // fetch installation data needed for immediate response and background processing
      const installation_data = await Installation.fetchApointmentById(installation_id);
      const pendingReview = Number(installation_data?.[0]?.complete_status) === 1 ? 1 : 0;
      const installationData = { status: 4, pending_review: pendingReview };

    // Run field save + status update in parallel since they are independent writes
    const [submissionResponse, updateInstallationStatus] = await Promise.all([
      Installation.updateBatchData(
        "installation_temp_fields",
        field_value_pairs
      ),
      Installation.updateInstallationStatus(installationData, installation_id),
    ]);

    emitProgress('updating_installation_status', `Updating installation status...`, 35);

    if (!submissionResponse || !updateInstallationStatus) {
      emitProgress('error', `Failed to submit the report`, 0);
      return res.send({
        status: 0,
        message: 'Failed to submit the report '
      });
    }

    // Fetch data needed for immediate response and background processing
    // const installation = await Installation.fetchApointmentById(installation_id);
       const installation = installation_data;
    console.log("installationssssssss", installation);

    const userData = await Admin.getUserById(userId);

    const installationProductName = installation[0]?.product_name || installation[0]?.service_name;
    const notificationMsg = `Installation "${installationProductName || installation[0]?.name}" has been completed and published by ${userData[0]?.first_name} ${userData[0]?.last_name}.`;

    // ✅ Send response as soon as critical DB work is done
    res.send({ status: 1, message: notificationMsg });

    // 🔄 Run non-critical work in the background (fire-and-forget)
    (async () => {
      try {
        emitProgress('processing_quickbooks', `Processing QuickBooks entries...`, 45);
        
        const installationCostDataForQb = await Installation.getInstallationCostDetailsForQb(installation_id);
        console.log("installationCostDataForQb",installationCostDataForQb)
        if(installationCostDataForQb?.syncWithQuickbooks == 1){
          await addJournalEntryForProductInstalled(installationCostDataForQb)
        }

        emitProgress('fetching_installation_data', `Fetching installation and request data...`, 55);

        console.log("requestDataa");
        const requestData = await Requests.getAllRequests(installation[0]?.request_id, 1, 1);
        console.log("requestDataa 1 ", requestData);
        console.log("installation[0]?.request_id", installation[0]?.request_id);
        const requestId = installation[0]?.request_id;

        if (requestData?.data[0]?.project_category == 12 && requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
          emitProgress('updating_request_review', `Updating request review status...`, 60);
          
          const data = {
            isReview: 2
          };
          const updated = await Request.updateRequets(requestId, data);
          console.log('updated sales order----', updated);
        }

        if (requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
          emitProgress('updating_tab_counts', `Updating tab counts...`, 70);
          try {
            const facilityTypes = (requestData?.data[0]?.facility_type || "")
              .split(",")
              .map(v => v.trim())
              .filter(v => v !== "");
            const targetFacilityId = facilityTypes.filter(id => id !== String(FACILITY_ID));
            const originRequestId = requestId || null;
            const isSplitOrder = requestData?.data[0]?.is_split_order || null;
            const project_category = requestData?.data[0]?.project_category == 15 ? true : false;
            const forParentFacility = requestData?.data[0]?.for_parent_facility == 1 ? true : false;
            const installerFacilityId = installation[0]?.installer_facility_id ?? installation[0]?.service_installer_facility_id;
            const installStatus = installerFacilityId != FACILITY_ID ? installation[0]?.complete_status : 4;
            const receivedStatus = installerFacilityId != FACILITY_ID ? 1 : 0;
            if (isSplitOrder && originRequestId && targetFacilityId && project_category && forParentFacility) {
              const updateSplitMirrorStatus = await updateMirrorOrderStatusFromOtherInstallations(originRequestId, targetFacilityId, installStatus, receivedStatus);
              console.log('updateSplitMirrorStatus invoicing', updateSplitMirrorStatus);
              if (receivedStatus == 1) {
                const updateRequestStatus = await Request.updateRequets(requestId, { received_status: receivedStatus });
                console.log('updateRequestStatus == current installation', updateRequestStatus);
              }
            }
          } catch (error) {
            console.log('error updateSplitMirrorStatus invoicing', error);
          }

          // Fetch data needed for count updates in parallel
          // const [allUserIds, PartnerUserIds, projectResult] = await Promise.all([
          //   Admin.getAllUserIds(),
          //   RequestPartner.fetchPartnerUserIds(requestId),
          //   Project.getProjectByRequestId(requestId),
          // ]);
          // console.log("projectResult", projectResult);
          // const usersToUpdate = [...new Set([userId, ...PartnerUserIds, ...allUserIds].filter(Boolean))];

          // const updateEditCounts = async (uid) => {
          //   await Requests.salesOrderIncrementField(uid, 'installs_count', -1, 'installs_count_ids', requestId, false);
          //   await Requests.salesOrderIncrementField(uid, 'invoicing_count', 1, 'invoicing_count_ids', requestId, true);
          //   await Project.jobTabIncrementField(uid, 'installs_count', -1, 'installs_count_ids', projectResult, false);
          //   await Project.jobTabIncrementField(uid, 'completed_count', 1, 'completed_count_ids', projectResult, true);

          //   console.log("counts updated successfully.");
          // };

          // await Promise.all(usersToUpdate.map(uid => updateEditCounts(uid)));
          // console.log("Request tab counts updated successfully after edit.");
        }

        const EstimateData = await Request.getRequestById(requestId);
        const isSplitOrder = Number(EstimateData[0]?.is_split_order);
        const isBuildOrder = Number(EstimateData[0]?.for_parent_facility);
        const productId = installation[0]?.product_id;

        if (isSplitOrder && isBuildOrder && productId) {
          const parentFacilityId = Number(EstimateData[0]?.origin_facility_id);
          const originFacilityRequestId = Number(EstimateData[0]?.origin_facility_request_id);
          const customerOrderProductData = await CustomerOrderProduct.getCustomerOrderProductsbyProduct(requestId, productId);
          console.log('customerOrderProductData----', customerOrderProductData);
          // Process per-product work in parallel since each product is independent
          await Promise.all(
            customerOrderProductData.map(async (eachProduct) => {
              const facilityId = Number(eachProduct.facility_id);
              const productData = await Product.getProductDetailsFromId(eachProduct.product_id);
              console.log("productData", productData);

              await Product.updateCustomerOrderProductTransferStatus(eachProduct.product_id, EstimateData[0]?.id, 2);
              const newProductData = {
                ...productData,
                id: null,
                special_price: null,
                price: null,
                recipe_id: null,
                in_stock_no: Number(eachProduct?.location_quantity),
                inhouse: 6
              };
              const transferResult = await transferProductStockToOtherInstallation(
                newProductData,
                null,
                originFacilityRequestId,
                parentFacilityId,
                eachProduct.product_id
              );
              console.log('transferResult---', transferResult);

              // If transfer was successful, create a completed task in parent facility
              if (transferResult && transferResult.success) {
                try {
                  const taskResult = await SplitManagementModel.createCompletedTaskInParentFacility(
                    parentFacilityId,
                    originFacilityRequestId,
                    productData,
                    eachProduct,
                    facilityId
                  );

                  if (taskResult.success) {
                    console.log('Task created successfully in parent facility:', taskResult.data);
                  } else {
                    console.error('Failed to create task in parent facility:', taskResult.message);
                  }
                } catch (error) {
                  console.error('Error creating task in parent facility:', error);
                }
              }
            })
          );
        }

        emitProgress('processing_notifications', `Processing notifications...`, 80);

        await RequestUpdates.addRequestUpdates({
          request_id: installation[0]?.request_id,
          activity: notificationMsg,
          partner_id: 0,
          added_by: userId,
          timestamp: currentDate,
        });

        if (requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
          const isTimeandMaterial = requestData?.data[0]?.project_category == 12 ? true : false;
          await RequestUpdates.addRequestUpdates({
            request_id: installation[0]?.request_id,
            activity: isTimeandMaterial ? `The installation has been completed and moved to Review, awaiting Review.` : `The installation has been completed and moved to invoicing, awaiting approval.`,
            partner_id: 0,
            added_by: userId,
            timestamp: currentDate,
          });
        }

        let notificationUrl = "installation";
        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);

        if (installation[0].driver_userId && installation[0].driver_userId !== userId) {
          let notificationData_driver = {
            user_id: installation[0].driver_userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId
          };
          const addNotificationResult_driver = await Admin.addNotification(notificationData_driver);
        }

        const adminIds = await Admin.getAllAdminIds();
        // Increment admin noti_count and add notifications in parallel
        await Promise.all(
          adminIds
            .filter((adminId) => adminId != userId)
            .map(async (adminId) => {
              await Admin.incrementField(adminId, "noti_count", 1);
              const notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              await Admin.addNotification(notificationData);
            })
        );

        // const clientId = installation[0]?.customer_id;
        // const request_id = installation[0]?.request_id;
        // console.log("request_id request_id 1", installation[0]);
        // console.log("request_id request_id", request_id);
        // const allUserIdsForTabs = await Admin.getAllAdminUserIds();
        // const projectResultForTabs = await Project.getProjectByRequestId(request_id);
        // console.log("projectResult", projectResultForTabs);
        // const project_members = await Project.getAllMemberUserIdsByProjectId(projectResultForTabs);
        // console.log("project_members", project_members);
        // const clientUser = await Client.getClientById(clientId);
        // const selectedClientId = clientUser?.user_id || null;
        // let allUsersToCheck = [...new Set([userId, selectedClientId, ...project_members, ...allUserIdsForTabs].filter(Boolean))];
        // const installationId = installation[0]?.id;

        // const handleTabCountUpdate = async (statusVal, installationIdVal, allUsersToCheckVal, userTypeVal, selectedClientIdVal, allUserIdsVal, publishedVal) => {
        //   let updateOpenCount;
        //   let stagedCountField;

        //   // Define the logic for each status (1 = installation, 2 = pickup, 3 = shipping)
        //   switch (statusVal) {
        //     case 1: // Installation
        //       stagedCountField = 'staged_count';
        //       updateOpenCount = async (uid) => {
        //         await Installation.installationTabIncrementField(uid, 'installing_count', -1, 'installing_count_ids', installationIdVal, false);
        //         await Installation.installationTabIncrementField(uid, 'completed_count', 1, 'completed_count_ids', installationIdVal, true);
        //       };
        //       break;

        //     case 2: // Pickup
        //       stagedCountField = 'pickup_count';
        //       updateOpenCount = async (uid) => {
        //         await Installation.installationTabIncrementField(uid, 'staged_count', -1, 'staged_count_ids', installationIdVal, false);
        //         await Installation.installationTabIncrementField(uid, 'completed_count', 1, 'completed_count_ids', installationIdVal, true);
        //       };
        //       break;

        //     case 3: // Shipping
        //       stagedCountField = 'shipping_count';
        //       updateOpenCount = async (uid) => {
        //         await Installation.installationTabIncrementField(uid, 'staged_count', -1, 'staged_count_ids', installationIdVal, false);
        //         await Installation.installationTabIncrementField(uid, 'completed_count', 1, 'completed_count_ids', installationIdVal, true);
        //       };
        //       break;

        //     default:
        //       throw new Error('Invalid status');
        //   }

        //   const usersToUpdateTabs =
        //     [...new Set([selectedClientIdVal, userId, ...project_members, ...allUserIdsVal].filter(Boolean))];

        //   // Update counts for users
        //   await Promise.all(usersToUpdateTabs.map(user => updateOpenCount(user)));

        //   console.log(`Successfully updated ${stagedCountField} for all necessary users.`);
        // };

        // if (installation[0]?.complete_status) {
        //   emitProgress('updating_installation_counts', `Updating installation tab counts...`, 90);

        //   // Call the refactored function for updating staged counts based on complete_status
        //   await handleTabCountUpdate(installation[0]?.complete_status, installationId, allUsersToCheck, userType, selectedClientId, allUserIdsForTabs, installation[0]?.published);
        // } else {
        //   console.log("Invalid complete_status");
        // }

        emitProgress('complete', `Installation template saved successfully!`, 100);

        // Send install photos to company install_address_email
        try {
          await sendInstallPhotosToEmail(submitForm, installation_id, installation, currentDate);
        } catch (err) {
          console.error('Send install photos email:', err);
        }
      } catch (error) {
        console.error('[INSTALLATION-TEMPLATE-SAVE] Background processing error:', error);
        emitProgress('error', `An error occurred during background processing`, 0);
      }
    })();
  } catch (error) {
    console.log(error);
    res.send({ status: 500, message: 'Error submitting the report .' });
  }
};

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

const saveInstTemplateForMultipleInstallation = async (req, res) => {
  try {
    let currentDate = moment().unix();
    let { id, submitForm, installation_id, status, userId, userType, socketId } = req.body;
    console.log("dataaaaaaaaaaaaaaaa 2", req.body)

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_template_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-PROGRESS] 🚀 Starting installation template saving for user:`, userId);
    emitProgress('start', `Initializing installation template saving...`, 5);
    
    console.log('Received installation_id:', installation_id);
    // 🛠 Convert installation_id to an array if it's not already
    if (!Array.isArray(installation_id)) {
      installation_id = [installation_id];
    }
    console.log('Processed installation_id:', installation_id);
    if (!empty(submitForm) && installation_id.length > 0) {
      emitProgress('data_preparation', `Preparing form data for ${installation_id.length} installation(s)...`, 10);
      
      const field_value_pairs = [];
      let valueData = removeNull(submitForm);
      emitProgress('form_processing', `Processing form fields...`, 15);
      
      for (const [key, value] of Object.entries(valueData)) {
        if (value && typeof value === 'object' && "value" in value) {
          const formattedValue =
            value.content === "date" && typeof value.value === 'number' && !isNaN(value.value)
              ? moment.unix(value.value).format('YYYY-MM-DD')
              : value.value;
          
          installation_id.forEach(installId => {
            field_value_pairs.push({
              field_id: value.field_id,
              value: formattedValue,
              template_id: id,
              installation_id: installId,
              timestamp: currentDate,
              status: status,
            });
          });
        } else if (value && Array.isArray(value) && value.every(item => typeof item === 'object' && "value" in item)) {
          for (const item of value) {
            if (!empty(item.value)) {
              const formattedValue =
                item.content === "date" && typeof item.value === 'number' && !isNaN(item.value)
                  ? moment.unix(item.value).format('YYYY-MM-DD')
                  : item.value;
              
              installation_id.forEach(installId => {
                field_value_pairs.push({
                  field_id: item.field_id,
                  value: formattedValue,
                  template_id: id,
                  installation_id: installId,
                  timestamp: currentDate,
                  status: status,
                });
              });
            }
          }
        }
      }
      if (!empty(field_value_pairs)) {
        emitProgress('database_update', `Saving form data to database...`, 25);
        let submissionResponse = await Installation.updateBatchData(
          "installation_temp_fields",
          field_value_pairs
        );
        
        emitProgress('installation_processing', `Processing ${installation_id.length} installation(s)...`, 30);
        for (const installId of installation_id) {
          let installationData = { status: 4, installation_temp_id: id };
          await Installation.updateInstallationStatus(installationData, installId);
          const installation = await Installation.fetchApointmentById(installId);
          const instData = await Installation.fetchApointmentById(installId) 
          let installationProductName  = instData[0]?.product_name || instData[0]?.service_name;
          const userData = await Admin.getUserById(userId);
          if (submissionResponse) {
            emitProgress('quickbooks_processing', `Processing QuickBooks entries for installation ${installId}...`, 40);
            const installationCostDataForQb = await Installation.getInstallationCostDetailsForQb(installId);
            console.log("installationCostDataForQb",installationCostDataForQb)
            if(installationCostDataForQb?.syncWithQuickbooks == 1){
              await addJournalEntryForProductInstalled(installationCostDataForQb)
            }
            emitProgress('notifications_processing', `Creating notifications and updates...`, 50);
            let notificationMsg = `Installation "${installationProductName || installation[0]?.name}" has been completed and published by ${userData[0]?.first_name} ${userData[0]?.last_name}.`;

            await RequestUpdates.addRequestUpdates({
              request_id: installation[0]?.request_id,
              activity: notificationMsg,
              partner_id: 0,
              added_by: userId,
              timestamp: currentDate,
            });

            const newRequestData = await Requests.getAllRequests(installation[0]?.request_id, 1, 1);
            if (newRequestData?.data[0]?.allInstallationCompleted == 1 && newRequestData?.data[0]?.installation_acceptance == null) {
              await RequestUpdates.addRequestUpdates({
                request_id: installation[0]?.request_id,
                activity: `The installation has been completed and moved to invoicing, awaiting approval.`,
                partner_id: 0,
                added_by: userId,
                timestamp: currentDate,
              });
            } // comment this if QA told the before order is correct

            let notificationUrl = "installation";
            let notificationData_user = {
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };


            await Admin.addNotification(notificationData_user);
            let adminIds = await Admin.getAllAdminIds();
            for (const adminId of adminIds) {
              if (adminId != userId) {
                await Admin.incrementField(adminId, "noti_count", 1);
                let notificationData = {
                  user_id: adminId,
                  url: notificationUrl,
                  timestamp: currentDate,
                  message: notificationMsg,
                  status: 1,
                  from_id: userId,
                };
                await Admin.addNotification(notificationData);
              }
            }
            // const ProjectResult = await Project.findProjectById(installation[0]?.request_id, true); 
            // const projectResult = await Project.getProjectByRequestId(installation[0]?.request_id);  
            // const project_members = await Project.getAllMemberUserIdsByProjectId(projectResult)
            // const clientId = installation[0]?.customer_id;
            // const allUserIds = await Admin.getAllAdminUserIds();
            // const clientUser = await Client.getClientById(clientId);
            // const selectedClientId = clientUser?.user_id || null;
            // const installationId = installation[0]?.id;

            // const handleTabCountUpdate = async (status, installationId, userType, selectedClientId, allUserIds) => {
            //   let updateOpenCount;
            //   let stagedCountField;

            //   switch (status) {
            //     case 2: // Pickup
            //       stagedCountField = 'pickup_count';
            //       updateOpenCount = async (userId) => {
            //         await Installation.pickupTabIncrementField(userId, 'staged_count', -1, 'staged_count_ids', installationId, false);
            //         await Installation.pickupTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', installationId, true);
            //         await Project.jobTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', projectResult, true);
            //         await Project.jobTabIncrementField(userId, 'pickup_count', -1, 'pickup_count_ids', projectResult, false);
            //       };
            //       break;

            //     case 3: // Shipping
            //       stagedCountField = 'shipping_count';
            //       updateOpenCount = async (userId) => {
            //         await Installation.shippingTabIncrementField(userId, 'staged_count', -1, 'staged_count_ids', installationId, false);
            //         await Installation.shippingTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', installationId, true);
            //         await Project.jobTabIncrementField(userId, 'completed_count', 1, 'completed_count_ids', projectResult, true);
            //         await Project.jobTabIncrementField(userId, 'shipping_count', -1, 'shipping_count_ids', projectResult, false);
            //       };
            //       break;

            //     default:
            //       console.log('No count updates required for this status.');
            //       return;
            //   }

            //   let usersToUpdate = 
            //   // ? [...new Set([userId, selectedClientId, ...allUserIds].filter(Boolean))]
            //    [...new Set([selectedClientId,userId,...project_members, ...allUserIds].filter(Boolean))];

            //   await Promise.all(usersToUpdate.map(user => updateOpenCount(user)));

            //   console.log(`Successfully updated ${stagedCountField} for users.`);
            // };

            // emitProgress('tab_count_updates', `Updating tab counts and user statistics...`, 70);
            // if (installation[0]?.complete_status) {
            //   await handleTabCountUpdate(
            //     installation[0]?.complete_status,
            //     installationId,
            //     userType,
            //     selectedClientId,
            //     allUserIds,
            //     installation[0]?.published,
            //   );
            // } else {
            //   console.log("Invalid complete_status");
            // }

          const requestData = await Requests.getAllRequests(installation[0]?.request_id, 1, 1);
        console.log("requestDataa 1 ",requestData)
        console.log("installation[0]?.request_id",installation[0]?.request_id)
        const requestId = installation[0]?.request_id
        if (requestData?.data[0]?.project_category == 12 && requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance == null) {
          const data = {
            isReview: 2
          }
          let updated = await Request.updateRequets(requestId, data);
          console.log('updated sales order----', updated)
        }
        
        if(requestData?.data[0]?.allInstallationCompleted == 1 && requestData?.data[0]?.installation_acceptance  == null){
          try {
            const facilityTypes = (requestData?.data[0]?.facility_type || "")
              .split(",")
              .map(v => v.trim())
              .filter(v => v !== "");
            const targetFacilityId = facilityTypes.filter(id => id !== String(FACILITY_ID));
            const originRequestId = requestId || null;
            const isSplitOrder = requestData?.data[0]?.is_split_order || null;
            const project_category = requestData?.data[0]?.project_category == 15 ? true : false;
            const forParentFacility = requestData?.data[0]?.for_parent_facility == 1 ? true : false;
            const installerFacilityId = installation[0]?.installer_facility_id ?? installation[0]?.service_installer_facility_id;
            const installStatus = installerFacilityId != FACILITY_ID ? installation[0]?.complete_status : 4;
            const receivedStatus = installerFacilityId != FACILITY_ID ? 1 : 0;
            if (isSplitOrder && originRequestId && targetFacilityId && project_category && forParentFacility) {
              const updateSplitMirrorStatus = await updateMirrorOrderStatusFromOtherInstallations(originRequestId, targetFacilityId, installStatus,receivedStatus);
              console.log('updateSplitMirrorStatus invoicing', updateSplitMirrorStatus)
              if (receivedStatus == 1) {
                const updateRequestStatus = await Request.updateRequets(requestId, { received_status: receivedStatus });
                console.log('updateRequestStatus == current installation', updateRequestStatus)
              }
            }
          } catch (error) {
            console.log('error updateSplitMirrorStatus invoicing', error)
          }
        // let PartnerUserIds = await RequestPartner.fetchPartnerUserIds(requestId)
        // const usersToUpdate = [...new Set([userId,...PartnerUserIds, ...allUserIds].filter(Boolean))];
        // const updateEditCounts = async (userId) => {
        //   if(installation[0]?.complete_status == 2){
        //     await Requests.salesOrderIncrementField(userId, 'pickup_count', -1, 'pickup_count_ids', requestId, false);
        //     await Requests.salesOrderIncrementField(userId, 'invoicing_count', 1, 'invoicing_count_ids', requestId, true);  
        //   console.log("moved to pickup tab counts updated");
        //   }else if (installation[0]?.complete_status == 3) {
        //     await Requests.salesOrderIncrementField(userId, 'shipping_count', -1, 'shipping_count_ids', requestId, false);
        //     await Requests.salesOrderIncrementField(userId, 'invoicing_count', 1, 'invoicing_count_ids', requestId, true);  
        //   console.log("moved to shipping tab counts updated");
        //   }
        //   else {
        //     console.log("Unknown complete_status, skipping sales order count update.");
        //   }      
        //   console.log("counts updated successfully.")
        // }
        // Apply updates
        // await Promise.all(usersToUpdate.map(userId => updateEditCounts(userId)));
        // console.log("Request tab counts updated successfully after edit.");
        }
          }
          const requestId = installation[0]?.request_id;
          let EstimateData = await Request.getRequestById(requestId);
          const isSplitOrder = Number(EstimateData[0]?.is_split_order);
          const isBuildOrder = Number(EstimateData[0]?.for_parent_facility);
          const productId = installation[0]?.product_id;
          if(isSplitOrder && isBuildOrder && productId){
          const parentFacilityId = Number(EstimateData[0]?.origin_facility_id);
          const originFacilityRequestId = Number(EstimateData[0]?.origin_facility_request_id);
          // const productId = installation[0]?.product_id;
          const customerOrderProductData = await CustomerOrderProduct.getCustomerOrderProductsbyProduct(requestId,productId);
          // const customerOrderProductData = await CustomerOrderProduct.getCustomerOrderProductsbyRequestId(requestId);
          for(let eachProduct of customerOrderProductData){
            const facilityId = Number(eachProduct.facility_id)
            let productData ={} 
            productData =  await Product.getProductDetailsFromId(eachProduct.product_id)
            console.log("productData",productData)
            
            const update = await Product.updateCustomerOrderProductTransferStatus(eachProduct.product_id,EstimateData[0]?.id,2)
            const newProductData = {
              ...productData,
              id: null,
              special_price: null,
              // formula_cost: null,
              price: null,
              recipe_id: null,
              in_stock_no: Number(eachProduct?.location_quantity),
              inhouse: 6,
              status: 3,
              transfered_product_id: eachProduct.product_id,
            };
            const transferResult = await transferProductStockToOtherInstallation(newProductData,null,originFacilityRequestId,parentFacilityId,eachProduct.product_id);
            console.log('transferResult---', transferResult)
            
            // If transfer was successful, create a completed task in parent facility
            // if(transferResult && transferResult.success) {
            //   try {
            //     const taskResult = await SplitManagementModel.createCompletedTaskInParentFacility(
            //       parentFacilityId, 
            //       originFacilityRequestId, 
            //       productData, 
            //       eachProduct,
            //       facilityId
            //     );
                
            //     if(taskResult.success) {
            //       console.log('Task created successfully in parent facility:', taskResult.data);
            //     } else {
            //       console.error('Failed to create task in parent facility:', taskResult.message);
            //     }
            //   } catch (error) {
            //     console.error('Error creating task in parent facility:', error);
            //   }
            // }

          }

        }
        }
        res.send({ status: 1, message: "Inspection reports submitted successfully." });
      } else {
        res.send({ status: 0, message: "Failed to submit the report." });
      }
    } else {
      res.send({ status: 0, message: "Invalid data or missing installation IDs." });
    }
  } catch (error) {
    console.error(error);
    res.send({ status: 500, message: "Error submitting the report." });
  }
};

const getInstTemplateDatabyId=async(req,res)=>{
  try {
    const {id,inst_id} = req.body 
    const  data = await Installation.getTemplateDataId(id,inst_id)
    console.log(data,'-----------data')
    if(!empty(data)){
      res.status(200).send({
        status:1,data
      })
    }else{
      res.status(200).send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const updateInstTemplate =async(req,res)=>{
  try {
     const {formData} = req.body
     console.log(formData,'-------    formData-')
     if(!empty(formData)){
      for(let row of formData){
        let updateData={}
        updateData['value'] = row?.value
        updateData['status']=1
        let updateRes = await Installation.updateInstTemplateField(updateData,row?.field_id)
        if(updateRes===true){
          res.send({
            status:1,message:'Update Success'
          })
        }else{
          emitProgress('error', 'Failed to update the Installation template', 0);
          res.send({
            status:0,message:'Failed to update the Installation template'
          })
        }
        
        emitProgress('complete', `Installation template saved successfully for ${installation_id.length} installation(s)!`, 100);
        res.json({ status: 1, message: "Installation template saved successfully" });
      }
     }else{
      emitProgress('error', 'Failed to update the Installation template', 0);
      res.send({
        status:0,message:'Failed to update the Installation template'
      })
     }
  } catch (error) {
    console.log(error);
    emitProgress('error', `Error saving installation template: ${error.message}`, 0);
    res.json({ status: 0, message: "Error saving installation template" });
  }
}

const updateInstallationHoldStatus = async (req, reply) => {
  try {
    const { instId, userId, reason } = req.body;
    const currentDate = moment().unix();

    if (!instId || !userId) {
      return reply.send({ status: 0, message: "Installation id and user id are required" });
    }

    const installationData = await Installation.findInstallationDataById(instId);
    if (!installationData) {
      return reply.send({ status: 0, message: "Installation not found" });
    }
    if (!installationData.project_id || !installationData.request_id) {
      return reply.send({ status: 0, message: "Installation is missing project/request mapping" });
    }

    const installationDetails = await Installation.fetchApointmentById(instId);
    const installationName =
      installationDetails?.[0]?.name ||
      installationDetails?.[0]?.product_name ||
      installationDetails?.[0]?.service_name ||
      `Installation #${instId}`;

    const isOnHold = Number(installationData.status) === 7;
    const holdValue = isOnHold ? 0 : 1;
    const nextInstallationStatus = isOnHold ? 1 : 7;

    const installationUpdateData = {
      status: nextInstallationStatus,
      hold: holdValue,
      hold_reason: holdValue === 1 ? (reason || null) : null,
      timestamp: currentDate,
    };

    const projectDetails = await Project.getProjectById(installationData.project_id);

    const projectUpdateData = {
      hold: holdValue,
      change_order: 0,
      reason: holdValue === 1
        ? (reason || projectDetails?.reason || "")
        : (projectDetails?.reason || ""),
      timestamp: currentDate,
    };

    const requestHoldData = {
      hold: holdValue,
      hold_reason: holdValue === 1 ? (reason || null) : null,
      timestamp: currentDate,
    };

    const [installationUpdated, projectUpdatedRaw, requestUpdatedRaw] = await Promise.all([
      Installation.updateInstallationHoldStatus(instId, installationUpdateData),
      Project.updateProjectByRequestId(installationData.request_id, projectUpdateData),
      Request.updateRequestById(installationData.request_id, requestHoldData),
    ]);

    const requestUpdated = Array.isArray(requestUpdatedRaw)
      ? Number(requestUpdatedRaw[0]) > 0
      : !!requestUpdatedRaw;
    const projectUpdated = !!projectUpdatedRaw;

    if (!(installationUpdated && projectUpdated && requestUpdated)) {
      return reply.send({
        status: 0,
        message: "Failed to update installation hold status",
        debug: { installationUpdated, projectUpdated, requestUpdated }
      });
    }

    const notificationMsg = holdValue === 1
      ? `The installation "${installationName}" has been moved to Hold`
      : `The installation "${installationName}" has been removed from Hold`;

    const notificationUrl = "installation";
    await Admin.incrementField(userId, "noti_count", 1);
    await Admin.addNotification({
      user_id: userId,
      url: notificationUrl,
      timestamp: currentDate,
      message: notificationMsg,
      status: 1,
      from_id: userId,
    });

    const requestActivity = await RequestActivity.addRequestUpdate({
      request_id: installationData.request_id,
      activity: notificationMsg,
      added_by: userId,
      timestamp: currentDate,
    });
    console.log("requestActivity", requestActivity)
    const adminIds = await Admin.getAllAdminIds();
    await Promise.all(
      adminIds
        .filter((adminId) => adminId != userId)
        .map(async (adminId) => {
          await Admin.incrementField(adminId, "noti_count", 1);
          await Admin.addNotification({
            user_id: adminId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          });
        })
    );

    return reply.send({
      status: 1,
      message: notificationMsg,
      hold: holdValue,
      installation_status: nextInstallationStatus,
      requestHoldData,
      projectHoldData: projectUpdateData,
    });
  } catch (error) {
    console.log("updateInstallationHoldStatus error:", error);
    return reply.status(500).send({ status: 0, message: "Server error: " + error });
  }
}

const updateInstallationStatus = async (req,res) => {
  try{
    const {instId,userId,driverId,status,cancelReason,userType} = req.body
    console.log("loggggggggggggggg",req.body)
    let currentDate = Math.round(moment().valueOf() / 1000);

    // const initialInstalltionData = await Installation.findInstallationDataById(instId)
    // console.log("initialInstalltionData",initialInstalltionData)
    // return
    let data = {}
    data['status'] = status
    if (status === 4) {
      data['pending_review'] = 2;
    }
    if ((status === 5) && cancelReason) {
      data['cancel_reason'] = cancelReason
    } else {
      data['cancel_reason'] = null
    }
    if((status===5) && cancelReason){
      data['cancel_reason'] = cancelReason
    }else{
      data['cancel_reason'] = null
    }
    if(instId){
      const result = await Installation.updateInstallationStatus(data,instId)
      const installationData = await Installation.fetchApointmentById(instId)
      if(instId && (driverId || userId) && result){
        const deleteDataFromDriverSelectedRoute = await Routes.deleteDriverRoute(instId,driverId,userId)
      }
      if(result){
        let installation = installationData[0]
        console.log("installationinstallation",installation)
        // Notification
        let notificationMsg;
        let mobileNotification=''
        if(status === 3){
          notificationMsg = `Installation ${installation.name} has been delivered by ${installation.driver_name}.`;
          mobileNotification =`Installation ${installation.name} has been completed`
        }else if(status === 5){
          notificationMsg = `Installation ${installation.name} has been cancelled.`;
          mobileNotification =`Installation ${installation.name} has been cancelled.`
        }else if(status === 4){
          notificationMsg = `Installation ${installation.name} has completed by ${installation.driver_name}.`;
          mobileNotification =`Installation ${installation.name} has completed.`

        }
        let notificationUrl = "installation";
        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 );

        // if(installation?.fcmToken){
        //   const message = {
        //     data: {
        //         // Your custom data payload if needed
        //         // Example:
        //         score: '850',
        //         time: '2:45'
        //     },
        //     notification: {
        //         title: 'Installation',
        //         body: mobileNotification || `Installation status has been updated.`
        //     },
        //     android: {
        //       notification: {
        //         image: `https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e`
        //         // icon: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/test%2Fsignwiseround.png?alt=media&token=ecf322c0-9490-49d3-b744-dbe7c154859d', // Use the app's local icon
      
        //       }},
        //     token: installation.fcmToken // Add registration tokens of specific devices here
        //   };
          
        //   try {
        //     const response = await admin.messaging().send(message);
        //     console.log('Successfully sent message:', response);
        // } catch (error) {
        //     console.error('Error sending message:', error);
    
        //     // Check if error is due to an invalid/expired FCM token
        //     if (error.code === 'messaging/registration-token-not-registered') {
        //         console.warn(`Invalid FCM token detected: ${installation.fcmToken}. Skipping notification.`);
        //     } else {
        //         console.error(` Unexpected FCM error: ${error.message}`);
        //     }
        // }
    
        //   // admin.messaging().send(message)
        //   //     .then((response) => {
        //   //     console.log('Successfully sent message:', response);
        //   //   // Assuming 'res' is used to respond to an HTTP request
        //   //     res.send({ success: true, response });
        //   //     })
        //   //     .catch((error) => {
        //   //       console.error('Error sending message:', error);
        //   //   res.status(500).send({ error: error.message });
        //   // });
        // }

      const notificationTokens = [];

if (installation?.fcmToken) {
  notificationTokens.push(installation?.fcmToken);
}
if (installation?.installerFcmToken) {
  notificationTokens.push(installation?.installerFcmToken);
}


if (notificationTokens.length > 0) {
  for (const token of notificationTokens) {
    console.log("notificationTokenstoken", token);
    const message = {
      data: {},
      notification: {
        title: 'Installation',
        body: mobileNotification || 'Installation status has been updated.',
      },
      android: {
        notification: {
          image: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e'
          // icon: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/test%2Fsignwiseround.png?alt=media&token=ecf322c0-9490-49d3-b744-dbe7c154859d'
        }
      },
      token
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message to token:', token, response);
      })
      .catch((error) => {
        console.error('Error sending message to token:', token, error);
      });
    }}


        if(installation.driver_userId!==userId){
            let notificationData_driver = {
              user_id:installation.driver_userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId
          }
          const addNotificationResult_driver = await Admin.addNotification( notificationData_driver );
        }

        const userDataArr = await Admin.getUserById(userId);
        const userData = userDataArr?.[0]; // safely access first object

        const fullName = userData
          ? `${userData.first_name || ''} ${userData.last_name || ''}`.trim() || userData.username
          : 'Unknown User';

        // await RequestUpdates.addRequestUpdates({
        //   request_id: installation.request_id,
        //   // activity: `Installation "${installation.name}" for "${installation.product_name}" - Route "${installation.route_name}" has been completed by ${fullName}.`,
        //   activity: `Installation "${installation.product_name}" has been completed by ${fullName}.`,
        //   partner_id: 0,
        //   added_by: userId,
        //   timestamp: currentDate,
        // });

        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 );    
            }
        }


        const initialInstalltionData = await Installation.findInstallationDataById(instId)
        const allInstalltionData = await Installation.findInstallationDataByRequestId(initialInstalltionData.request_id)
        let allInstallationCompleted = allInstalltionData.every(val => val.status === 4 || val.status === 5);
        
        let updateRoute =null
        if(allInstallationCompleted){
          let data={};
          data['assigned_sales_order'] = null
          data['assigned'] = 0
           updateRoute =await Route.updateRoute(data,initialInstalltionData.route_id)
        }

        // if (allInstallationCompleted) {
        //   await RequestUpdates.addRequestUpdates({
        //     request_id: initialInstalltionData.request_id,
        //     activity: `The installation has been completed and moved to invoicing, awaiting approval.`,
        //     partner_id: 0,
        //     added_by: userId,
        //     timestamp: currentDate,
        //   });
        // } // un comment this if QA told the before order is correct
            const installationById = await Installation.findInstallationById(instId)
            if (!installationById) {
                console.error("Installation data not found for instId:", instId);
                return res.status(400).send({ status: 0, message: "Installation not found." });
            }
            // const clientId = installationById.customer_id;
            // const ProjectResult = await Project.findProjectById(installationById?.request_id,true);   
            // const project_members = await Project.getAllMemberUserIdsByProjectId(ProjectResult?.id)
            // const allUserIds = await Admin.getAllAdminUserIds();
            // const clientUser = await Client.getClientById(clientId);
            // const selectedClientId = clientUser?.user_id ||null;
            // let allUsersToCheck = [...new Set([userId, selectedClientId,...project_members, ...allUserIds].filter(Boolean))];
            // const installationId = instId
            // const installationStatus = installation?.status
            // let updateCounts = async () => {};

          //   if (installationStatus == 5) {  
          //       updateCounts = async (userId) => {
          //           try {
          //               console.log(`Updating installing_count for user: ${userId}`);
          //               await Installation.installationTabIncrementField(userId, "installing_count", -1, "installing_count_ids", installationId, false);
                        
          //               console.log(`Updating returned_count for user: ${userId}`);
          //               await Installation.installationTabIncrementField(userId, "returned_count", 1, "returned_ids", installationId, true);
          //           } catch (error) {
          //               console.error(`Error updating counts for user ${userId}:`, error);
          //           }
          //       };
          //   } else if (installationStatus == 4) {
          //               updateCounts = async (userId) => {
          //   try {
          //       await Installation.installationTabIncrementField(userId, "installing_count", 1, "installing_count_ids", installationId, true);
          //   } catch (error) {
          //       console.error(`Error updating counts for user ${userId}:`, error);
          //   }
          //   };
          // }


            // let usersToUpdate = 
            //   // ? [...new Set([userId, selectedClientId, ...allUserIds].filter(Boolean))]
            //    [...new Set([selectedClientId,userId,...project_members, ...allUserIds].filter(Boolean))];

            // if (usersToUpdate.length > 0) {
            //   await Promise.all(usersToUpdate.map(user => updateCounts(user)));
            // }
            // console.log(`Successfully updated installs count`);


        res.send({status:1,message:notificationMsg,updateRoute})
      }else{
        res.send({status:0,message:'Failed to update installation'})
      }
    }
  }catch(error){
    console.log("Installation status updation error : ",error);
  }
}

const completeInstallationReview = async (req, res) => {
  try {
    const { instId } = req.body;
    if (!instId) {
      return res.send({ status: 0, message: 'Installation id is required.' });
    }
    const data = { pending_review: 0, review_reject_reason: null };
    const result = await Installation.updateInstallationStatus(data, instId);
    if (result) {
      return res.send({ status: 1, message: 'Installation completed and moved to Completed.' });
    }
    return res.send({ status: 0, message: 'Failed to complete installation.' });
  } catch (error) {
    console.log('completeInstallationReview error:', error);
    return res.send({ status: 0, message: 'Server error.' });
  }
};

const rejectInstallationReview = async (req, res) => {
  try {
    const { instId, reason, selectTemplate, selectedValues, isDriver, selectedDriver, userId, userType } = req.body;
    const instIdArray = Array.isArray(instId) ? instId : [instId];
    if (!instIdArray.length || !instIdArray[0]) {
      return res.send({ status: 0, message: 'Installation id is required.' });
    }
    if (!reason || typeof reason !== 'string' || !reason.trim()) {
      return res.send({ status: 0, message: 'Reject reason is required.' });
    }
    if (!selectTemplate || !selectedValues) {
      return res.send({ status: 0, message: 'Template and installer are required for re-assign.' });
    }
    const reassignReq = {
      body: {
        instId: instIdArray,
        selectTemplate,
        selectedValues: Array.isArray(selectedValues) ? selectedValues : selectedValues,
        isDriver: !!isDriver,
        selectedDriver: Array.isArray(selectedDriver) ? selectedDriver : selectedDriver,
        userId,
        userType,
      },
    };
    let reassignResult = null;
    const reassignRes = {
      send: (data) => {
        if (reassignResult !== null) return;
        reassignResult = data;
      },
      status: () => ({ send: (data) => reassignRes.send(data) }),
    };
    await reassignInstallationToDriver(reassignReq, reassignRes);
    if (reassignResult && reassignResult.status === 1) {
      const updateData = { review_reject_reason: reason.trim(), pending_review: 0 };
      try {
        await Promise.all(instIdArray.map((id) => Installation.updateInstallationStatus(updateData, id)));
        return res.send({ status: 1, message: 'Installation rejected and re-assigned to Installing.' });
      } catch (err) {
        console.error('rejectInstallationReview update error:', err);
        return res.send({ status: 0, message: 'Re-assign succeeded but failed to save reject reason.' });
      }
    }
    return res.send(reassignResult || { status: 0, message: 'Re-assign failed.' });
  } catch (error) {
    console.log('rejectInstallationReview error:', error);
    return res.send({ status: 0, message: 'Server error.' });
  }
};

const DuplicateTemplate = async (req, res) => {
  try {
    console.log(req.body, '*8888888888888888888888888888888888888')
    let { userId, values, id } = req.body;

    let data = await CustomFieldTemplate.getTemplateDataById(id)
    let formattedData = [];

    
    data.forEach(item => {
     
      const templateName = item.template_name;
      const fields = [];
  
   
      for (const key in item.fields) {
          if (item.fields.hasOwnProperty(key)) {
              const field = item.fields[key];
              const { content: label, tag: type, required,field_id,name} = field;
              const className = type !== "radio-group" && type !== "checkbox-group" ? "form-control" : "";

            {console.log("##########field.options",field)}
          let mappedArray = field.options?.map(item => {
              return {
                label: item.label,
                value:item.value,
                selected: item.selected,
               
                
              };
            });
            
            field.options
              fields.push({
                  label,
                  type,
                  required: required === 0 ? false : true,
                  className: className,
                  values:mappedArray,
                  field_id,
                  name
              });
          }
      }
  
      // Push template name and formatted fields into the formattedData array
      formattedData.push({
          template: templateName,
          fields
      });
  });
   
    let time=moment().unix()
    const template = {
      name:formattedData[0].template+time,
      timestamp: moment().unix(),
      updated_on: moment().unix(),
      added_by: req.body.userId,
      status: 6,
    };

    const formFields = formattedData[0].fields;
    let stageId = uniqid()
    let formFieldId = uniqid()
    template['template_uid'] = formFieldId
    template['stage_uid'] = uniqid()
    // template.template_uid = formFields.id;

    // if (formFields.stages && formFields.stages.length > 0) {
    //   template.stage_uid = formFields.stages[0].id;
    // } else {
    //   res.status(400).send({ status: 0, message: 'Failed to create custom field template!' });
    //   return;
    // }
    if (empty(formFields)) {
      res.status(400).send({ status: 0, message: 'Failed to duplicate installation template!' });
      return;
    }


    let templateId = await CustomFieldTemplate.addTemplate(template)

    if (templateId) {
      let i = 1;
    
      for (const row of formFields) {

        const customFields = {};
        customFields.template_id = templateId;
        // customFields.row_id = 'row' + uniqid();
        customFields.row_id = row.name;
        customFields.column_id = 'column' + uniqid();
        customFields.html_tag = row.type;
        customFields.name = row.type;

        if (row.required) {
          customFields.is_required = 1;
        }

        if (row.description) {
          customFields.help_text = row.description;
        }

        customFields.tag_uid = row.type;

        if (!empty(row.label)) {
          customFields.content = row.label.replace(/[\r\n]+/g, '').trim();
        }

        customFields.field_uid = 'field' + uniqid();
        customFields.position_order = i++;

        if (row.placeholder) {
          customFields.placeholder = row.placeholder;
        }

        if (row.date_format) {
          customFields.date_format = row.date_format;
        }

        if (row.pattern) {
          customFields.pattern = row.pattern;
        }

        if (row.href) {
          customFields.a_href = row.href;
        }

        if (row.target) {
          customFields.a_target = row.target;
        }

        if (customFields.tag_uid === 'header') {
          customFields.default_select = 'h1';
          if (row.tag) {
            row.tag.forEach((headerTag) => {
              if (headerTag.selected) {
                customFields.default_select = headerTag.value;
              }
            });
          }
        }

        customFields.timestamp = moment().unix();
        customFields.added_by = userId;
        customFields.status = 1;
        console.log("##############", row.subtype);
        if (!empty(row.subtype)) {
          customFields.input_type = row.subtype || 'text';
        }

        const fieldId = await CustomFieldTemplate.addTemplateField(customFields);

        if (row.values) {
          let o = 1;
          for (const fieldOption of row.values) {
            console.log("RRRRRRRRRRRRRNN", fieldId);
            const customFieldOptions = {};
            customFieldOptions.field_id = fieldId;
            customFieldOptions.option_name = fieldOption.label;
            customFieldOptions.selected = fieldOption.selected ? parseInt(fieldOption.selected) : 0

            // if (formFields.fields[fieldId].content && customFieldOptions.option_name === formFields.fields[fieldId].content) {
            //   customFieldOptions.selected = 1;
            // }

            customFieldOptions.position_order = o++;
            customFieldOptions.timestamp = moment().unix();
            customFieldOptions.added_by = userId;
            customFieldOptions.status = 1;

            const fieldOptionId = await CustomFieldTemplate.addTemplateFieldOptions(customFieldOptions);
          }
        }
      }
      let notificationMessage = "New installation template " + formattedData[0].template + " has been duplicated"
      let notificationUrl = "dashboard/installation-template"
      const adminIds = await Admin.getAllAdminIds()
      for (let eachadminIds of adminIds) {
        if (eachadminIds != userId) {
          let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
          let addNotification = {
            user_id: eachadminIds,
            url: notificationUrl,
            timestamp: moment().unix(),
            message: notificationMessage,
            status: 1,
            from_id: userId,
          }
          const addNotificationResult = await Admin.addNotification(addNotification);
        }
      }
      const incrementResult_User = await Admin.incrementField(userId, "noti_count", 1);

      let notificationData_user = {
        user_id: userId,
        url: notificationUrl,
        timestamp: moment().unix(),
        message: notificationMessage,
        status: 1,
        from_id: userId,
      };

      const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      res.send({
        status: 1, msg: notificationMessage
      })
    }
    else {
      res.send({
        status: 1, msg: "Failed to add new template"
      })
    }
  } catch (error) {
    console.error(error);
    res.status(500).send({ message: "Server error" + error });
  }
}
const updateTemplate = async (req, res) => {
  try {
   
    let { userId, values, name,id } = req.body;
    const template = {
      name: req.body.name,
      timestamp: moment().unix(),
      updated_on: moment().unix(),
      added_by: req.body.userId,
      status: 6,
    };

    const formFields = req.body.values;
    let stageId = uniqid()
    let formFieldId = uniqid()
    template['template_uid'] = formFieldId
    template['stage_uid'] = uniqid()
 
    if (empty(values)) {
      res.status(400).send({ status: 0, message: 'Failed to create custom field template!' });
      return;
    }

    let templateId = await CustomFieldTemplate.updateCustomFieldTemplate(id,template)
    // let templateId = await CustomFieldTemplate.addTemplate(template)

    if (templateId) {
      let i = 1;
      // let deleteExisting=await CustomFieldTemplate.deleteCustomField(id)
      const names = values.map(item => `"${item.name}"`);
      const namesCSV = names.join(', ');

    
      let deleteExisting=await CustomFieldTemplate.removeCustomField(id,namesCSV)
      // let deleteExisting=await CustomFieldTemplate.updateCustomField(id)
      for (const row of values) {
        let existing=await CustomFieldTemplate.checkExisting(id,row.name)
        const customFields = {};
        customFields.template_id = templateId;
        customFields.row_id = row.name||row.type;
        customFields.column_id = 'column' + uniqid();
        customFields.html_tag = row.type;
        customFields.name = row.type;

        if (row.required) {
          customFields.is_required = 1;
        }

        if (row.description) {
          customFields.help_text = row.description;
        }

        customFields.tag_uid = row.type;

        if (!empty(row.label)) {
          customFields.content = row.label.replace(/[\r\n]+/g, '').trim();
        }

        customFields.field_uid = 'field' + uniqid();
        customFields.position_order = i++;

        if (row.placeholder) {
          customFields.placeholder = row.placeholder;
        }

        if (row.date_format) {
          customFields.date_format = row.date_format;
        }

        if (row.pattern) {
          customFields.pattern = row.pattern;
        }

        if (row.href) {
          customFields.a_href = row.href;
        }

        if (row.target) {
          customFields.a_target = row.target;
        }

        if (customFields.tag_uid === 'header') {
          customFields.default_select = 'h1';
          if (row.tag) {
            row.tag.forEach((headerTag) => {
              if (headerTag.selected) {
                customFields.default_select = headerTag.value;
              }
            });
          }
        }

        customFields.timestamp = moment().unix();
        customFields.added_by = userId;
        customFields.status = 1;
        console.log("##############", row.subtype);
        if (!empty(row.subtype)) {
          customFields.input_type = row.subtype || 'text';
        }
        console.log("##############", existing);
        let fieldId
        if(existing){
          console.log("##############existing", existing);
           fieldId = await CustomFieldTemplate.updateTemplateField(existing.id,customFields)
        }
        else{
           fieldId = await CustomFieldTemplate.addTemplateField(customFields);
        }
       
        if (row.values) {
          let o = 1;
          console.log("RRRRRRRRRRRRRNN", fieldId);
          let names = row.values.map(item =>item.value);
          let integerValues = names.filter(value => Number.isInteger(value));
          let namesCSV = integerValues.join(', ');
          console.log("RRRRRRRRRRRRRNN", namesCSV);
          let fetchAllOptions=await CustomFieldTemplate.fetchOptions(fieldId)
          if(fetchAllOptions){
            let deleteExisting=await CustomFieldTemplate.removeCustomFieldOptions(fieldId,namesCSV)
          }
         
          console.log("fetchAllOptions", fetchAllOptions);
          for (const fieldOption of row.values) {
            console.log("RRRRRRRRRRRRRNN", fieldId);
            let existing=await CustomFieldTemplate.checkExistingOptions(Number.isInteger(fieldOption.value),fieldId)
            const customFieldOptions = {};
            customFieldOptions.field_id = fieldId;
            customFieldOptions.option_name = fieldOption.label;
            customFieldOptions.selected = fieldOption.selected ? parseInt(fieldOption.selected) : 0

            // if (formFields.fields[fieldId].content && customFieldOptions.option_name === formFields.fields[fieldId].content) {
            //   customFieldOptions.selected = 1;
            // }

            customFieldOptions.position_order = o++;
            customFieldOptions.timestamp = moment().unix();
            customFieldOptions.added_by = userId;
            customFieldOptions.status = 1;
            if(existing){
              const fieldOptionId = await CustomFieldTemplate.updateTemplateFieldOptions(customFieldOptions,fieldOption.value)
            }
            else{
              const fieldOptionId = await CustomFieldTemplate.addTemplateFieldOptions(customFieldOptions);
            }
           
          }
        }
      }
      let notificationMessage = "New custom field template " + req.body.name + " has been Updated"
      let notificationUrl = "dashboard/custom-field-template"
      const adminIds = await Admin.getAllAdminIds()
      for (let eachadminIds of adminIds) {
        if (eachadminIds != userId) {
          let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
          let addNotification = {
            user_id: eachadminIds,
            url: notificationUrl,
            timestamp: moment().unix(),
            message: notificationMessage,
            status: 1,
            from_id: userId,
          }
          const addNotificationResult = await Admin.addNotification(addNotification);
        }
      }
      const incrementResult_User = await Admin.incrementField(userId, "noti_count", 1);

      let notificationData_user = {
        user_id: userId,
        url: notificationUrl,
        timestamp: moment().unix(),
        message: notificationMessage,
        status: 1,
        from_id: userId,
      };

      const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      res.send({
        status: 1, msg: notificationMessage
      })
    }
    else {
      res.send({
        status: 1, msg: "Failed to add new template"
      })
    }
  } catch (error) {
    console.error(error);
    res.status(500).send({ message: "Server error" + error });
  }
}

////////////////////////
const getAddressFromCoordinates = async (latitude, longitude) => {
  try {
    const url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${longitude},${latitude}.json?access_token=${MAPBOX_ACCESS_TOKEN}`;
    const response = await axios.get(url);

    const features = response.data.features;

    let address = '';
    let city = '';
    let state = '';
    let zipcode = '';

    features.forEach((item) => {
      console.log('installationData new', item)
      if (item.place_type.includes('address') && !address) {
        address = item.text;
      }
      if (item.place_type.includes('locality') && !address) {
        address = item.text;
      }
      if (item.place_type.includes('place') && !city) {
        city = item.text;
      }
      if (item.place_type.includes('region') && !state) {
        state = item.text;
      }
      if (item.place_type.includes('postcode') && !zipcode) {
        zipcode = item.text;
      }
    });

    // If no detailed address, use city as fallback
    if (!address) {
      address = city;
    }

    return { address, city, state, zipcode };
  } catch (error) {
    console.error('Error fetching address from coordinates:', error.message);
    throw error;
  }
};

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

const updateLatLong = async (req,res)=>{
  try {
    const {markerId , latitude , longitude}= req.body
    console.log('markerIdmarkerIdmarkerIdmarkerId', markerId)
    
    const updatedAddress = await getAddressFromCoordinates(latitude,longitude)
    console.log('updatedAddress', updatedAddress)

    const data={
      lat:latitude,
      lng:longitude,
      address:updatedAddress.address,
      city:updatedAddress.city,
      state:updatedAddress.state,
      zipcode:updatedAddress.zipcode,
    }
    const result = await Installation.updateInstallationDataById(markerId,data)

    const installationData = await Installation.findInstallationDataById(markerId)
    console.log('installationData', installationData)
    if(installationData.product_id){
      const updateRequestLocation = await Requests.updateLocation(data,installationData.location_id)
    }else if(installationData.labour_cost_service_id){
      const updateRequestServiceLocation = await Requests.updateServiceLocation(data,installationData.location_id)

    }else{
       console.log("no produts no service");
       
    }
    if(result) {
      res.send({status:1,message:"updated successfully",updatedInstallationData:installationData})

    }else{
      res.send({status:0,message:"failed to update",updatedInstallationData:[]})
    }
  
    
  } catch (error) {
    res.send({message:'server error',error:error,status:0})
  }
}



// const convertJobToInstallation = async (req, res) => {
//   try {
//     const {selectedIds , userId} = req.body;
//     let user_Id =userId
//     let flag=0;
//     let currentDate = moment().unix();
//     const ids = Array.isArray(selectedIds) ? selectedIds : [selectedIds];
//     let result= {}
//     let productOrServiceData = [];

//     for (let id of ids) {
//        result = await Project.findProjectById(id);
//       console.log("result", result);

//       if (result.project_category == 11) {
//         // Get services
//         productOrServiceData = await Installation.getServices(result.request_id);

//         for (let service of productOrServiceData) {
//           let locationdata = await Installation.getServiceLocations(service.id, result.request_id);

//           service.locationdata = locationdata;
//         }
//       } else {
//         // Get products if not project category 11
//         productOrServiceData = await Installation.getProducts(result.id);
      
//         for (let product of productOrServiceData) {
//           let locationdata = await Installation.getLocations(product.id,product.product_id)
//           product.locationdata = locationdata;
//         }
//       }

//       console.log('productOrServiceData with locationdata', productOrServiceData[0].locationdata);
 
//       for (let data of productOrServiceData) {
//         let locationData = data.locationdata
//           console.log('locationDatalocationDatalocationData',locationData)
          
//           /////
//               for(let i=0;i<locationData.length;i++){
//       data.address = locationData[i].address
//       data.city = locationData[i].city
//       data.state = locationData[i].state
//       data.zipcode = locationData[i].zip
//       data.name=result.name
      
  
//       data.project_id = result.id
//       data.request_id = result.request_id
//       data.product_id = data?.product_id
//       data.labour_cost_service_id = data?.labour_cost_service_id
//       data.product_index = locationData[i].product_index
//       data.location_id =  locationData[i].id
//       data.installation_date = result.installation_date
//       // data.installation_temp_id = values.installation_temp_id
//       data.source = data?.source || 1
//       data.due_date = result.installation_date
//       // data.team_id = values.team_user_id||values.team.map(driver => driver.user_id).join(",")
//       // data.driver_id = values.isDriver ?values.team.map(driver => driver.id).join(",") : null
//       // data.route_id = values.isDriver ? values.route?.id : null
//       data.order_information = values?.order_information || 1
//       data.added_by = user_Id
//       data.timestamp = moment().unix()
//       // data.status = (values.isDriver && values.route?.id) ? 6 : 1
//       data.status =  1
//       // data.driver_is_installer = values.isDriver ? 2 : 1
//       data.location_quantity = locationData[0]?.location_quantity || 1

//       let result = []
      
//         let resultData = await Installation.addInstallationAppointment(data);
        
   
//       if (result?.length == 1) {
//         flag=1
//         let projectData={
//           installation_date:result.installation_date, 
//         }
//         let result = await Project.updateProject(data.order_id, projectData);
//           let notificationMsg = `New Appointment to the "${data.address}" has been added.`;
//           let notificationUrl = "installation";
        
//           const incrementResult_User = await Admin.incrementField(user_Id, "noti_count", 1);
//           let notificationData_user = {
//               user_id: user_Id,
//               url: notificationUrl,
//               timestamp: currentDate,
//               message: notificationMsg,
//               status: 1,
//               from_id: user_Id,
//           };
//           const addNotificationResult_user = await Admin.addNotification(notificationData_user);
          
          
//       }
//     }
//       }
//     }

//     res.send({ message: "success", status: 1 });
//   } catch (error) {
//     console.log("error", error);
//     res.send({ message: 'server error', status: 0 });
//   }
// };



  const convertJobToInstallation = async (req, res) => {
    try {
      const { selectedIds, userType, userId, status, request, completeStatus, clientId, directInstalls } = req.body;
     
      let user_Id = userId;
      let flag = 0;
      let movedToInvoicing = 0
      let currentDate = moment().unix();
      const ids = Array.isArray(selectedIds) ? selectedIds : [selectedIds];
      let adminMangerIds = await Admin.getAllAdminAndManagerUserIds();
      let result = {}; // Outer result for project data
      let productOrServiceData = [];
      let STATUS = status ? status : null;
      
      // Store data for background processing
      let backgroundTasks = [];
      let completeStatuses = [];
      for (let id of ids) {
        result = await Project.findProjectById(id, request); // Fetch project data
        const allCreatedTasks = await ProjectTask.getAllProjectTasks(result.id, 1, 1);
        console.log("allCreatedTasks", allCreatedTasks);

        const isSingleCard = result?.is_single_card == 1 ? true : false;
        console.log("isSingleCard", isSingleCard);
        console.log("result", result);
        if (result.project_category == 1111) { //currently not using as per the new workflow of service only now the service only job have catalog on sales order
          // Get services if project category is 11
          productOrServiceData = await Installation.getServices(
            result.request_id
          );

          for (let service of productOrServiceData) {
            let locationdata = await Installation.getServiceLocations(
              service.id,
              result.request_id
            );
            service.locationdata = locationdata;
          }
        } else {
          let serviceData = [];
          let productData = [];
          const newServiceData = await Installation.getServices(result.request_id);
          // serviceData = newServiceData?.filter((item) => item.makeInstallCard == 1);
          if(result.project_category == 12){
            serviceData = newServiceData?.filter((item) => {
              if(item.labour_cost_service_id == 10) {
                return item.makeInstallCard_lcs == 1;
              } else {
                return item.makeInstallCard == 1;
              }
            });
          }else{
            serviceData = newServiceData?.filter((item) => item.makeInstallCard == 1);
          }
          console.log('newServiceData', newServiceData)
          console.log('serviceData', serviceData)

          for (let service of serviceData) {
            let locationdata = await Installation.getServiceLocations(service.id, result.request_id);
            service.locationdata = locationdata;
          }
          productData = await Installation.getProducts(result.order_id);
          console.log("productData", productData);

          // Filter products for split orders - only include current facility products when project_category != 15
          if (result.is_split_order && result.project_category != 15) {
            productData = productData.filter(product => product.facility_id == FACILITY_ID);
            serviceData = serviceData.filter(service => service.facility_id == FACILITY_ID);
          }

          for (let product of productData) {
            let locationdata = await Installation.getLocations(product.id, product.product_id);
            product.locationdata = locationdata || [];
          }
          productOrServiceData = [...serviceData, ...productData];
        }

        console.log("productOrServiceData with locationdata", productOrServiceData);
      //   if (result.project_category == 12) {
      //   productOrServiceData = productOrServiceData.length ? [productOrServiceData[0]] : [];
      //   if (productOrServiceData[0]?.locationdata?.length) {
      //     productOrServiceData[0].locationdata = [productOrServiceData[0].locationdata[0]];
      //   }
      // }

      if (result.project_category == 12) {
        const firstWithLocation = productOrServiceData.find(
          item => item?.locationdata && item.locationdata.length > 0
        );
        productOrServiceData = firstWithLocation ? [firstWithLocation] : [];
        if (productOrServiceData[0]?.locationdata?.length) {
          productOrServiceData[0].locationdata = [productOrServiceData[0].locationdata[0]];
        }
      }      

        let conversionLogged = false;
        let projectCompleteStatuses = [];
        
        for (let data of productOrServiceData) {
          // if(data?.map_service != 1){
          let locationData = data.locationdata;
          console.log("locationDatalocationDatalocationData", locationData);

          for (let i = 0; i < locationData.length; i++) {
            if (result.project_category != 12 && data?.labour_cost_service_id && !(result.is_split_order && result.project_category == 15) && data.makeInstallCard_lcs != 1) {
              continue;
            }
            if((result.project_category !==11 && result.project_category !== 12 ) && data?.labour_cost_service_id == 10 && !(result.is_split_order && result.project_category == 15)) continue;
            data.address = locationData[i].address;
            data.city = locationData[i].city;
            data.state = locationData[i].state;
            data.zipcode = locationData[i].zip;
            data.name = result.name;
            data.project_id = result.id;
            data.request_id = result.request_id;
            data.product_id = data?.product_id;
            data.labour_cost_service_id = data?.labour_cost_service_id;
            data.product_index = locationData[i].product_index;
            data.location_id = locationData[i].id;
            data.installation_date = result.installation_date;
            data.installation_start_date = result.installation_start_date || null;
            data.installation_end_date = result.installation_end_date || null;
            data.source = data?.source || 1;
            data.due_date = result.installation_date;
            data.order_information = result?.order_information || 1;
            data.added_by = user_Id;
            data.timestamp = moment().unix();
            data.status = 1;
            data.complete_status = data?.delivery_type_id ?? completeStatus ?? 1;
            data.description = (result.description || '').replace(/\r?\n/g, '\n');
            data.description_lines = data.description ? data.description.split('\n') : [];
            data.notes = (result.notes || '').replace(/\r?\n/g, '\n');
            data.notes_lines = data.notes ? data.notes.split('\n') : [];
            data.location_quantity = data?.labour_cost_service_id || data.is_single_card == 1
                                      // ? locationData[0]?.location_quantity : 1;
                                      ? (locationData[0]?.location_quantity > 0 ? locationData[0]?.location_quantity : 1) : 1;
            data.route_id = result?.map_service_id || null;
            delete data?.id;

            console.log("dataaaaaaaaaaaaaaaaaaaaa 2", data);

            let installationResult = await Installation.addInstallationAppointment(data);
            if (installationResult) {
              if (installationResult?.complete_status != null) {
                completeStatuses.push(installationResult.complete_status);
                projectCompleteStatuses.push(installationResult.complete_status);
              }

              flag = 1;
              let projectData = {
                installation_date: installationResult.installation_date,
                change_order : directInstalls ? 0 : request ? 1 : 0
              };
              console.log("installationResultttttt", installationResult);
              // Update project
              let projectUpdateResult = await Project.updateProject(data.order_id, projectData);
              let notificationMsg = `New Appointment to the "${data.address}" has been added.`;
              let notificationUrl = "installation";
              // Increment notification count
              const incrementResult_User = await Admin.incrementField(user_Id, "noti_count", 1);
              let notificationData_user = {
                user_id: user_Id,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: user_Id,
              };
              // Add notification for user
              const addNotificationResult_user = await Admin.addNotification(notificationData_user);
              
              // Collect data for background processing
              const allUserIds = await Admin.getAllAdminUserIds();
              console.log("project_memberssssss 1", allUserIds);
              const project_members = await Project.getAllMemberUserIdsByProjectId(result?.id);
              console.log("project_memberssssss 2", project_members);
              const clientUser = await Client.getClientById(clientId);
              const selectedClientId = clientUser?.user_id || null;
              let allUsersToCheck = [
                ...new Set(
                  [
                    userId,
                    selectedClientId,
                    ...project_members,
                    ...allUserIds,
                  ].filter(Boolean)
                ),
              ];
              console.log("allUsersToCheckallUsersToCheck--", allUsersToCheck);
              const installationId = installationResult?.id;
              
              // Store background task data instead of executing immediately
              if (installationResult?.complete_status) {
                backgroundTasks.push({
                  installationResult,
                  installationId,
                  allUsersToCheck,
                  userType,
                  selectedClientId,
                  allUserIds,
                  project_members,
                  result,
                  adminMangerIds,
                  userId
                });
              }
            }
          }
        }
        // 🔹 Add conversion log after all installations for this project (so we have full projectCompleteStatuses)
        if (flag === 1 && !conversionLogged) {
          const getStatusLabel = (s) => ({ 1: 'Installs', 2: 'Pickup', 3: 'Shipping' }[s] || '');
          const labels = [...new Set(projectCompleteStatuses)].sort((a, b) => a - b).map(getStatusLabel).filter(Boolean);
          const typeLabel = labels.length === 0 ? 'Installation' : labels.length === 1 ? labels[0] : labels.length === 2 ? `${labels[0]} and ${labels[1]}` : `${labels.slice(0, -1).join(', ')} and ${labels[labels.length - 1]}`;
          await RequestUpdates.addRequestUpdates({
            request_id: result?.request_id,
            activity: `The Sales Order "${result?.name}" has been converted to ${typeLabel}.`,
            partner_id: 0,
            added_by: user_Id,
            timestamp: moment().unix(),
          });
          conversionLogged = true;
        }
        if (allCreatedTasks?.length <= 0 && flag === 0) {
          movedToInvoicing = 1
          console.log('movedToInvoicinggggg',movedToInvoicing)
        }
        if (allCreatedTasks?.length > 0 && flag === 0) {
          console.log(`⚠️ No installation created for project ${result.id}, but tasks exist.`);
          
          await Project.updateProject(result.id, { noServiceNoTask: 0 , change_order: directInstalls ? 0 : request ? 1 : 0 });
          await Request.updateRequestById(result.request_id, { noServiceNoTask: 0 });
          movedToInvoicing = 1
          console.log('movedToInvoicing',movedToInvoicing)
          // notify
          let notificationMsg = `Sales Order "${result.name}" has been moved to 'Invoicing' because no installation was created.`;
          let notificationUrl = "official-request";
          // Increment notification count
          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);

          // Alert to all admins of new added project

          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);
            }
          }
        }


        let projData = { status: 3, completion: 100 ,change_order: directInstalls ? 0 : request ? 1 : 0 };
        let taskData = { status: 3, complete: 100 };
        const projeId = result.id
        if(projeId){
          const updated = await Project.updateProject(projeId, projData);
          const updateAllTask = await ProjectTask.updateProjectTaskByProjectId(taskData, projeId);
          const updateAllSubtask = await ProjectTask.updateProjectSubTaskByProjectId(taskData, projeId);
        }
        let projects = await Project.getProjectById(id);
        console.log('projectsssssssssssss', projects)
        if(projects){
          try {
            const facilityTypes = (projects?.facility_type || "")
              .split(",")
              .map(v => v.trim())
              .filter(v => v !== "");
            const targetFacilityId = projects?.origin_facility_id || null;
            const originRequestId = projects?.request_id || null;
            const isSplitOrder = projects?.is_split_order || null;
            const project_category = projects?.project_category == 15 ? true : false;
            const forParentFacility = projects?.for_parent_facility == 1 ? true : false;
            if (isSplitOrder && originRequestId && targetFacilityId && project_category && forParentFacility) {
              // Get all customer products data for the request
              const customerProducts = await CustomerOrderProduct.getCustomerOrderProductsbyRequestId(originRequestId);
              console.log('customerProducts----', customerProducts);

              // Check installer_facility_id from customer products (all have same installer_facility_id)
              const minPaymentStatus = customerProducts?.length > 0 && customerProducts[0]?.installer_facility_id != FACILITY_ID ? 1 : 0;
              const updateOriginFacilityStatus =
                await SplitManagementModel.updateOriginFacilityRequestStatus(
                  originRequestId,        // originRequestId in target DB
                  targetFacilityId, // which installation DB to update
                  {
                    status: 4,
                    split_mirror_status: completeStatus,
                    timestamp: moment().unix(),
                    min_payment_status: minPaymentStatus
                  }
                );
                if(updateOriginFacilityStatus){
                  // Also update the local request with min_payment_status = 0
                  const updateRequest = await Request.updateRequets(projects.request_id, { min_payment_status: minPaymentStatus });
                  console.log('updateRequest (installation completion projects)', updateRequest)
                }
              console.log('updateOriginFacilityRequestStatus (installation)', updateOriginFacilityStatus);
            }
          } catch (error) {
            console.log('error updateSplitMirrorStatus12345', error)
          }
      }
      }
      
      // Store invoicing data for background processing
      let invoicingBackgroundData = null;
      if (movedToInvoicing === 1) {   
        invoicingBackgroundData = {
          ids,
          userId,
          clientId,
          adminMangerIds,
          currentDate
        };
      }
      
      // Send response immediately
      const mixed_installation = new Set(completeStatuses).size > 1;
      console.log('movedToInvoicing 222',movedToInvoicing)
      res.send({ message: "success", status: 1, productOrServiceData, result, movedToInvoicing, mixed_installation,mixed_status:completeStatuses });
      
      // Process background tasks after response is sent
      setImmediate(async () => {
        try {
          // Process tab count updates and notifications for each installation
          for (const task of backgroundTasks) {
            const { installationResult, installationId, allUsersToCheck, userType, selectedClientId, allUserIds, project_members, result, adminMangerIds, userId } = task;
            
            // const handleTabCountUpdate = async (
            //   status,
            //   installationId,
            //   allUsersToCheck,
            //   userType,
            //   selectedClientId,
            //   allUserIds,
            //   project_members,
            //   result
            // ) => {
            //   let ensureUserExists;
            //   let updateOpenCount;
            //   let stagedCountField;

            //   // Define the logic for each status (1 = installation, 2 = pickup, 3 = shipping)
            //   switch (status) {
            //     case 1: // Installation
            //       stagedCountField = "staged_count";
            //       ensureUserExists = async (userId) => {
            //         let userOrderCount =
            //           await Installation.getInstallationTabCountByUserId(
            //             userId
            //           );
            //         if (!userOrderCount || userOrderCount === "No record found") {
            //           const installationData = {
            //             staged_count: 0,
            //             installing_count: 0,
            //             returned_count: 0,
            //             completed_count: 0,
            //             timestamp: moment().unix(),
            //             user_id: userId,
            //             staged_count_ids: installationId,
            //           };
            //           await Installation.addInstallationTabCount(installationData);
            //         }
            //       };
            //       updateOpenCount = async (userId) => {
            //         await Installation.installationTabIncrementField(
            //           userId,
            //           "staged_count",
            //           1,
            //           "staged_count_ids",
            //           installationId
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "in_production_count",
            //           -1,
            //           "in_production_count_ids",
            //           result?.request_id,
            //           false
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "installs_count",
            //           1,
            //           "installs_count_ids",
            //           result?.request_id,
            //           true
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "pre_production_count",
            //           -1,
            //           "pre_production_count_ids",
            //           result?.id,
            //           false
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "installs_count",
            //           1,
            //           "installs_count_ids",
            //           result?.id,
            //           true
            //         );
            //         console.log("updated installs count");
            //       };
            //       break;

            //     case 2: // Pickup
            //       stagedCountField = "pickup_count";
            //       ensureUserExists = async (userId) => {
            //         let userOrderCount =
            //           await Installation.getPickupTabCountByUserId(userId);
            //         if (
            //           !userOrderCount ||
            //           userOrderCount === "No record found"
            //         ) {
            //           const installationData = {
            //             staged_count: 0,
            //             completed_count: 0,
            //             timestamp: moment().unix(),
            //             user_id: userId,
            //             staged_count_ids: installationId,
            //           };
            //           await Installation.addPickupTabCount(installationData);
            //         }
            //       };
            //       updateOpenCount = async (userId) => {
            //         await Installation.pickupTabIncrementField(
            //           userId,
            //           "staged_count",
            //           1,
            //           "staged_count_ids",
            //           installationId
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "in_production_count",
            //           -1,
            //           "in_production_count_ids",
            //           result?.request_id,
            //           false
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "pickup_count",
            //           1,
            //           "pickup_count_ids",
            //           result?.request_id,
            //           true
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "pre_production_count",
            //           -1,
            //           "pre_production_count_ids",
            //           result?.id,
            //           false
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "pickup_count",
            //           1,
            //           "pickup_count_ids",
            //           result?.id,
            //           true
            //         );
            //       };
            //       break;

            //     case 3: // Shipping
            //       stagedCountField = "shipping_count";
            //       ensureUserExists = async (userId) => {
            //         let userOrderCount =
            //           await Installation.getShippingTabCountByUserId(userId);
            //         if (
            //           !userOrderCount ||
            //           userOrderCount === "No record found"
            //         ) {
            //           const installationData = {
            //             staged_count: 0,
            //             completed_count: 0,
            //             timestamp: moment().unix(),
            //             user_id: userId,
            //             staged_count_ids: installationId,
            //           };
            //           await Installation.addShippingTabCount(
            //             installationData
            //           );
            //         }
            //       };
            //       updateOpenCount = async (userId) => {
            //         await Installation.shippingTabIncrementField(
            //           userId,
            //           "staged_count",
            //           1,
            //           "staged_count_ids",
            //           installationId
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "in_production_count",
            //           -1,
            //           "in_production_count_ids",
            //           result?.request_id,
            //           false
            //         );
            //         await Requests.salesOrderIncrementField(
            //           userId,
            //           "shipping_count",
            //           1,
            //           "shipping_count_ids",
            //           result?.request_id,
            //           true
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "pre_production_count",
            //           -1,
            //           "pre_production_count_ids",
            //           result?.id,
            //           false
            //         );
            //         await Project.jobTabIncrementField(
            //           userId,
            //           "shipping_count",
            //           1,
            //           "shipping_count_ids",
            //           result?.id,
            //           true
            //         );
            //       };
            //       break;

            //     default:
            //       throw new Error("Invalid status");
            //   }

            //   // Ensure users exist in the respective tab count table
            //   await Promise.all(
            //     allUsersToCheck.map((user) => ensureUserExists(user))
            //   );

            //   let usersToUpdate =
            //     [
            //       ...new Set(
            //         [
            //           selectedClientId,
            //           userId,
            //           ...project_members,
            //           ...allUserIds,
            //         ].filter(Boolean)
            //       ),
            //     ];

            //   // Update counts for users
            //   await Promise.all(
            //     usersToUpdate.map((user) => updateOpenCount(user))
            //   );

            //   console.log(
            //     `Successfully updated ${stagedCountField} for all necessary users.`
            //   );
            // };
            
            // Call the refactored function for updating staged counts based on complete_status
            // await handleTabCountUpdate(
            //   installationResult?.complete_status,
            //   installationId,
            //   allUsersToCheck,
            //   userType,
            //   selectedClientId,
            //   allUserIds,
            //   project_members,
            //   result
            // );
            
            // Send notifications and emails
            let allUsersToSendMessage = [
              ...new Set(
                [
                  userId,
                  selectedClientId,
                  ...project_members,
                  ...adminMangerIds,
                ].filter(Boolean)
              ),
            ];
            let typeLabel = 'Installs';
            if (installationResult?.complete_status === 2) typeLabel = 'Pickup';
            else if (installationResult?.complete_status === 3) typeLabel = 'Shipping';

            for (const userIdToCheck of allUsersToSendMessage) {
              console.log('useriddddd',userIdToCheck)
              const creator = await Admin.getUserNotificationAndPermissionSettings(userIdToCheck);
              console.log('creatorrrrrrrrr',creator)
              if (!creator) continue;

              if (
                creator?.emailEnabled === 1 &&
                creator?.pcb_new_installs === 1 &&
                creator?.pcb_new_installs_email === 1 &&
                creator?.email
              ) {
                const subject = `🛠️ New ${typeLabel} Created: ${result.name}`;
                const welcome = `Hello ${creator.name},`;
                const email_content = `A new ${typeLabel} has been created from a Job (${
                  result.project_category == 12
                    ? "Time & Material"
                    : result.project_category == 11
                    ? "Service Only"
                    : "Production"
                }). Please check your ${typeLabel} schedule.`;

                let message = newInstallsCreatedEmailTemplate({
                  user: creator,
                  requestName: result.name,
                  projectType: result.project_type,
                  location: installationResult?.address || "N/A",
                  baseUrl: BASE_URL,
                  type: typeLabel,
                  convertion: true,
                });

                message = message.replace("[emailContent]", email_content);
                message = message.replace("[CONTENT]", welcome);
                message = message.replace("[LOGIN_URL]", `${BASE_URL}`);

                const mailOptions = {
                  to: creator.email,
                  from: '"SignWise Solutions" <noreply@signwisesolutions.com>',
                  subject,
                  text: subject,
                  html: message,
                };

                try {
                  await transporter.sendMail(mailOptions);
                  console.log(`✅ ${typeLabel} email sent to: ${creator.email}`);
                } catch (err) {
                  console.error(`❌ Error sending ${typeLabel} email:`, err);
                }
              }
              if (creator?.pcb_new_installs === 1 && creator?.pcb_new_installs_sms === 1 && creator?.smsEnabled === 1 && creator?.phone) {
                const smsContent =
                  `🛠️ New ${typeLabel} Created from Sales Order!\n` +
                  `📄 Job: "${result.name}"\n` +
                  `📍 Location: ${installationResult?.address || "N/A"}\n` +
                  `🔗 View: ${BASE_URL}\n` +
                  `— SignWise`;

                const recipientPhone = creator.phone || TWILIO_PHONE;
                const Phone_country_code = creator.phone_country_code || '';

                try {
                  await sendMessageToPhoneNumber(
                    recipientPhone,
                    smsContent,
                    Phone_country_code
                  );
                  console.log(
                    `✅ SMS sent to ${
                      creator.name || "User"
                    } (${recipientPhone})`
                  );
                } catch (err) {
                  console.error(`❌ Failed to send ${typeLabel} SMS:`, err);
                }
              }
            }
          }
          
          // Process invoicing notifications in background
          if (invoicingBackgroundData) {
            const { ids, userId, clientId, adminMangerIds, currentDate } = invoicingBackgroundData;
            for (let id of ids) {
              let requests = await Request.getRequestById(id);
              console.log('requestsssssssssssssssss',requests)
              if(requests){
                const clientUser = await Client.getClientById(clientId);
                const selectedClientId = clientUser?.user_id || null;
                const allUsersToCheck = [...new Set([userId,selectedClientId, ...adminMangerIds].filter(Boolean))];
                console.log('allUsersTocheckkkkkkk',allUsersToCheck)
                for (const userIdToCheck of allUsersToCheck) {
                  console.log('useriddddd',userIdToCheck)
                  const approver = await Admin.getUserNotificationAndPermissionSettings(userIdToCheck);
                  console.log('approverrrrrrrrr',approver)
                  if (!approver) continue;
      
                  if (approver?.emailEnabled === 1 && approver?.pcb_final_invoice === 1 && approver?.pcb_final_invoice_email === 1 && approver?.email) {
                    const subject = `✅ Sales Order Moved to Invoicing: ${requests[0]?.name}`;
                    const welcome = `Hello ${approver.name},`;
                    const email_content = `The sales order "${requests[0]?.name}" has been moved to the invoicing stage. You can now proceed with generating the invoice or reviewing the order details.`;
    
                    let message = salesOrderMovedToInvoicingEmailTemplate({
                      user: approver,
                      requestName: requests[0]?.name,
                      baseUrl: BASE_URL,
                    });
      
                    message = message.replace('[emailContent]', email_content);
                    message = message.replace('[CONTENT]', welcome);
                    message = message.replace('[LOGIN_URL]', `${BASE_URL}`);
      
                    const mailOptions = {
                      to: approver.email,
                      from: '"SignWise Solutions" <noreply@signwisesolutions.com>',
                      subject,
                      text: subject,
                      html: message,
                    };
      
                    try {
                      await transporter.sendMail(mailOptions);
                      console.log(`✅ Invoicing email sent to: ${approver.email}`);
                    } catch (err) {
                      console.error(`❌ Error Invoicing email:`, err);
                    }
                  }
      
                  if (approver?.pcb_final_invoice === 1 && approver?.pcb_final_invoice_sms === 1 && approver?.smsEnabled === 1 && approver?.phone) {
                    const smsContent = 
                  `✅ Sales Order Moved to Invoicing\n` +
                  `📄 Order: "${requests[0]?.name}"\n` +
                  `🔗 View: ${BASE_URL}\n` +
                  `— SignWise`;
      
                    const recipientPhone = approver.phone || TWILIO_PHONE;
                    const Phone_country_code = approver.phone_country_code || '';
      
                    try {
                      await sendMessageToPhoneNumber(recipientPhone, smsContent,Phone_country_code);
                      console.log(`✅ Final invoice SMS sent to ${approver.name || 'User'} (${recipientPhone})`);
                    } catch (err) {
                      console.error(`❌ Failed to send invoice SMS:`, err);
                    }
                  }
                }
              }
            }
          }
        } catch (error) {
          console.error("Error in background processing:", error);
        }
      });
    } catch (error) {
      console.log("error", error);
      res.send({ message: "server error", status: 0 });
    }
  };

  const convertSingleJobToInstallationSplitBuildOrder = async (req, res) => {
    try {
      const { selectedIds, userId, completeStatus, customer_order_product_id, isProduct } = req.body;

      // This endpoint is meant to convert ONLY ONE selected product (customer_order_products.id) to installation
      if (!selectedIds || !customer_order_product_id) {
        return res.send({ status: 0, message: "selectedIds and customer_order_product_id are required" });
      }

      const user_Id = userId;
      const ids = Array.isArray(selectedIds) ? selectedIds : [selectedIds];

      let createdInstallations = [];
      let project = null;

      for (const id of ids) {
        console.log('convertsingle==idsssssssssssssssss',id)
        project = await Project.findProjectById(id, false);
        console.log('convertsingle==projectsssssssssssssssss',project)
        if (!project) continue;

        const products = await Installation.getProducts(project.order_id);
        const allServices = await Installation.getServices(project.request_id);
        console.log('convertsingle==productsssssssssssssssss',products)
        let selectedProduct = null;
        if(isProduct){
          selectedProduct = products?.find(
            (p) => Number(p.id) === Number(customer_order_product_id)
          );
        }else{
          selectedProduct = allServices?.find(
            (s) => Number(s.id) === Number(customer_order_product_id)
          );
        }
        // const selectedProduct = products?.find(
        //   (p) => Number(p.id) === Number(customer_order_product_id)
        // );
        console.log('convertsingle==selectedProductsssssssssssssssss',selectedProduct)

        if (!selectedProduct) {
          continue;
        }
        let locations = [];
        if(isProduct){
          locations = (await Installation.getLocations(selectedProduct.id, selectedProduct.product_id)) || [];
        }else{
          locations = (await Installation.getServiceLocations(selectedProduct.id, project?.request_id)) || [];
        }
        if (!locations.length) {
              continue;
            }
        console.log('convertsingle==locationssssssssssssssssss',locations)
        for (const loc of locations) {
          const payload = {
            ...selectedProduct,
            address: loc.address,
            city: loc.city,
            state: loc.state,
            zipcode: loc.zip,
            name: project.name,
            project_id: project?.id,
            request_id: project?.request_id,
            product_id: selectedProduct?.product_id || null,
            labour_cost_service_id: selectedProduct?.labour_cost_service_id || null,
            product_index: loc?.product_index || 0,
            location_id: loc?.id || null,
            installation_date: project?.installation_date || null,
            installation_start_date: project.installation_start_date || null,
            installation_end_date: project.installation_end_date || null,
            source: selectedProduct?.source || 1,
            due_date: project.installation_date,
            order_information: project?.order_information || 1,
                  added_by: user_Id,
                  timestamp: moment().unix(),
                status: 1,
            // prioritize user choice from popup, fallback to product delivery_type_id, then Installs
            complete_status: Number(completeStatus) || selectedProduct.delivery_type_id || 1,
            description: (project.description || "").replace(/\r?\n/g, "\n"),
            notes: (project.notes || "").replace(/\r?\n/g, "\n"),
            description_lines: [],
            notes_lines: [],
            location_quantity: loc?.location_quantity > 0 ? loc.location_quantity : 1,
            route_id: project?.map_service_id || null,
          };

          console.log('convertsingle==payloadsssssssssssssssss',payload)
          const installationResult = await Installation.addInstallationAppointment(payload);
          if (installationResult) {
            createdInstallations.push(installationResult);
          }
        }
      }

      if (!createdInstallations.length) {
        return res.send({ status: 0, message: "No installation created for the selected product" });
      }

      // Check if all products and services are now converted to installations
      const allProducts = await Installation.getProducts(project.order_id);
      const allServices = await Installation.getServices(project.request_id);
      const allInstallations = await Installation.getInstallationsByProjectId(project.id);
      console.log('updatinggg === allInstallations', allInstallations)

      // Products: check if every product has at least one installation
      const installedProductIds = [...new Set(allInstallations?.map(inst => inst.product_id).filter(Boolean))];
      const allProductsInstalled = allProducts?.every(product =>
        installedProductIds.includes(product.product_id)
      ) ?? true;

      // Services: check if every service has at least one installation (uses labour_cost_service_id)
      // If no services in allServices, treat as all installed (true)
      const installedServiceIds = [...new Set(allInstallations?.map(inst => inst.labour_cost_service_id).filter(Boolean))];
      const allServicesInstalled = allServices?.every(service =>
        installedServiceIds.includes(service.labour_cost_service_id)
      ) ?? true;

      console.log('updatinggg === installedProductIds', installedProductIds, 'installedServiceIds', installedServiceIds)
      console.log('updatinggg === allProductsInstalled', allProductsInstalled, 'allServicesInstalled', allServicesInstalled)

      // If all products AND all services are installed, update project status to 3 (completed)
      if (allProductsInstalled && allServicesInstalled) {
        let projData = { status: 3, completion: 100 };
        let taskData = { status: 3, complete: 100 };
        const projeId = project?.id
        if(projeId){
          const updated = await Project.updateProject(projeId, projData);
          console.log('updatinggg === updated', updated)
          const updateAllTask = await ProjectTask.updateProjectTaskByProjectId(taskData, projeId);
          console.log('updatinggg === updateAllTask', updateAllTask)
          const updateAllSubtask = await ProjectTask.updateProjectSubTaskByProjectId(taskData, projeId);
          console.log('updatinggg === updateAllSubtask', updateAllSubtask)
          try {
            const targetFacilityId = project?.origin_facility_id || null;
            const originRequestId = project?.request_id || null;
            const isSplitOrder = project?.is_split_order || null;
            const project_category = project?.project_category == 15 ? true : false;
            const forParentFacility = project?.for_parent_facility == 1 ? true : false;
            if (isSplitOrder && originRequestId && targetFacilityId && project_category && forParentFacility) {
              const customerProducts = await CustomerOrderProduct.getCustomerOrderProductsbyRequestId(originRequestId);
              console.log('customerProducts----', customerProducts);

              // Check installer_facility_id from customer products (all have same installer_facility_id)
              const minPaymentStatus = customerProducts?.length > 0 && customerProducts[0]?.installer_facility_id != FACILITY_ID ? 1 : 0;
              const updateOriginFacilityStatus =
                await SplitManagementModel.updateOriginFacilityRequestStatus(
                  originRequestId,        // originRequestId in target DB
                  targetFacilityId, // which installation DB to update
                  {
                    status: 4,
                    split_mirror_status: completeStatus,
                    timestamp: moment().unix(),
                    min_payment_status: minPaymentStatus
                  }
                );
                if(updateOriginFacilityStatus){
                  // Also update the local request with min_payment_status = 0
                  const updateRequest = await Request.updateRequets(project.request_id, { min_payment_status: minPaymentStatus });
                  console.log('updateRequest (installation completion)', updateRequest)
                }
              console.log('updateOriginFacilityRequestStatus (installation completion)', updateOriginFacilityStatus);
            }
          } catch (error) {
            console.log('error updateOriginFacilityRequestStatus (installation completion)', error)
          }
        }
        }

      return res.send({
        status: 1,
        message: "success",
        result: project,
        installations: createdInstallations,
      });
    } catch (error) {
      console.log("error", error);
      res.send({ message: "server error", status: 0 });
    }
  };

  /////////////////////////////////
  const createQuickBooksInventoryAdjustment = async ({
    itemId,
    qtyDiff,
    productName = "",
    txnDate = new Date().toISOString().split("T")[0],
  }) => {
    try {
      const token = await getNewAccessToken();
      let accountRefId = await findAccountIdByAcctNum(10134000);
      const apiUrl = PRODUCTION
        ? `https://quickbooks.api.intuit.com/v3/company/${realmId}`
        : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}`;
  
      if (!itemId) {
        console.error("Item ID is required for inventory adjustment.");
        return null;
      }
  
      if (!accountRefId) {
        console.error("Adjust account id is required for inventory adjustment.");
        return null;
      }
  
      if (Number(qtyDiff) === 0) {
        console.log("QtyDiff is 0, no inventory adjustment created.");
        return null;
      }
     
  
      const payload = {
        AdjustAccountRef: {
          value: String(accountRefId),
        },
        TxnDate: txnDate,
        PrivateNote: `${productName || "Item"} - Quantity adjustment`,
        Line: [
          {
            Description: productName || "",
            DetailType: "ItemAdjustmentLineDetail",
            ItemAdjustmentLineDetail: {
              ItemRef: {
                value: String(itemId),
              },
              QtyDiff: Number(qtyDiff),
            },
          },
        ],
      };
  
      console.log("Creating inventory adjustment payload:", payload);
  
      const response = await axios.post(
        `${apiUrl}/inventoryadjustment?minorversion=63`,
        payload,
        {
          headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json",
            Accept: "application/json",
          },
        }
      );
  
      console.log("Inventory adjustment created successfully:", response.data);
      return response.data;
    } catch (error) {
      if (error.response?.data) {
        console.error(
          "Error creating inventory adjustment:",
          JSON.stringify(error.response.data, null, 2)
        );
  
        error.response.data.Fault?.Error?.forEach((err) => {
          console.error(`Validation Error: ${err.Message}, Code: ${err.code}`);
        });
      } else {
        console.error("Error creating inventory adjustment:", error.message);
      }
      return null;
    }
  };

const convertJobToBuildOrderComplete = async (req, res) => {
  try {
    const { selectedIds, userType, userId, status, request, completeStatus, clientId } = req.body;
    const ids = Array.isArray(selectedIds) ? selectedIds : [selectedIds];
    let currentDate = moment().unix();
    let movedToInvoicing = 0;
    let result = {};
    let productOrServiceData = [];

    for (let id of ids) {
      result = await Project.findProjectById(id, request);

      const allCreatedTasks = await ProjectTask.getAllProjectTasks(result.id, 1, 1);

      // ✅ Fetch products
      let productData = await Installation.getProductsBuildOrder(result.order_id);
      productOrServiceData = [...productData];

      for (let product of productData) {
        console.log('productsssssssssssssssss',product)
        let locationData = await Installation.getLocations(product.id, product.product_id);
        product.locationdata = locationData || [];

        let totalQtyToAdd = 0;

        for (let loc of product.locationdata) {
          const productQty = parseFloat(product.product_qty || 0);
          const locationQty = parseFloat(loc.location_quantity || 0);
          totalQtyToAdd += productQty * locationQty;
        }

        // ✅ Add to in_stock_no (even if it's 0 or null)
        const currentStock = parseFloat(product.in_stock_no || 0);
        const updatedStock = currentStock + totalQtyToAdd;

        const id = crypto.randomBytes(6).readUIntLE(0, 6);
        const barcode = String(id).padStart(14, "0");
        const addData = {
          barcode: product.meterial !==1 ? "C" + barcode : "SW" + barcode,
          material_id: product.product_id,
          unit_cost: product.actual_retail_price,
          actual_qty: totalQtyToAdd,
          qty: totalQtyToAdd,
          actual_unit_qty: totalQtyToAdd,
          unit_qty: totalQtyToAdd,
          actual_total_cost: product.actual_retail_price * totalQtyToAdd,
          total_cost: product.actual_retail_price * totalQtyToAdd,
          status: 1,
          added_by: userId,
          timestamp: currentDate,
          source:0
        };
        if(product.meterial !==1 ){
          const result = await Product.addFinishedProduct(addData);

          const adjustmentResult = await createQuickBooksInventoryAdjustment({
            itemId: product.quickbookId,
            qtyDiff : Number(totalQtyToAdd),
            productName: product.product_name,
          });

          let message = `A new Finished Product has been added through build order ${result.name}.`;

          await Product.addClientStockLog({
            catalog_id: product.product_id,
            catalog_log_message: message,
            timestamp: currentDate,
            status: 1,
            catalog_source: 2, 
            added_by: userId,
          });

        }

        await Product.updateProduct(product.product_id, {
          in_stock_no: updatedStock
        });

        if (product?.product_id && updatedStock) {
          const previousStock = parseFloat(product.in_stock_no || 0);
          const addedStock = totalQtyToAdd;

          const logData = {
            catalog_source: 3, // 3 = Completed Job
            catalog_id: product.product_id,
            added_by: userId,
            timestamp: currentDate,
            status: 1,
            catalog_log_message: `#${addedStock} stock(s) added to "${product.product_name}" via Completed Job (Previous: ${previousStock}, New Total: ${updatedStock})`
          };

          // await Product.addClientStockLog(logData); // model call
        }

      }

      // ✅ Mark project and tasks as completed
      const projData = { status: 3, completion: 100, change_order:0 };
      const taskData = { status: 3, complete: 100 };
      const projectId = result.id;

      if (projectId) {
        await Project.updateProject(projectId, projData);
        await ProjectTask.updateProjectTaskByProjectId(taskData, projectId);
        await ProjectTask.updateProjectSubTaskByProjectId(taskData, projectId);
      }

      // if (allCreatedTasks?.length <= 0) {
        // movedToInvoicing = 1;

        await Project.updateProject(result.id, { noServiceNoTask: 0 ,change_order:0 });
        // await Request.updateRequestById(result.request_id, { noServiceNoTask: 0, installation_acceptance: 1 });
        await Request.updateRequestById(result.request_id, { noServiceNoTask: 0});

        const notificationMsg = `Build Order "${result.name}" has been completed.`;
        const notificationUrl = "official-request";

        await Admin.incrementField(userId, "noti_count", 1);
        await Admin.addNotification({
          user_id: userId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        });

        const adminIds = await Admin.getAllAdminIds();
        for (const adminId of adminIds) {
          if (adminId != userId) {
            await Admin.incrementField(adminId, "noti_count", 1);
            await Admin.addNotification({
              user_id: adminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            });
          }
        // }
      }
    }

    // ✅ Send invoicing email if moved
    if (movedToInvoicing === 1) {
      for (let id of ids) {
        let requests = await Request.getRequestById(id);
        if (requests) {
          const clientUser = await Client.getClientById(clientId);
          const selectedClientId = clientUser?.user_id || null;
          const adminMangerIds = await Admin.getAllAdminAndManagerUserIds();
          const allUsersToCheck = [...new Set([userId, selectedClientId, ...adminMangerIds].filter(Boolean))];

          for (const userIdToCheck of allUsersToCheck) {
            const approver = await Admin.getUserNotificationAndPermissionSettings(userIdToCheck);
            if (!approver) continue;

            if (approver?.emailEnabled === 1 && approver?.pcb_final_invoice === 1 && approver?.pcb_final_invoice_email === 1 && approver?.email) {
              const subject = `✅ Sales Order Moved to Invoicing: ${requests[0]?.name}`;
              const welcome = `Hello ${approver.name},`;
              const email_content = `The sales order "${requests[0]?.name}" has been moved to the invoicing stage. You can now proceed with generating the invoice or reviewing the order details.`;

              let message = salesOrderMovedToInvoicingEmailTemplate({
                user: approver,
                requestName: requests[0]?.name,
                baseUrl: BASE_URL,
              });

              message = message.replace('[emailContent]', email_content);
              message = message.replace('[CONTENT]', welcome);
              message = message.replace('[LOGIN_URL]', `${BASE_URL}`);

              const mailOptions = {
                to: approver.email,
                from: '"SignWise Solutions" <noreply@signwisesolutions.com>',
                subject,
                text: subject,
                html: message,
              };

              try {
                await transporter.sendMail(mailOptions);
                console.log(`✅ Invoicing email sent to: ${approver.email}`);
              } catch (err) {
                console.error(`❌ Error Invoicing email:`, err);
              }
            }

            if (approver?.pcb_final_invoice === 1 && approver?.pcb_final_invoice_sms === 1 && approver?.smsEnabled === 1 && approver?.phone) {
              const smsContent =
                `✅ Sales Order Moved to Invoicing\n` +
                `📄 Order: "${requests[0]?.name}"\n` +
                `🔗 View: ${BASE_URL}\n` +
                `— SignWise`;

              const recipientPhone = approver.phone || TWILIO_PHONE;
              const Phone_country_code = approver.phone_country_code || '';

              try {
                await sendMessageToPhoneNumber(recipientPhone, smsContent, Phone_country_code);
                console.log(`✅ Final invoice SMS sent to ${approver.name || 'User'} (${recipientPhone})`);
              } catch (err) {
                console.error(`❌ Failed to send invoice SMS:`, err);
              }
            }
          }
        }
      }
    }

    res.send({ message: "success", status: 1, productOrServiceData, result, movedToInvoicing });
  } catch (error) {
    console.log("error", error);
    res.send({ message: "server error", status: 0 });
  }
};

  const convertJobToNoChargeComplete = async (req, res) => {
  try {
    const { selectedIds, userType, userId, status, request, completeStatus, clientId, stockData } = req.body;
    const ids = Array.isArray(selectedIds) ? selectedIds : [selectedIds];
    let currentDate = moment().unix();
    let result = {};
    let productOrServiceData = [];

    for (let id of ids) {
      result = await Project.findProjectById(id, request);

      // Check if project category is 13 (no charge)
      if (result.project_category !== 13) {
        continue; // Skip projects that are not no charge category
      }

      const allCreatedTasks = await ProjectTask.getAllProjectTasks(result.id, 1, 1);

      // ✅ Fetch products for no charge projects
      let productData = await Installation.getProductsNoChargeOrder(result.order_id);
      productOrServiceData = [...productData];

      for (let product of productData) {
        console.log('No charge product:', product);
        
        // Only process products with isTrafficCatalog = 0 and inhouse != 1
        if (product.isTrafficCatalog ===0 && product.inhouse === 1) {
          continue; // Skip products that don't meet criteria
        }

        let locationData = await Installation.getLocations(product.id, product.product_id);
        product.locationdata = locationData || [];

        let totalQtyToAdd = 0;

        for (let loc of product.locationdata) {
          const productQty = parseFloat(product.product_qty || 0);
          const locationQty = parseFloat(loc.location_quantity || 0);
          totalQtyToAdd += productQty * locationQty;
        }

        // ✅ Add to in_stock_no (even if it's 0 or null)
        const currentStock = parseFloat(product.in_stock_no || 0);
        const updatedStock = currentStock + totalQtyToAdd;

        // Check if frontend provided stock data for this product
        const stockInfo = stockData?.find(item => item.productId === product.product_id);
        
        if (stockInfo && stockInfo.selection === 'add_to_existing_stock' && stockInfo.finishedProductId) {
          // Handle existing stock - update the selected finished product
          console.log('Updating existing finished product:', stockInfo.finishedProductId);
          
          // Get current finished product data
          const existingFinishedProduct = await Product.getFinishedProductById(stockInfo.finishedProductId);
          
          if (existingFinishedProduct && existingFinishedProduct.length > 0) {
            const currentQty = parseFloat(existingFinishedProduct[0].qty || 0);
            const newQty = currentQty + totalQtyToAdd;
            
            // Update the finished product quantity
            const updateData = {
              qty: newQty,
              actual_qty: newQty,
              actual_unit_qty: newQty,
              unit_qty: newQty,
              actual_total_cost: existingFinishedProduct[0].unit_cost * newQty,
              total_cost: existingFinishedProduct[0].unit_cost * newQty,
              timestamp: currentDate
            };
            
            await Product.updateFinishedProduct(stockInfo.finishedProductId, updateData);
            
            // Log the update
            let message = `Finished Product quantity updated through no charge order ${result.name}. Quantity increased by ${totalQtyToAdd} (Previous: ${currentQty}, New Total: ${newQty}).`;
            
            await Product.addClientStockLog({
              catalog_id: product.product_id,
              catalog_log_message: message,
              timestamp: currentDate,
              status: 1,
              catalog_source: 2, // 2 = No Charge Order
              added_by: userId,
            });
          } else {
            console.log('Finished product not found, falling back to new stock creation');
            // Fallback to creating new stock if finished product not found
            await createNewFinishedProduct(product, totalQtyToAdd, userId, currentDate, result);
          }
        } else {
          // Handle new stock - create new finished product (existing functionality)
          console.log('Creating new finished product');
          await createNewFinishedProduct(product, totalQtyToAdd, userId, currentDate, result);
        }

        await Product.updateProduct(product.product_id, {
          in_stock_no: updatedStock
        });

        if (product?.product_id && updatedStock) {
          const previousStock = parseFloat(product.in_stock_no || 0);
          const addedStock = totalQtyToAdd;

          const logData = {
            catalog_source: 3, // 3 = Completed Job
            catalog_id: product.product_id,
            added_by: userId,
            timestamp: currentDate,
            status: 1,
            catalog_log_message: `#${addedStock} stock(s) added to "${product.product_name}" via No Charge Job Completion (Previous: ${previousStock}, New Total: ${updatedStock})`
          };

          await Product.addClientStockLog(logData);
        }
      }

      // ✅ Mark project and tasks as completed
      const projData = { status: 3, completion: 100, change_order:0 };
      const taskData = { status: 3, complete: 100 };
      const projectId = result.id;

      if (projectId) {
        await Project.updateProject(projectId, projData);
        await ProjectTask.updateProjectTaskByProjectId(taskData, projectId);
        await ProjectTask.updateProjectSubTaskByProjectId(taskData, projectId);
      }

      await Project.updateProject(result.id, { noServiceNoTask: 0 ,change_order:0 });
      // Set installation_acceptance = 0 for no charge projects
      await Request.updateRequestById(result.request_id, { 
        noServiceNoTask: 0, 
      });

      const notificationMsg = `No Charge Order "${result.name}" has been completed.`;
      const notificationUrl = "official-request";

      await Admin.incrementField(userId, "noti_count", 1);
      await Admin.addNotification({
        user_id: userId,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: userId,
      });

      const adminIds = await Admin.getAllAdminIds();
      for (const adminId of adminIds) {
        if (adminId != userId) {
          await Admin.incrementField(adminId, "noti_count", 1);
          await Admin.addNotification({
            user_id: adminId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          });
        }
      }
    }

    res.send({ message: "success", status: 1, productOrServiceData, result });
  } catch (error) {
    console.log("error", error);
    res.send({ message: "server error", status: 0 });
  }
};


// const updateInstallationsAssignToDriver = async (req,res) =>{
//   try {
//     const {instId,selectTemplate,selectedValues,isDriver,selectedDriver,userId}= req.body
// let currentDate = Math.round(moment().valueOf() / 1000);
// console.log('dfdsifisdbfibsidbf',req.body)

// let driverId = isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null


//     let installationData =[]
//     for (let id of instId) {
//       const getinstallationData = await Installation.findInstallationDataById(id)
//       console.log('installationDatainstallationData',getinstallationData)
//       installationData.push(getinstallationData)
//     }

//     let data={}
//     data['name'] = `route ${currentDate}`
//     data['zipcodes'] = installationData.map(data => data?.zipcode).join(', ');
//     data['assigned_driver'] = null
//     data['timestamp'] = currentDate
//     data['added_by'] = userId
//     data['status'] = 1
//     const randomBytes = crypto.randomBytes(2).toString('hex');
//     const u_id = parseInt(randomBytes, 16) % 90000 + 10000;
//     data['unique_id'] = 'SWS'+u_id      
//     let routeId = await Route.createRoute(data)


// for (let id of instId) {

//     const installationTableData = {
//       installation_temp_id :selectTemplate.id,
//       // status : (routeId) ? 6 : 1,
//       status : (routeId) ? 2 : 1,
//       team_id : selectedValues?.user_id||selectedValues.map(driver => driver.user_id).join(","),
//       driver_is_installer : isDriver ? 2 : 1,
//       driver_id : isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null,
//       route_id : routeId || null
//     }
//  const updateInstallation = await Installation.updateInstallationDataById(id,installationTableData)

// if(updateInstallation,id){
// // const installationDataaaa = await Installation.fetchApointmentById(id)
// const installationDataaaa = await Installation.fetchDetailsForNotification(id,driverId)
// //  return res.send(installationDataaaa)
//         let notificationMsg=`A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to ${installationDataaaa[0]?.driver_name}`
//         let mobileNotification=`A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to you`
        
//         let currentDate = Math.round(moment().valueOf() / 1000);

//     let notificationUrl = "installation";
//         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 );

//               if(installationDataaaa[0]?.fcmToken){
//           const message = {
//             data: {
//                 // Your custom data payload if needed
//                 // Example:
//                 score: '850',
//                 time: '2:45'
//             },
//             notification: {
//                 title: 'Installation',
//                 body: mobileNotification || `Installation status has been updated.`
//             },
//             token: installationDataaaa[0].fcmToken 
//           };

//              admin.messaging().send(message)
//               .then((response) => {
//               console.log('Successfully sent message:', response);
//             // Assuming 'res' is used to respond to an HTTP request
//               res.send({ success: true, response });
//               })
//               .catch((error) => {
//                 console.error('Error sending message:', error);
//             res.status(500).send({ error: error.message });
//           })
        

// }}

//   }


//     let updatedRouteData ={
//       assigned_driver : isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null,
//     }
//   let updataRouteData = await Route.updateRoute(updatedRouteData,routeId)

//     res.send({message:"success",status:1})
//   } catch (error) {
//     res.send({message:error.message,status:0})
//   }
// }

const getAllInstallsTabCount = async (req, res) => {
  try {
    let userId = req.body.userId
    
    let data = await Installation.getInstallCountByUser(userId);
      res.send({
      status: 1,
      data: data,
      message: 'Installs count fetched successful'
    })
  } catch (error) {
    console.log(error)
    res.send({ status: 0, message: 'Failed to fetch install tab counts' });
  }
}

const getAllPickupTabCount = async (req, res) => {
  try {
    let userId = req.body.userId
    
    let data = await Installation.getPickupTabCountByUser(userId);
      res.send({
      status: 1,
      data: data,
      message: 'Pickup count fetched successful'
    })
  } catch (error) {
    console.log(error)
    res.send({ status: 0, message: 'Failed to fetch Pickup tab counts' });
  }
}
const getAllShippingTabCount = async (req, res) => {
  try {
    let userId = req.body.userId
    
    let data = await Installation.getShippingTabCountByUser(userId);
      res.send({
      status: 1,
      data: data,
      message: 'Shipping count fetched successful'
    })
  } catch (error) {
    console.log(error)
    res.send({ status: 0, message: 'Failed to fetch Shipping tab counts' });
  }
}

const updateInstallationsAssignToDriver = async (req, res) => {
  try {
    const { instId, selectTemplate, selectedValues, isDriver, selectedDriver, userId, userType, socketId ,vehicleId} = req.body;
    console.log('selectedValuesselectedValues', selectedValues)
    
    let currentDate = Math.round(moment().valueOf() / 1000);
    console.log('Received body:', req.body);

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_assignment_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-ASSIGNMENT-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-ASSIGNMENT-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-ASSIGNMENT-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_assignment_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-ASSIGNMENT-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-ASSIGNMENT-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-ASSIGNMENT-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-ASSIGNMENT-PROGRESS] 🚀 Starting installation assignment for user:`, userId);
    emitProgress('start', `Initializing installation assignment...`, 5);

    // Ensure selectedValues and selectedDriver are arrays
    const selectedValuesArray = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
    const selectedDriverArray = Array.isArray(selectedDriver) ? selectedDriver : [selectedDriver];

    emitProgress('processing_drivers', `Processing driver assignments...`, 15);

    let driverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

    emitProgress('fetching_installations', `Fetching installation data...`, 25);

    // let installationData = [];
    // for (let id of instId) {
    //   const getinstallationData = await Installation.findInstallationDataById(id);
    //   console.log('Installation Data:', getinstallationData);
    //   installationData.push(getinstallationData);
    //   console.log('Installation Dataaa:', installationData[0].request_id);
    // }
    const installationPromises = instId.map(id => Installation.findInstallationDataById(id));
    const installationData = await Promise.all(installationPromises);
    const requestId = installationData[0]?.request_id
    const routeId = await Routes.getRouteDatabyRequestId(requestId);

    emitProgress('updating_installations', `Updating installation assignments...`, 40);
    
    // ✅ OPTIMIZATION: Collect notification data for async processing
    const notificationDataArray = [];

    for (let i = 0; i < instId.length; i++) {
      const id = instId[i];
      const progressPercent = 40 + (i / instId.length) * 30; // 40-70% for installation updates
      
      emitProgress(`updating_installation_${i + 1}`, `Updating installation ${i + 1} of ${instId.length}...`, Math.round(progressPercent));
      
      const installationTableData = {
        installation_temp_id: selectTemplate.id,
        status: routeId ? 2 : 1,
        team_id: selectedValuesArray.map(driver => driver.user_id).join(","),
        driver_is_installer: isDriver ? 2 : 1,
        driver_id: driverId,
        route_id: routeId || null,
        vehicle_id: vehicleId || null,
      };

      const updateInstallation = await Installation.updateInstallationDataById(id, installationTableData);

      if (updateInstallation) {
        const installationById = await Installation.findInstallationById(id);
        const clientId = installationById?.customer_id;
        
        // ✅ OPTIMIZATION: Collect data for async processing instead of processing immediately
        let allDriverId = isDriver
          ? selectedValuesArray.map(driver => driver.id).join(",")
          : selectedDriverArray.map(driver => driver.id).join(",") || null;

        const driverIds = allDriverId.split(",").map(s => s.trim()).filter(Boolean).map(Number); 

        let installationDataaaa = [];
        let notificationMsg = ``;
        let mobileNotification = ``;
        const driverNames = new Set(); 
        let installationName = "";  
        let notificationTokens = [];

        const productInstallation = await Installation.fetchApointmentById(id);
        let installationProductName = productInstallation[0]?.product_name || productInstallation[0]?.service_name;
        
        for (const driverIdItem of driverIds) {
          installationDataaaa = await Installation.fetchDetailsForNotification(id, driverIdItem);
          installationName = installationDataaaa[0].installation_name || installationName;
          driverNames.add(installationDataaaa[0].driver_name);
          
          notificationMsg = `A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to ${installationDataaaa[0]?.driver_name}`;
          mobileNotification = `A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to you`;
        }
        
        notificationMsg = `A new Installation ${installationName} has been assigned to ${[...driverNames].join(", ")}`;

        if (installationDataaaa[0]?.fcmToken) {
          notificationTokens.push(installationDataaaa[0]?.fcmToken);
        }
        if (installationDataaaa[0]?.installerFcmToken) {
          notificationTokens.push(installationDataaaa[0]?.installerFcmToken);
        }

        // Store notification data for async processing
        notificationDataArray.push({
          installationId: id,
          installationById,
          clientId,
          notificationMsg,
          mobileNotification,
          installationProductName,
          installationName,
          driverNames: [...driverNames],
          notificationTokens,
          previousStatus: installationData[0]?.status,
          requestId: installationById.request_id
        });
      }
    }

    emitProgress('updating_route', `Updating route information...`, 90);
    
    let updatedRouteData = {
      assigned_driver: driverId,
      zipcodes : installationData?.map(data => data?.zipcode).join(', ') || '',
      assigned : 1,
    };
    await Route.updateRoute(updatedRouteData, routeId);
    
    // ✅ OPTIMIZATION: Send response immediately after critical operations
    emitProgress('complete', `Installation assignment completed successfully!`, 100);
    console.log('routeIdData checking' );
    res.send({ message: "success", status: 1 });

    // ✅ OPTIMIZATION: Handle all notifications/activity logs/tab counts/FCM async (non-blocking)
    const handleNotificationsAsync = async () => {
      try {
        for (const notificationData of notificationDataArray) {
          const {
            installationId,
            installationById,
            clientId,
            notificationMsg,
            mobileNotification,
            installationProductName,
            installationName,
            driverNames,
            notificationTokens,
            previousStatus,
            requestId
          } = notificationData;

          let currentDate = Math.round(moment().valueOf() / 1000);
          let notificationUrl = "installation";
          
          // User notification
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          await Admin.addNotification(notificationData_user);

          // Request activity log
          await RequestUpdates.addRequestUpdates({
            request_id: requestId,
            activity: `A new Installation "${installationProductName || installationName}" has been assigned to ${driverNames.join(", ")}`,
            partner_id: 0,
            added_by: userId,
            timestamp: currentDate,
          });
          
          // Admin notifications (parallelized)
          let adminIds = await Admin.getAllAdminIds();
          const adminNotificationPromises = adminIds
            .filter(eachadminIds => eachadminIds != userId)
            .map(async (eachadminIds) => {
              try {
                await Admin.incrementField(eachadminIds, 'noti_count', 1);
                let addNotification = {
                  user_id: eachadminIds,
                  url: notificationUrl,
                  timestamp: currentDate,
                  message: notificationMsg,
                  status: 1,
                  from_id: userId,
                };
                await Admin.addNotification(addNotification);
              } catch (err) {
                console.error(`❌ Error sending notification to admin ${eachadminIds}:`, err);
              }
            });
          await Promise.all(adminNotificationPromises);
      
          // Tab count updates
          // const projectResult = await Project.findProjectById(installationById?.request_id, true);   
          // const project_members = await Project.getAllMemberUserIdsByProjectId(projectResult?.id);
          // const allUserIds = await Admin.getAllAdminUserIds();
          // const clientUser = await Client.getClientById(clientId);
          // const selectedClientId = clientUser?.user_id || null;
          // let usersToUpdate = [...new Set([selectedClientId, userId, ...project_members, ...allUserIds].filter(Boolean))];

          // const updateCounts = async (userIdToUpdate) => {
          //   try {
          //     if (previousStatus == 1) {
          //       await Installation.installationTabIncrementField(userIdToUpdate, "staged_count", -1, "staged_count_ids", installationId, false);
          //       await Installation.installationTabIncrementField(userIdToUpdate, "installing_count", 1, "installing_count_ids", installationId, true);
          //     }
          //   } catch (err) {
          //     console.error(`❌ Error updating tab count for user ${userIdToUpdate}:`, err);
          //   }
          // };

          // if (usersToUpdate.length > 0) {
          //   await Promise.all(usersToUpdate.map(user => updateCounts(user)));
          // }
          // console.log(`Successfully updated installs count for installation ${installationId}`);

          // FCM push notifications (parallelized)
          const fcmPromises = notificationTokens.map(async (token) => {
            try {
              console.log("notificationTokenstoken", token);
              const message = {
                data: {},
                notification: {
                  title: 'Installation',
                  body: mobileNotification || `Installation status has been updated.`
                },
                android: {
                  notification: {
                    image: `https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e`
                  }
                },
                token
              };

              const response = await admin.messaging().send(message);
              console.log(`Successfully sent message to token ${token}:`, response);
            } catch (error) {
              console.error(`Error sending message to token ${token}:`, error);
              if (error.code === 'messaging/registration-token-not-registered') {
                console.warn(`Invalid FCM token detected: ${token}`);
              }
            }
          });
          await Promise.all(fcmPromises);
        }
      } catch (error) {
        console.error('Error in async notifications handler:', error);
      }
    };

    // ✅ OPTIMIZATION: Run non-critical operations asynchronously (fire and forget)
    handleNotificationsAsync().catch(error => {
      console.error('Error in async operations:', error);
    });
  } catch (error) {
    console.error('Error:', error.message);
    res.status(500).send({ message: error.message, status: 0 });
  }
};


const deleteInstallationById = async (req, res) => {
  try {
    const { instId} = req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    console.log('Received body:', req.body);

    for (let id of instId) {
      const getinstallationData = await Installation.findInstallationDataById(id);
      console.log('getinstallationDatagetinstallationData',getinstallationData)
      if (getinstallationData) {
        const request_id = getinstallationData?.request_id
        const project_id = getinstallationData?.project_id
        try {
          let result = await Request.deleteRequestById(request_id)
            console.log('resultresult',result )
          if(result){
            let installations = await Installation.getInstallationsByProjectId(project_id);
            console.log('installationsinstallations',installations )
            const installationDeleted = await Installation.deleteInstallationUsingProjectId(project_id);
            console.log('installationDeleted',installationDeleted )
            const timelogDeleted = await ProjectTask.deleteStaffTaskTimelogs(project_id);
            console.log('timelogDeleted',timelogDeleted )
            const jobDeleted = await Project.deleteProject(project_id);
            console.log('deleteddddddddddddddddd',jobDeleted)
          }
        } catch (error) {
          console.error('❌ Error during project deletion:', error);
        }
      }
    }
    res.send({ message: "installation deleted", status: 1 });
  } catch (error) {
    console.error('Error:', error.message);
    res.status(500).send({ message: error.message, status: 0 });
  }
};

const updateInstallationspickupshipping = async (req,res) =>{
  try {
    const {instId,userId,complete_status,status,reasons,userType}= req.body
let currentDate = Math.round(moment().valueOf() / 1000);
console.log('dfdsifisdbfibsidbf',req.body)



    let installationData =[]
    for (let id of instId) {
      const getinstallationData = await Installation.findInstallationDataById(id)
      console.log('installationDatainstallationData',getinstallationData)
      installationData.push(getinstallationData)
    }

    let data={}
    data['name'] = `route ${currentDate}`
    data['zipcodes'] = installationData.map(data => data?.zipcode).join(', ');
    data['assigned_driver'] = null
    data['timestamp'] = currentDate
    data['added_by'] = userId
    data['status'] = 1
    const randomBytes = crypto.randomBytes(2).toString('hex');
    const u_id = parseInt(randomBytes, 16) % 90000 + 10000;
    data['unique_id'] = 'SWS'+u_id      
    // let routeId = await Route.createRoute(data)


for (let id of instId) {
let installationTableData={}

    if(status === 2){ 
      installationTableData = {
      status : 5 ,
      cancel_reason :reasons,
      }
    }else{
      installationTableData = {
        status : 4,
        }
    }
 const updateInstallation = await Installation.updateInstallationDataById(id,installationTableData)

  // if (updateInstallation) {
  //   // Fetch installation details
  //   // const installationById = await Installation.findInstallationById(id);
  //   // const clientId = installationById?.customer_id;
  //   // console.log("project_membersssss",installationById?.project_id)
  //   // const projectResult = await Project.findProjectById(installationById?.project_id,false);   
  //   // console.log("project_membersssss 1",projectResult)
  //   // const project_members = await Project.getAllMemberUserIdsByProjectId(projectResult?.id)
  //   // console.log("project_membersssss 2",project_members)
  //   // const allUserIds = await Admin.getAllAdminUserIds();
  //   // const clientUser = await Client.getClientById(clientId);
  //   // const selectedClientId = clientUser?.user_id || null;
  //   // let usersToUpdate = 
  //   //       // ? [...new Set([userId, selectedClientId, ...allUserIds].filter(Boolean))]
  //   //        [...new Set([selectedClientId,userId,...project_members, ...allUserIds].filter(Boolean))];


  //   // Define updateCounts function
  //   // const updateCounts = async (userId) => {
  //   //     if (installationById?.complete_status == 2 && status == 1) {  
  //   //         await Installation.pickupTabIncrementField(userId, "staged_count", -1, "staged_count_ids", id, false);
  //   //         await Installation.pickupTabIncrementField(userId, "completed_count", 1, "completed_count_ids", id, true);
  //   //     }else if (installationById?.complete_status == 3 && status == 1){
  //   //       await Installation.shippingTabIncrementField(userId, "staged_count", -1, "staged_count_ids", id, false);
  //   //       await Installation.shippingTabIncrementField(userId, "completed_count", 1, "completed_count_ids", id, true);
  //   //     }else if (installationById?.complete_status == 3 && status == 2){
  //   //       await Installation.shippingTabIncrementField(userId, "staged_count", -1, "staged_count_ids", id, false);
  //   //       await Installation.shippingTabIncrementField(userId, "returned_count", 1, "returned_ids", id, true);
  //   //     }
  //   // };

  //   // Execute updates for all necessary users
  //   // if (usersToUpdate.length > 0) {
  //   //     await Promise.all(usersToUpdate.map(user => updateCounts(user)));
  //   // }

  //   console.log(`Successfully updated counts for installation: ${id}`);
  // }

// if(updateInstallation,id){
// // const installationDataaaa = await Installation.fetchApointmentById(id)
// // const installationDataaaa = await Installation.fetchDetailsForNotification(id,driverId)
// //  return res.send(installationDataaaa)
//         let notificationMsg=``
//         let mobileNotification=``
//         // let notificationMsg=`A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to ${installationDataaaa[0]?.driver_name}`
//         // let mobileNotification=`A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to you`
        
//         let currentDate = Math.round(moment().valueOf() / 1000);

//     let notificationUrl = "installation";
//         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 );

//               if(installationDataaaa[0]?.fcmToken){
//           const message = {
//             data: {
//                 // Your custom data payload if needed
//                 // Example:
//                 score: '850',
//                 time: '2:45'
//             },
//             notification: {
//                 title: 'Installation',
//                 body: mobileNotification || `Installation status has been updated.`
//             },
//             token: installationDataaaa[0].fcmToken 
//           };

//              admin.messaging().send(message)
//               .then((response) => {
//               console.log('Successfully sent message:', response);
//             // Assuming 'res' is used to respond to an HTTP request
//               res.send({ success: true, response });
//               })
//               .catch((error) => {
//                 console.error('Error sending message:', error);
//             res.status(500).send({ error: error.message });
//           })
        

// }}

  }


  //   let updatedRouteData ={
  //     assigned_driver : isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null,
  //   }
  // let updataRouteData = await Route.updateRoute(updatedRouteData,routeId)

    res.send({message:"success",status:1})
  } catch (error) {
    res.send({message:error.message,status:0})
  }
}


// const reassignInstallationToDriver = async (req,res) =>{
//   try {
//     const {instId,selectTemplate,selectedValues,isDriver,selectedDriver,userId}= req.body
// let currentDate = Math.round(moment().valueOf() / 1000);
// let driverId = isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null

// console.log("dattaaaaaaaaaaaaaaaaaa",req.body)

//     let installationData =[]
//     for (let id of instId) {
//       const getinstallationData = await Installation.findInstallationDataById(id)
//       console.log('installationDatainstallationData',getinstallationData)
//       installationData.push(getinstallationData)
//     }

//     let data={}
//     data['name'] = `route ${currentDate}`
//     data['zipcodes'] = installationData.map(data => data.zipcode).join(', ');
//     data['assigned_driver'] = isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null,
//     data['timestamp'] = currentDate
//     data['added_by'] = userId
//     const randomBytes = crypto.randomBytes(2).toString('hex');
//     const u_id = parseInt(randomBytes, 16) % 90000 + 10000;
//     data['unique_id'] = 'SWS'+u_id      
//     // let routeId = await Route.createRoute(data)
//   let updataRouteData = await Route.updateRoute(data,installationData[0].route_id)



// for (let id of instId) {
//     const installationTableData = {
//       installation_temp_id :selectTemplate.id,
//       // status : (installationData[0].route_id) ? 6 : 1,
//       status:2,
//       team_id : selectedValues?.user_id||selectedValues.map(driver => driver.user_id).join(","),
//       driver_is_installer : isDriver ? 2 : 1,
//       driver_id : isDriver ?selectedValues.map(driver => driver.id).join(",") : selectedDriver.map(driver => driver.id).join(",") || null,
//       route_id : installationData[0].route_id || null
//     }
//  const updateInstallation = await Installation.updateInstallationDataById(id,installationTableData)

//  if(updateInstallation,id){
//   // const installationDataaaa = await Installation.fetchApointmentById(id)
//   const installationDataaaa = await Installation.fetchDetailsForNotification(id,driverId)
   
//           let notificationMsg=`A  Installation ${installationDataaaa[0].installation_name} has been re-assigned to ${installationDataaaa[0].driver_name}`
//           let mobileNotification=`A new Installation ${installationDataaaa[0].installation_name} has been assigned to you`
          
//           let currentDate = Math.round(moment().valueOf() / 1000);
  
//       let notificationUrl = "installation";
//           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 );
  
//                 if(installationDataaaa[0]?.fcmToken){
//             const message = {
//               data: {
//                   // Your custom data payload if needed
//                   // Example:
//                   score: '850',
//                   time: '2:45'
//               },
//               notification: {
//                   title: 'Installation',
//                   body: mobileNotification || `Installation status has been updated.`
//               },
//               token: installationDataaaa[0].fcmToken 
//             };
  
//                admin.messaging().send(message)
//                 .then((response) => {
//                 console.log('Successfully sent message:', response);
//               // Assuming 'res' is used to respond to an HTTP request
//                 res.send({ success: true, response });
//                 })
//                 .catch((error) => {
//                   console.error('Error sending message:', error);
//               res.status(500).send({ error: error.message });
//             })
          
  
//   }}

//   }

//     res.send({message:"success",status:1})
//   } catch (error) {
//     res.send({message:error.message,status:0})
//   }
// }

const reassignInstallationToDriver = async (req,res) =>{
  try {
    const {instId,selectTemplate,selectedValues,isDriver,selectedDriver,userId,userType,socketId,reassign_reason,vehicleId}= req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_reassignment_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_reassignment_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-REASSIGNMENT-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-REASSIGNMENT-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 🚀 Starting installation reassignment for user:`, userId);
    emitProgress('start', `Initializing installation reassignment...`, 5);

    // Ensure selectedValues and selectedDriver are arrays
    const selectedValuesArray = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
    const selectedDriverArray = Array.isArray(selectedDriver) ? selectedDriver : [selectedDriver];

    emitProgress('processing_drivers', `Processing driver reassignment...`, 15);

    let driverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

    emitProgress('fetching_installations', `Fetching installation data...`, 25);

    let installationData = [];
    for (let id of instId) {
      const getinstallationData = await Installation.findInstallationDataById(id);
      console.log('installationDatainstallationData', getinstallationData);
      installationData.push(getinstallationData);
    }

    emitProgress('updating_route', `Updating route information...`, 40);

    let data = {};
    data['name'] = `route ${currentDate}`;
    data['zipcodes'] = installationData.map(data => data.zipcode).join(', ');
    data['assigned_driver'] = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;
    data['timestamp'] = currentDate;
    data['added_by'] = userId;
    const randomBytes = crypto.randomBytes(2).toString('hex');
    const u_id = parseInt(randomBytes, 16) % 90000 + 10000;
    data['unique_id'] = 'SWS' + u_id;
    data['assigned_sales_order'] = installationData[0]?.request_id;
    data['assigned'] = 1;
    if (reassign_reason != null && reassign_reason !== '') {
      data['reassign_reason'] = reassign_reason;
    }
    // let routeId = await Route.createRoute(data);
    let updataRouteData = await Route.updateRoute(data, installationData[0].route_id);

    emitProgress('updating_installations', `Updating installation assignments...`, 50);

    for (let i = 0; i < instId.length; i++) {
      const id = instId[i];
      const progressPercent = 50 + (i / instId.length) * 30; // 50-80% for installation updates
      
      emitProgress(`updating_installation_${i + 1}`, `Updating installation ${i + 1} of ${instId.length}...`, Math.round(progressPercent));
      
      const installationTableData = {
        installation_temp_id: selectTemplate.id,
        status: 2,
        team_id: selectedValuesArray.map(driver => driver.user_id).join(","),
        driver_is_installer: isDriver ? 2 : 1,
        driver_id: driverId,
        route_id: installationData[0].route_id || null,
        vehicle_id: vehicleId || null,
      };
      if (reassign_reason != null && reassign_reason !== '') {
        installationTableData['reassign_reason'] = reassign_reason;
      }
      const updateInstallation = await Installation.updateInstallationDataById(id, installationTableData);

      if (updateInstallation) {
        emitProgress(`processing_notifications_${i + 1}`, `Processing notifications for installation ${i + 1}...`, Math.round(80 + (i / instId.length) * 10));
        
        let allDriverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

      const driverIds = allDriverId.split(",").map(s => s.trim()).filter(Boolean).map(Number);        

       const notificationTokens = [];
       let installationDataaaa = []
        let notificationMsg =``
        let mobileNotification =``
        const driverNames        = new Set(); 
        let   installationName   = "";  
      const installationData = await Installation.fetchApointmentById(id)
      let installationProductName  = installationData[0]?.product_name || installationData[0]?.service_name;
      for (const driverId of driverIds) {
         installationDataaaa = await Installation.fetchDetailsForNotification(id, driverId);

       installationName = installationDataaaa[0].installation_name || installationName;
       driverNames.add(installationDataaaa[0].driver_name);
         
         notificationMsg = `A Installation ${installationDataaaa[0]?.installation_name} has been re-assigned to ${installationDataaaa[0]?.driver_name}`;
         mobileNotification = `A new Installation ${installationDataaaa[0]?.installation_name} has been assigned to you`;

       
              if (installationDataaaa[0]?.fcmToken) {
  notificationTokens.push(installationDataaaa[0]?.fcmToken);
}
if (installationDataaaa[0]?.installerFcmToken) {
  notificationTokens.push(installationDataaaa[0]?.installerFcmToken);

    }
      }

   notificationMsg = `Installation ${installationName} has been re-assigned to ${[...driverNames].join(", ")}`;

   let currentDate = Math.round(moment().valueOf() / 1000);
        const requestUpdateInfo = await Installation.fetchDetailsForNotification(id, driverIds[0]);

        await RequestUpdates.addRequestUpdates({
          request_id: requestUpdateInfo[0]?.request_id,
          activity: `Installation "${installationProductName || installationName}" has been re-assigned to ${[...driverNames].join(", ")} ${reassign_reason != null && reassign_reason !== '' ? `with reason: ${reassign_reason}` : ''}`,
          partner_id: 0,
          added_by: userId,
          timestamp: currentDate,
        });

        let notificationUrl = "installation";
        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();
            for (let eachadminIds of adminIds) {
              if (eachadminIds != userId) {
                let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
                
                  notificationData_user.user_id= eachadminIds,
                 
                 await Admin.addNotification(notificationData_user);
              }
            }


       
               
if (notificationTokens.length > 0) {
  for (const token of notificationTokens) {
    console.log("notificationTokenstoken", token);
    const message = {
      data: {},
      notification: {
        title: 'Installation',
        body: mobileNotification || 'Installation status has been updated.',
      },
      android: {
        notification: {
          image: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e'
          // icon: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/test%2Fsignwiseround.png?alt=media&token=ecf322c0-9490-49d3-b744-dbe7c154859d'
        }
      },
      token
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message to token:', token, response);
      })
      .catch((error) => {
        console.error('Error sending message to token:', token, error);
      });
    }}

      }
    }

    emitProgress('complete', `Installation reassignment completed successfully!`, 100);
    res.send({ message: "success", status: 1 });
  } catch (error) {
    res.send({ message: error.message, status: 0 });
  }
};



// const reassignInstallationToDriverInsideDetails = async (req, res) => {
//   try {
//     const { instId, selectTemplate, selectedValues, isDriver, selectedDriver, userId } = req.body;
//     let currentDate = Math.round(moment().valueOf() / 1000);

//     // Determine the driver ID
//     let driverId = isDriver
//       ? selectedValues[0]?.id
//       : selectedDriver[0]?.id || null;

//     console.log("dattaaaaaaaaaaaaaaaaaa", req.body);

//     let installationId = Number(instId)
//     // Fetch installation data for the single instId
//     const installationData = await Installation.findInstallationDataById(installationId);
//     console.log('installationData', installationData);

//     // Prepare route data
//     let data = {
//       name: `route ${currentDate}`,
//       zipcodes: installationData?.zipcode || '',
//       assigned_driver: driverId,
//       timestamp: currentDate,
//       added_by: userId,
//       unique_id: 'SWS' + (parseInt(crypto.randomBytes(2).toString('hex'), 16) % 90000 + 10000),
//     };

//     // Update the route
//     await Route.updateRoute(data, installationData.route_id);

//     // Prepare installation table data
//     const installationTableData = {
//       installation_temp_id: selectTemplate.id,
//       status: 2,
//       team_id: isDriver ? selectedValues[0]?.user_id : selectedDriver[0]?.user_id || null,
//       driver_is_installer: isDriver ? 2 : 1,
//       driver_id: driverId,
//       route_id: installationData.route_id || null,
//     };

//     // Update the installation data
//     const updateInstallation = await Installation.updateInstallationDataById(instId, installationTableData);

//     if (updateInstallation) {
//       const installationDetails = await Installation.fetchDetailsForNotification(instId, driverId);

//       // Prepare notification messages
//       let notificationMsg = `An Installation ${installationDetails[0].installation_name} has been re-assigned to ${installationDetails[0].driver_name}`;
//       let mobileNotification = `A new Installation ${installationDetails[0].installation_name} has been assigned to you`;

//       let notificationUrl = "installation";
//       let notificationData_user = {
//         user_id: userId,
//         url: notificationUrl,
//         timestamp: currentDate,
//         message: notificationMsg,
//         status: 1,
//         from_id: userId,
//       };

//       // Add notification
//       await Admin.addNotification(notificationData_user);

//       // Send mobile notification if FCM token exists
//       if (installationDetails[0]?.fcmToken) {
//         const message = {
//           notification: {
//             title: 'Installation',
//             body: mobileNotification,
//           },
//           token: installationDetails[0].fcmToken,
//         };

//         admin.messaging().send(message)
//           .then((response) => {
//             console.log('Successfully sent message:', response);
//             res.send({ success: true, response });
//           })
//           .catch((error) => {
//             console.error('Error sending message:', error);
//             res.status(500).send({ error: error.message });
//           });
//       } 
//         res.send({ message: "Installation reassigned successfully", status: 1 });
      
//     } else {
//       res.status(400).send({ message: "Failed to update installation data", status: 0 });
//     }
//   } catch (error) {
//     console.log("Error:", error);
//     res.status(500).send({ message: error.message, status: 0 });
//   }
// };


const reassignInstallationToDriverInsideDetails = async (req, res) => {
  try {
    const { instId, selectTemplate, selectedValues, isDriver, selectedDriver, userId, userType, socketId, reassign_reason, vehicleId} = req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_reassignment_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_reassignment_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-REASSIGNMENT-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-REASSIGNMENT-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-REASSIGNMENT-PROGRESS] 🚀 Starting installation reassignment for user:`, userId);
    emitProgress('start', `Initializing installation reassignment...`, 5);

    // Ensure selectedValues and selectedDriver are arrays
    const selectedValuesArray = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
    const selectedDriverArray = Array.isArray(selectedDriver) ? selectedDriver : [selectedDriver];

    emitProgress('processing_drivers', `Processing driver reassignment...`, 15);

    // Determine the driver ID
    let driverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

    console.log("dattaaaaaaaaaaaaaaaaaa", driverId);

    emitProgress('fetching_installation', `Fetching installation data...`, 25);

    let installationId = Number(instId);
    // Fetch installation data for the single instId
    const installationData = await Installation.findInstallationDataById(installationId);
    console.log('installationData', installationData);

    emitProgress('updating_route', `Updating route information...`, 35);

    // Prepare route data
    let data = {
      name: `route ${currentDate}`,
      zipcodes: installationData?.zipcode || '',
      assigned_driver: driverId,
      timestamp: currentDate,
      added_by: userId,
      unique_id: 'SWS' + (parseInt(crypto.randomBytes(2).toString('hex'), 16) % 90000 + 10000),
      assigned_sales_order : installationData?.request_id || '',
      assigned : 1,
    };

    // let routeId = null;
    // Update the route
    // if(installationData.route_id){
    await Route.updateRoute(data, installationData.route_id);
    let  routeId = installationData.route_id;
    // }
    // else{
    //       // Prepare route data
    // let data = {
    //   name: `route ${currentDate}`,
    //   zipcodes: installationData?.zipcode || '',
    //   assigned_driver: null,
    //   timestamp: currentDate,
    //   added_by: userId,
    //   status: 1,
    //   unique_id: 'SWS' + (parseInt(crypto.randomBytes(2).toString('hex'), 16) % 90000 + 10000),
    //   assigned_sales_order : installationData?.request_id || '',
    //   assigned : 1,
    // };

    // // Create the route
    //  routeId = await Route.createRoute(data);
    // }

    emitProgress('updating_installation', `Updating installation assignment...`, 50);

    // Prepare installation table data
    const installationTableData = {
      installation_temp_id: selectTemplate.id,
      status: 2,
      // team_id: isDriver ? selectedValuesArray[0]?.user_id : selectedDriverArray[0]?.user_id || null,
      team_id:selectedValuesArray.map(driver => driver.user_id).join(",") || null ,
      driver_is_installer: isDriver ? 2 : 1,
      driver_id: driverId,
      route_id: installationData.route_id || null,
      vehicle_id: vehicleId || null,
    };
    if (reassign_reason != null && reassign_reason !== '') {
      installationTableData.reassign_reason = reassign_reason;
    }
    console.log('installationTableData', installationTableData)

    // Update the installation data
    const updateInstallation = await Installation.updateInstallationDataById(instId, installationTableData);

    if (updateInstallation) {
      emitProgress('processing_notifications', `Processing notifications...`, 70);
      
              let allDriverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

      const driverIds = allDriverId.split(",").map(s => s.trim()).filter(Boolean).map(Number); 
       const notificationTokens = [];
       let installationDataaaa = []
        let notificationMsg =``
        let mobileNotification =``
        const driverNames        = new Set(); 
        let   installationName   = "";  
        const installationData = await Installation.fetchApointmentById(instId) 
        let   installationProductName  = installationData[0]?.product_name || installationData[0]?.service_name; 
         for (const driverId of driverIds) {
      const installationDetails = await Installation.fetchDetailsForNotification(instId, driverId);
     
       installationName = installationDetails[0].installation_name || installationName;
       driverNames.add(installationDetails[0].driver_name);
     
      // Prepare notification messages
       notificationMsg = `An Installation ${installationDetails[0]?.installation_name} has been re-assigned to ${installationDetails[0]?.driver_name}`;
       mobileNotification = `A new Installation ${installationDetails[0]?.installation_name} has been assigned to you`;

  
if (installationDetails[0]?.fcmToken) {
  notificationTokens.push(installationDetails[0]?.fcmToken);
}
if (installationDetails[0]?.installerFcmToken) {
  notificationTokens.push(installationDetails[0]?.installerFcmToken);
}

         }

         notificationMsg = `Installation ${installationName} has been re-assigned to ${[...driverNames].join(", ")}`;

      let notificationUrl = "installation";
      let notificationData_user = {
        user_id: userId,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: userId,
      };

      // Add notification
      await Admin.addNotification(notificationData_user);

      // Safely get installationDetails again outside the loop
      const firstDriverId = driverIds[0];
      const requestUpdateDetails = await Installation.fetchDetailsForNotification(instId, firstDriverId);

      await RequestUpdates.addRequestUpdates({
        request_id: requestUpdateDetails[0]?.request_id,
        activity: `Installation "${installationProductName || installationName}" has been re-assigned to ${[...driverNames].join(", ")}${reassign_reason ? `. Reason: ${reassign_reason}` : ''}`,
        partner_id: 0,
        added_by: userId,
        timestamp: currentDate,
      });

       let adminIds = await Admin.getAllAdminIds();
            for (let eachadminIds of adminIds) {
              if (eachadminIds != userId) {
                let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
                
                  notificationData_user.user_id= eachadminIds,
                 
                 await Admin.addNotification(notificationData_user);
              }
            }

if (notificationTokens.length > 0) {
  for (const token of notificationTokens) {
    console.log("notificationTokenstoken", token);
    const message = {
      data: {},
      notification: {
        title: 'Installation',
        body: mobileNotification || 'Installation status has been updated.',
      },
      android: {
        notification: {
          image: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e'
          // icon: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/test%2Fsignwiseround.png?alt=media&token=ecf322c0-9490-49d3-b744-dbe7c154859d'
        }
      },
      token
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message to token:', token, response);
      })
      .catch((error) => {
        console.error('Error sending message to token:', token, error);
      });
    }}


        emitProgress('complete', `Installation reassignment completed successfully!`, 100);
        res.send({ message: "Installation reassigned successfully", status: 1 });
      
    } else {
      emitProgress('error', `Failed to update installation data`, 0);
      res.status(400).send({ message: "Failed to update installation data", status: 0 });
    }
  } catch (error) {
    console.log("Error:", error);
    res.status(500).send({ message: error.message, status: 0 });
  }
};


// const assignInstallationsAssignToDriverInsideDetails = async (req, res) => {
//   try {
//     const { instId, selectTemplate, selectedValues, isDriver, selectedDriver, userId } = req.body;
//     let currentDate = Math.round(moment().valueOf() / 1000);

//     // Determine the driver ID
//     let driverId = isDriver
//       ? selectedValues[0]?.id
//       : selectedDriver[0]?.id || null;

//     console.log("dattaaaaaaaaaaaaaaaaaa", req.body);

//     // Fetch installation data for the single instId
//     const installationData = await Installation.findInstallationDataById(instId);
//     console.log('installationData', installationData);

//     // Prepare route data
//     let data = {
//       name: `route ${currentDate}`,
//       zipcodes: installationData?.zipcode || '',
//       assigned_driver: null,
//       timestamp: currentDate,
//       added_by: userId,
//       status: 1,
//       unique_id: 'SWS' + (parseInt(crypto.randomBytes(2).toString('hex'), 16) % 90000 + 10000),
//     };

//     // Create the route
//     let routeId = await Route.createRoute(data);

//     // Prepare installation table data
//     const installationTableData = {
//       installation_temp_id: selectTemplate.id,
//       status: routeId ? 2 : 1,
//       team_id: isDriver ? selectedValues[0]?.user_id : selectedDriver[0]?.user_id || null,
//       driver_is_installer: isDriver ? 2 : 1,
//       driver_id: driverId,
//       route_id: routeId || null,
//     };

//     // Update the installation data
//     const updateInstallation = await Installation.updateInstallationDataById(instId, installationTableData);

//     if (updateInstallation) {
//       const installationDetails = await Installation.fetchDetailsForNotification(instId, driverId);

//       // Prepare notification messages
//       let notificationMsg = `A new Installation ${installationDetails[0]?.installation_name} has been assigned to ${installationDetails[0]?.driver_name}`;
//       let mobileNotification = `A new Installation ${installationDetails[0]?.installation_name} has been assigned to you`;

//       let notificationUrl = "installation";
//       let notificationData_user = {
//         user_id: userId,
//         url: notificationUrl,
//         timestamp: currentDate,
//         message: notificationMsg,
//         status: 1,
//         from_id: userId,
//       };

//       // Add notification
//       await Admin.addNotification(notificationData_user);

//       // Send mobile notification if FCM token exists
//       if (installationDetails[0]?.fcmToken) {
//         const message = {
//           notification: {
//             title: 'Installation',
//             body: mobileNotification,
//           },
//           token: installationDetails[0].fcmToken,
//         };

//         admin.messaging().send(message)
//           .then((response) => {
//             console.log('Successfully sent message:', response);
//             res.send({ success: true, response });
//           })
//           .catch((error) => {
//             console.error('Error sending message:', error);
//             res.status(500).send({ error: error.message });
//           });
        
//       }
//     }

//     // Update the route with the assigned driver
//     let updatedRouteData = {
//       assigned_driver: driverId,
//     };

//     await Route.updateRoute(updatedRouteData, routeId);

//     res.send({ message: "Installation reassigned successfully", status: 1 });
//   } catch (error) {
//     console.error("Error:", error);
//     res.status(500).send({ message: error.message, status: 0 });
//   }
// };


const assignInstallationsAssignToDriverInsideDetails = async (req, res) => {
  try {
    const { instId, selectTemplate, selectedValues, isDriver, selectedDriver, userId, userType, socketId, vehicleId} = req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);

    // 🚀 PROGRESS TRACKING: Socket progress emission function
    const emitProgress = (step, message, progress) => {
      const progressData = {
        step,
        message,
        progress,
        userId,
        domain: DOMAIN,
        timestamp: currentDate,
        type: 'installation_assignment_inside_progress'
      };
      
      // Emit to working socket server (same as chat)
      console.log(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] 📡 Emitting progress to working socket server...`);
      try {
        const workingSocket = ioClient(REST_API_IO, {
          path: '/socket.io',
          transports: ['websocket', 'polling'],
          secure: true,
          timeout: 5000
        });
        
        workingSocket.on('connect', () => {
          console.log(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] 🔌 Connected to working socket server`);
          console.log(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] 📊 Emitting progress data:`, progressData);
          
          // Try emitting as 'message' event (same as chat) to test if socket server handles it
          workingSocket.emit('message', {
            ...progressData,
            type: 'progress',
            conversationId: `installation_assignment_inside_progress_${userId}`,
            senderId: 'system'
          });
          
          // Also try the original request_progress event
          workingSocket.emit('request_progress', progressData);
          
          console.log(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] ✅ Successfully emitted progress to working socket server`);
          
          // Disconnect after emitting
          setTimeout(() => {
            workingSocket.disconnect();
          }, 1000);
        });
        
        workingSocket.on('connect_error', (error) => {
          console.error(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] ❌ Working socket connection error:`, error);
        });
        
      } catch (error) {
        console.error(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] ❌ Error creating working socket connection:`, error);
      }
    };

    // Initial progress
    console.log(`[INSTALLATION-ASSIGNMENT-INSIDE-PROGRESS] 🚀 Starting installation assignment inside details for user:`, userId);
    emitProgress('start', `Initializing installation assignment...`, 5);

    // Ensure selectedValues and selectedDriver are arrays
    const selectedValuesArray = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
    const selectedDriverArray = Array.isArray(selectedDriver) ? selectedDriver : [selectedDriver];

    emitProgress('processing_drivers', `Processing driver assignment...`, 15);

    // Determine the driver ID
    let driverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;
      console.log('selectedValuesArrayyyyy',selectedValuesArray)
      console.log('driverIdddddd',driverId)
    console.log("dattaaaaaaaaaaaaaaaaaa", req.body);

    emitProgress('fetching_installation', `Fetching installation data...`, 25);

    // Fetch installation data for the single instId
    const installationData = await Installation.findInstallationDataById(instId);
    const requestId = installationData?.request_id
    const routeId = await Routes.getRouteDatabyRequestId(requestId);
    const installationById = await Installation.findInstallationById(instId)
    const clientId = installationById?.customer_id
    
    console.log('installationData', installationData);
    console.log('routeIdddddd:', routeId);

    // Prepare route data
    // let data = {
    //   name: `route ${currentDate}`,
    //   zipcodes: installationData?.zipcode || '',
    //   assigned_driver: null,
    //   timestamp: currentDate,
    //   added_by: userId,
    //   status: 1,
    //   unique_id: 'SWS' + (parseInt(crypto.randomBytes(2).toString('hex'), 16) % 90000 + 10000),
    //   assigned_sales_order : installationData?.request_id || '',
    //   assigned : 1,
    // };

    // // Create the route
    // let routeId = await Route.createRoute(data);

    emitProgress('updating_installation', `Updating installation assignment...`, 40);

    // Prepare installation table data
    const installationTableData = {
      installation_temp_id: selectTemplate.id,
      status: routeId ? 2 : 1,
      // team_id: isDriver ? selectedValuesArray[0]?.user_id : selectedValuesArray[0]?.user_id || null,
      team_id:selectedValuesArray.map(driver => driver.user_id).join(",") || null ,
      driver_is_installer: isDriver ? 2 : 1,
      driver_id: driverId,
      route_id: routeId || null,
      vehicle_id: vehicleId || null,
    };

    // Update the installation data
    const updateInstallation = await Installation.updateInstallationDataById(instId, installationTableData);
    console.log('updateInstallationn',updateInstallation)
    if (updateInstallation) {
      emitProgress('processing_notifications', `Processing notifications...`, 60);
      
              let allDriverId = isDriver
      ? selectedValuesArray.map(driver => driver.id).join(",")
      : selectedDriverArray.map(driver => driver.id).join(",") || null;

      const driverIds = allDriverId.split(",").map(s => s.trim()).filter(Boolean).map(Number); 

 const notificationTokens = [];
       let installationDataaaa = []
        let notificationMsg =``
        let mobileNotification =``
        const driverNames        = new Set(); 
        let   installationName   = "";  
        const installationData = await Installation.fetchApointmentById(instId) 
        let   installationProductName  = installationData[0]?.product_name || installationData[0]?.service_name;

         for (const driverId of driverIds) {
      const installationDetails = await Installation.fetchDetailsForNotification(instId, driverId);
       
       installationName = installationDetails[0].installation_name || installationName;
       driverNames.add(installationDetails[0].driver_name);
      
      // Prepare notification messages
       notificationMsg = `A new Installation ${installationDetails[0]?.installation_name} has been assigned to ${installationDetails[0]?.driver_name}`;
       mobileNotification = `A new Installation ${installationDetails[0]?.installation_name} has been assigned to you`;

       if (installationDetails[0]?.fcmToken) {
  notificationTokens.push(installationDetails[0]?.fcmToken);
}
if (installationDetails[0]?.installerFcmToken) {
  notificationTokens.push(installationDetails[0]?.installerFcmToken);
}

         }
            notificationMsg = `A new Installation ${installationName} has been assigned to ${[...driverNames].join(", ")}`;
      let notificationUrl = "installation";
      let notificationData_user = {
        user_id: userId,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: userId,
      };

      // Add notification
      await Admin.addNotification(notificationData_user);

      await RequestUpdates.addRequestUpdates({
        request_id: installationById.request_id,
        activity: `A new Installation "${installationProductName || installationName}" has been assigned to ${[...driverNames].join(", ")}`,
        partner_id: 0,
        added_by: userId,
        timestamp: currentDate,
      });

       let adminIds = await Admin.getAllAdminIds();
            for (let eachadminIds of adminIds) {
              if (eachadminIds != userId) {
                let incrementResult = await Admin.incrementField(eachadminIds, 'noti_count', 1)
                
                  notificationData_user.user_id= eachadminIds,
                 
                 await Admin.addNotification(notificationData_user);
              }
            }
    

        // const projectResult = await Project.findProjectById(installationById?.request_id,true);   
        // const project_members = await Project.getAllMemberUserIdsByProjectId(projectResult?.id)
        // const allUserIds = await Admin.getAllUserIds();
        // const clientUser = await Client.getClientById(clientId);
        // const selectedClientId = clientUser?.user_id ||null;
        // const installationId = instId
        // const previousStatus = installationById?.status
        // const updateCounts = async (userId) => {
        //   if (previousStatus == 1) {
        //       await Installation.installationTabIncrementField(userId, "staged_count", -1, "staged_count_ids", installationId, false);
        //       await Installation.installationTabIncrementField(userId, "installing_count", 1, "installing_count_ids", installationId, true);
        //     } 
        //   };
      
        // let usersToUpdate = 
        //   // ? [...new Set([userId, selectedClientId, ...allUserIds].filter(Boolean))]
        //    [...new Set([selectedClientId,userId,...project_members, ...allUserIds].filter(Boolean))];

        // if (usersToUpdate.length > 0) {
        //   await Promise.all(usersToUpdate.map(user => updateCounts(user)));
        // }
        // console.log(`Successfully updated installs count`);

      

            




if (notificationTokens?.length > 0) {
  for (const token of notificationTokens) {
    console.log("notificationTokenstoken", token);
    const message = {
      data: {},
      notification: {
        title: 'Installation',
        body: mobileNotification || 'Installation status has been updated.',
      },
      android: {
        notification: {
          image: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/whiteowl.png?alt=media&token=4c1a34f9-899f-4de1-888d-81ea9dade65e'
          // icon: 'https://firebasestorage.googleapis.com/v0/b/signwise-2024.appspot.com/o/test%2Fsignwiseround.png?alt=media&token=ecf322c0-9490-49d3-b744-dbe7c154859d'
        }
      },
      token
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message to token:', token, response);
      })
      .catch((error) => {
        console.error('Error sending message to token:', token, error);
      });
    }}

    }

    emitProgress('updating_route', `Updating route information...`, 90);

    // Update the route with the assigned driver
    let updatedRouteData = {
      assigned_driver: driverId,
      zipcodes: installationData?.zipcode || '',
      assigned : 1,
    };

    await Route.updateRoute(updatedRouteData, routeId);

    emitProgress('complete', `Installation assignment completed successfully!`, 100);
    res.send({ message: "Installation reassigned successfully", status: 1 });
  } catch (error) {
    console.error("Error:", error);
    res.status(500).send({ message: error.message, status: 0 });
  }
};
const reduceInstallationCount = async (req, reply) => {
  try {
    const { installation_id, userId } = req.body;
    console.log(`Successfully installation_id`,installation_id,userId);
    const userCount = await Installation.getInstallationTabCountByUserData(userId);
    if (!userCount) {
      return reply.status(400).send({ status: 0, message: "User record not found" });
    }
    console.log(`Successfully userCount`,userCount);
    const countFields = {
      staged_count: "staged_count_ids",
      completed_count: "completed_count_ids",
      returned_count: "returned_ids",
      installing_count: "installing_count_ids",
    };

    let updatedField = null;
    let updatedCountField = null;

    for (const [countField, idsField] of Object.entries(countFields)) {
      let idsArray = userCount[idsField] ? userCount[idsField].split(",") : [];

      if (idsArray.includes(installation_id.toString())) {
        await Installation.installationTabIncrementField(userId, countField, -1, idsField, installation_id, false);
        updatedField = idsField;
        updatedCountField = countField;
        break;
      }
    }

    if (!updatedField) {
      return reply.status(400).send({ status: 0, message: "Installation ID not found in any count list" });
    }

    console.log(`Successfully updated count for ${updatedCountField}`);

    reply.send({
      status: 1,
      message: `Count updated successfully. Removed from ${updatedField}`,
      updatedCountField,
    });
  } catch (error) {
    console.error("Error reducing design order count:", error);
    reply.status(500).send({ status: 0, message: "Server error", error });
  }
};
const reducePickupCount = async (req, reply) => {
  try {
    const { installation_id, userId } = req.body;
    console.log(`Successfully installation_id`,installation_id,userId);
    const userCount = await Installation.getPickupTabCountByUserData(userId);
    if (!userCount) {
      return reply.status(400).send({ status: 0, message: "User record not found" });
    }
    console.log(`Successfully userCount`,userCount);
    const countFields = {
      staged_count: "staged_count_ids",
      completed_count: "completed_count_ids",
    };

    let updatedField = null;
    let updatedCountField = null;

    for (const [countField, idsField] of Object.entries(countFields)) {
      let idsArray = userCount[idsField] ? userCount[idsField].split(",") : [];

      if (idsArray.includes(installation_id.toString())) {
        await Installation.pickupTabIncrementField(userId, countField, -1, idsField, installation_id, false);
        updatedField = idsField;
        updatedCountField = countField;
        break;
      }
    }

    if (!updatedField) {
      return reply.status(400).send({ status: 0, message: "Installation ID not found in any count list" });
    }

    console.log(`Successfully updated count for ${updatedCountField}`);

    reply.send({
      status: 1,
      message: `Count updated successfully. Removed from ${updatedField}`,
      updatedCountField,
    });
  } catch (error) {
    console.error("Error reducing pickup count:", error);
    reply.status(500).send({ status: 0, message: "Server error", error });
  }
};
const reduceShippingCount = async (req, reply) => {
  try {
    const { installation_id, userId } = req.body;
    console.log(`Successfully installation_id`,installation_id,userId);
    const userCount = await Installation.getShippingTabCountByUserData(userId);
    if (!userCount) {
      return reply.status(400).send({ status: 0, message: "User record not found" });
    }
    console.log(`Successfully userCount`,userCount);
    const countFields = {
      staged_count: "staged_count_ids",
      completed_count: "completed_count_ids",
      returned_count: "returned_ids",
    };

    let updatedField = null;
    let updatedCountField = null;

    for (const [countField, idsField] of Object.entries(countFields)) {
      let idsArray = userCount[idsField] ? userCount[idsField].split(",") : [];

      if (idsArray.includes(installation_id.toString())) {
        await Installation.shippingTabIncrementField(userId, countField, -1, idsField, installation_id, false);
        updatedField = idsField;
        updatedCountField = countField;
        break;
      }
    }

    if (!updatedField) {
      return reply.status(400).send({ status: 0, message: "Installation ID not found in any count list" });
    }

    console.log(`Successfully updated count for ${updatedCountField}`);

    reply.send({
      status: 1,
      message: `Count updated successfully. Removed from ${updatedField}`,
      updatedCountField,
    });
  } catch (error) {
    console.error("Error reducing shipping count:", error);
    reply.status(500).send({ status: 0, message: "Server error", error });
  }
};

// Helper function to create new finished product (extracted from original logic)
const createNewFinishedProduct = async (product, totalQtyToAdd, userId, currentDate, result) => {
  if (product.meterial !== 1) {
    const id = crypto.randomBytes(6).readUIntLE(0, 6);
    const barcode = String(id).padStart(14, "0");
    const addData = {
      barcode: product.meterial !== 1 ? "C" + barcode : "SW" + barcode,
      material_id: product.product_id,
      unit_cost: product.actual_retail_price,
      actual_qty: totalQtyToAdd,
      qty: totalQtyToAdd,
      actual_unit_qty: totalQtyToAdd,
      unit_qty: totalQtyToAdd,
      actual_total_cost: product.actual_retail_price * totalQtyToAdd,
      total_cost: product.actual_retail_price * totalQtyToAdd,
      status: 1,
      added_by: userId,
      timestamp: currentDate,
      source: 0
    };

    const finishedProductResult = await Product.addFinishedProduct(addData);

    let message = `A new Finished Product has been added through no charge order ${result.name}.`;

    await Product.addClientStockLog({
      catalog_id: product.product_id,
      catalog_log_message: message,
      timestamp: currentDate,
      status: 1,
      catalog_source: 2, 
      added_by: userId,
    });
  }
};
const getInstallationByTeamId = async (req, reply) => {
  try {
    const { team_id,forAddTimesheet } = req.body;
    console.log('team_id :==> ',team_id)
    const installations = await Installation.getInstallationByTeamId(team_id,forAddTimesheet);
    if(installations.length > 0){
      return reply.send({ status: 1, installations });
    }else{
      return reply.send({ status: 0, message: "No installations found" });
    }
  } catch (error) {
    console.error("Error fetching installation by team id:", error);
    return reply.status(500).send({ status: 0, message: "Server error", error });
  }
};  
const getInstallationTaskByRequestId = async (req, reply) => {
  try {
    const { id } = req.body;
    console.log('id :==> ',id)
    const installations = await Installation.getInstallationTaskByRequestId(id);
    if(installations.length > 0){
      return reply.send({ status: 1, tasks: installations });
    }else{
      return reply.send({ status: 0, message: "No installations found" });
    }
  } catch (error) {
    console.error("Error fetching installation task by request id:", error);
    return reply.status(500).send({ status: 0, message: "Server error", error });
  }
};
module.exports={getAllProjectsInstallation,getAllTeamAndDrivers,getProductsById,getLocationsById,getTotalPaidAmountByRequestId,addApointment,
  fetchAllApointments,fetchAllApointmentsFilter,fetchAllApointmentsCalendar,fetchAllApointmentsCount,updateProjectInstallationDate,fetchApointmentById, getAllCustomerOrders, addInstallationNote, 
  editInstallationNote, deleteInstallationNote, fetchNotesByInstallationId,
  addInstallationTemplate,
  getAllInstallationTemplate,
  deleteInstallationTemplate,
  getInstTemplateData,
  saveInstTemplate,
  getInstTemplateDatabyId,
  updateInstTemplate,
  updateInstallationHoldStatus,
  updateInstallationStatus,
  completeInstallationReview,
  rejectInstallationReview,
  DuplicateTemplate,
  updateProjectInstallationDateInProject,
  updateTemplate,
  updateInstallationAddress,
  updateInstallationDataByRequestId,
  deactivateInstallationTemplate,
  saveProjectOrder,
  updateLatLong,
  convertJobToInstallation,
  convertSingleJobToInstallationSplitBuildOrder,
  convertJobToBuildOrderComplete,
  convertJobToNoChargeComplete,
  updateInstallationsAssignToDriver,
  updateInstallationspickupshipping,
  reassignInstallationToDriver,
  reassignInstallationToDriverInsideDetails,
  assignInstallationsAssignToDriverInsideDetails,
  saveInstTemplateForMultipleInstallation,
  getAllInstallsTabCount,
  reduceInstallationCount,
  getAllPickupTabCount,
  getAllShippingTabCount,
  reduceShippingCount,
  reducePickupCount,
  deleteInstallationById,
  getInstallationByTeamId,
  getInstallationTaskByRequestId
}