const { empty } = require("../Helpers/Common");
const Project = require("../models/Projects");
const Installation = require(`../models/installation`);
const Community = require(`../models/community`);
const Admin = require("../models/admin");
const Client = require("../models/client");
const moment = require("moment");
const ProjectTask = require("../models/projectTask");
const ProjectTaskController = require("../controllers/projectTask");
const ProjectPost = require("../models/Projectpost");
const Products = require("../models/product");
const JobCost = require("../models/jobCost");
const Product = require("../models/product");
const Request = require("../models/request");
const RequestPartner = require('../models/requestPartners');
const { BASE_URL } = require("../constants/constant");
const { ItemAssignmentContextImpl } = require("twilio/lib/rest/numbers/v2/regulatoryCompliance/bundle/itemAssignment");
const { deletedItemEmailTemplate } = require("../constants/emailTemplates");
const { sendMessageToPhoneNumber } = require("./teams");
let currentDate = Math.round(moment().valueOf() / 1000);
const nodemailer = require('nodemailer');
const recipeModel = require("../models/recipe");
const { getAllWorkflow } = require('../models/staffmember');
const staffmember = require('../models/staffmember');
const Department = require('../models/department');
const { FACILITY_ID } = require("../config/SplitManagementDb");
const { filteredSignwiseInstalations } = require("../Helpers/SplitManagementHelper");
const { default: axios } = require("axios");
const SplitManagementModel = require('../models/SplitManagementModel');
const { getNewAccessToken, realmId, PRODUCTION } = require("../quickbook/quickbook");

function formatHoursToHHMMSS(hours) {
  const duration = moment.duration(hours, "hours");
  const formattedDuration = moment
    .utc(duration.asMilliseconds())
    .format("HH:mm:ss");
  return formattedDuration;
}

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

const formatSubTaskHoursToHHMMSS = (hours) => {
  const duration = moment.duration(hours, "hours");
  const hh = Math.floor(duration.asHours());
  const mm = Math.floor(duration.asMinutes()) % 60;
  const ss = Math.floor(duration.asSeconds()) % 60;
  return `${hh.toString().padStart(2, "0")}:${mm
    .toString()
    .padStart(2, "0")}:${ss.toString().padStart(2, "0")}`;
};

const getDataForAddProject = async (request, reply) => {
  try {
    let userType = request.body?.userType||null;
    let From = request.body?.From || null;
    let teamId = request.body?.teamId || null;
    const FromDesignOrder = request.body?.FromDesignOrder || false;
    // let projectCategories = await Project.getAllProjectCategories(true);
    // let projectTypes = await Project.getAllProjectTypes(true);
    // let noChargeType = await Project.getAllNoChargeTypes(true);
    // let states = await Project.getAllStates(true);
    // let acceptedRequests = await Project.acceptedRequests();
    // let community = await Community.getAllCommunities(null,null,null,null,null,userType,null,From,teamId);
    // let labourCostServices = await Product.getAllLabourCostServices();
    // let allDesigners = await Project.getAllDesignTeamMembers();
    // let allEstimators = await Project.getAllEstimateTeamMembers();
    let projectCategories = [];
    let projectTypes = [];
    let noChargeType = [];
    let states = [];
    let acceptedRequests = [];
    let community = [];
    let labourCostServices = [];
    let allDesigners = [];
    let allEstimators = [];

    if (FromDesignOrder) {
      [labourCostServices, allDesigners] = await Promise.all([
        Product.getAllLabourCostServices(true),
        Project.getAllDesignTeamMembers(),
      ]);
    } else {
      [projectCategories, projectTypes, noChargeType, states, acceptedRequests, community, labourCostServices, allDesigners, allEstimators] = await Promise.all([
        Project.getAllProjectCategories(true),
        Project.getAllProjectTypes(true),
        Project.getAllNoChargeTypes(true),
        Project.getAllStates(true),
        Project.acceptedRequests(),
        Community.getAllCommunities(null, null, null, null, null, userType, null, From, teamId),
        Product.getAllLabourCostServices(true),
        Project.getAllDesignTeamMembers(),
        Project.getAllEstimateTeamMembers(),
      ]);
    }
    // labourCostServices = labourCostServices.filter(row => row.inhouse === 1)
    reply.send({
      status: 1,
      projectCategories,
      projectTypes,
      allDesigners,
      allEstimators,
      states,
      acceptedRequests,
      community,
      noChargeType,
      labourCostServices,
      message: "Data fetched successfully",
    });
  } catch (error) {
    console.log("errorerror", error);
    reply.status(500).send("Server error");
  }
};
const getSpecificDataForAddProject = async (request, reply) => {
  try {
    let [projectCategories,projectTypes,allEstimators] = await Promise.all([
      Project.getAllProjectCategories(true),
      Project.getAllProjectTypes(true),
      Project.getAllEstimateTeamMembers()
    ]);
    // labourCostServices = labourCostServices.filter(row => row.inhouse === 1)
    reply.send({
      status: 1,
      projectCategories,
      projectTypes,
      allEstimators,
      message: "Data fetched successfully",
    });
  } catch (error) {
    console.log("errorerror", error);
    reply.status(500).send("Server error");
  }
};
const addProject = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectData = {};
    (projectData.project_uid = request.body.project_uid),
      (projectData.name = request.body.name),
      (projectData.short_code = request.body.short_name || "DefaultShortName"),
      (projectData.request_id = request.body.rfq || 0),
      (projectData.tags = request.body.tags || ""),
      (projectData.start_date = request.body.start_date || null),
      (projectData.due_date = request.body.end_date || null),
      (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),
      (projectData.project_category = request.body.project_category || 0),
      (projectData.community = request.body.community || 1),
      (projectData.project_type = request.body.project_type || 0),
      (projectData.website_url = request.body.url || ""),
      (projectData.state_id = request.body.state || 0),
      (projectData.city = request.body.city || "DefaultCity"),
      (projectData.cost = request.body.cost || null),
      (projectData.description = (request.body.description || '').replace(/\r?\n/g, '\n')),
      (projectData.description_lines = projectData.description ? projectData.description.split('\n') : []),
      (projectData.approved_image =
        request.body.approved_image ||
        "https://media.freshbooks.com/wp-content/uploads/2022/03/approve-an-invoice-payment.jpg"),
      (projectData.cover_image = request.body.avatarUrl || null),
      (projectData.reason = request.body.reason || ""),
      (projectData.added_by = request.body.added_by),
      (projectData.timestamp = moment().unix()),
      (projectData.status = 1),
      (projectData.installation_status = request.body.installation_status || 0),
      /* ********************** */
      console.log("$$$$$$$$$$$$$$$$$$$ projectData : ", projectData);
    /* ********************** */
    let projectNameExist = await Project.isProjectNameExist(projectData.name);
    console.log("projectNameExist : ", projectNameExist);

    if (projectNameExist != true) {
      try {
        projectData.thumbnail = "fileNamewithDate";

        let result = await Project.addProject(projectData);
        console.log("allProducts-2--", allProducts);
        if (result) {
          let projects = await Project.getProjectById(result.id);
          let allProducts = await Products.getAllProductsBasedOnRequest(
            request.body.rfq
          );
          let taskUid = await ProjectTask.getSubTaskUid(result.id);
          console.log("allProducts-2--", allProducts);
          for (const product of allProducts) {
            const projectTask = {
              name: product.product_name,
              project_id: result.id,
              timestamp: moment().unix(),
              userid: request.body.added_by,
              start_date: request.body.start_date || null,
              due_date: request.body.end_date ? request.body.end_date : null,
              task_uid: taskUid,
              complete: 0,
              complete_sync: 1,
              status: 1,
              cover_image:
                product.product_design || projects.cover_image || null,
              product_id: product.product_id || null,
              priority: 1,
              reporter_id: request.body.added_by,
              description: "",
              project_task_uid: "",
            };

            const projectTaskId = await ProjectTask.addProjectTask(projectTask);

            let task_uid = await ProjectTask.getSubTaskUid(projectTaskId);
            for (const workflow of product.workflow) {
              const subTask = {
                name: workflow.name,
                task_id: projectTaskId,
                timestamp: moment().unix(),
                userid: request.body.added_by,
                start_date: request.body.start_date || null,
                due_date: request.body.end_date ? request.body.end_date : null,
                task_uid: task_uid,
                complete: 0,
                priority: 1,
                status: 1,
                reporter_id: request.body.added_by,
                description: workflow.message,
              };

              const projectSubTaskId = await ProjectTask.addProjectSubTask(
                subTask
              );
              let notificationMsg = `New Job "${projectData.name}" has been added.`;
              let notificationUrl = "Jobs";
              // let projectManagers = await Project.getTeamMembers(14)
              //Add Team member based on skills
              let projectManagers = await Project.getTeamMembersBasedOnSkills(
                request.body.rfqServices,
                14
              );
              console.log("######$$$$$$$$$Annues", projectManagers);
              let pm = {};
              for (const projectManager of projectManagers) {
                console.log("#######nnnn", result.id);
                pm = {
                  project_id: result.id,
                  subtask_id: projectSubTaskId,
                  staff_id: !empty(projectManager["id"])
                    ? projectManager["id"]
                    : NULL,
                  partner_id: null,
                  contact_id: null,
                  lead_id: null,
                };

                let insertId = await Project.addProjectMember(pm);
                const incrementResult_User = await Admin.incrementField(
                  projectManager.user_id,
                  "noti_count",
                  1
                );
              }
            }

            let notificationData_user = {
              user_id: projectManager.user_id,
              url: notificationUrl,
              timestamp: currentDate,
              message: "has assigned you to the job: " + projectData.name,
              status: 1,
              from_id: projectData.added_by,
            };

            const addNotificationResult_user = await Admin.addNotification(
              notificationData_user
            );
          }

          // Notification

          // Alert to user of new added project

          const incrementResult_User = await Admin.incrementField(
            projectData.added_by,
            "noti_count",
            1
          );
          console.log(
            "incrementResult--to--user-----------",
            incrementResult_User
          );
          let notificationData_user = {
            user_id: projectData.added_by,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: projectData.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 != projectData.added_by) {
              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: projectData.added_by,
              };
              console.log("notificationData------------", notificationData);
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
              console.log(
                "addNotificationResult-------",
                addNotificationResult
              );
            }
          }
          reply.send({
            status: 1,
            message: "Job has been successfully added!.",
          });
        } else {
          reply.send({ status: 0, message: "Failed to add the Job" });
        }
        //     }
        //     else {
        //         reply.send({ status: 406, message: "File upload error" })
        //     }
        // }
      } catch (error) {
        console.log("error : ", error);
        reply.send({ status: 0, message: "Failed to add the job" + error });
      }
    } else {
      console.log("The job already exist!");
      reply.send({ status: 2, message: "The Job already exist!" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" });
  }
};
const updateProject = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectId = request.body.projectId;
    let projectData = {};

    // projectData.project_uid = request.body.project_uid,
    (projectData.name = request.body.name),
      (projectData.short_code = request.body.short_name || "DefaultShortName"),
      (projectData.request_id = request.body.rfq || 0),
      (projectData.tags = request.body.tags || ""),
      (projectData.start_date = request.body.start_date || null),
      (projectData.due_date = request.body.end_date || null),
      (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),
      (projectData.project_category = request.body.project_category || 0),
      (projectData.community = request.body.community || 1),
      (projectData.project_type = request.body.project_type || 0),
      (projectData.website_url = request.body.url || ""),
      (projectData.state_id = request.body.state || 0),
      (projectData.city = request.body.city || "DefaultCity"),
      (projectData.cost = request.body.cost || null),
      (projectData.description = (request.body.description || '').replace(/\r?\n/g, '\n')),
      (projectData.description_lines = projectData.description ? projectData.description.split('\n') : []),
      (projectData.approved_image =
        request.body.approved_image ||
        "https://media.freshbooks.com/wp-content/uploads/2022/03/approve-an-invoice-payment.jpg"),
      (projectData.cover_image = request.body.avatarUrl || null),
      (projectData.reason = request.body.reason || ""),
      //
      (projectData.completion = request.body.completion || 0),
      (projectData.installation_status = request.body.installation_status || 0),
      /* ********************** */
      console.log("$$$$$$$$$$$$$$$$$$$ projectData : ", projectData);
    /* ********************** */
    let projectNameExist = await Project.isProjectNameExist(
      projectData.name,
      projectId
    );
    console.log("projectNameExist : ", projectNameExist);
    if (projectNameExist != true) {
      try {
        // const fullfilename = request.body.thumbnail.filename;
        // const extension = fullfilename.substring(fullfilename.lastIndexOf('.') + 1, fullfilename.length);
        // console.log("extension  ", extension);
        // const newfilename = projectData.name.replace(/[^a-zA-Z0-9 ]/g, '_');
        // const filename = newfilename + "." + extension;
        // console.log("filename-- ", filename);
        // const parts = request.body.thumbnail.toBuffer();
        // console.log("File ####################### : ", parts);
        // console.log("Filename ####################### : ", filename);
        // if (parts) {
        //     let fileNamewithDate = `${currentDate}_${filename}`;
        //     let uploaded = await Project.doUpload(parts, fileNamewithDate);
        //     console.log("Filename : ", fileNamewithDate)
        //     if (uploaded) {
        //         console.log("uploaded response - ", uploaded)
        projectData.thumbnail = "fileNamewithDate";
        //         console.log("File uploaded successfully")
        let result = await Project.updateProject(projectId, projectData);
        if (result) {
          // // Notification
          let notificationMsg = `The Job "${projectData.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
          );
          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: "Job has been updated successfully !.",
          });
        } else {
          reply.send({ status: 0, message: "Failed to update the job" });
        }
      } catch (error) {
        console.log("error : ", error);
        reply.send({ status: 0, message: "Failed to update the job" });
      }
    } else {
      console.log("The job already exist!");
      reply.send({ status: 2, message: "The job already exist!" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};
// NEW OPTIMIZED CONTROLLER - Get only filter data (communities, clients, staffMembers)
const getProjectFilterData = async (request, reply) => {
  try {
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let FromDesignJobs = request.body.FromDesignJobs || false;
    
    // Fetch only filter data - no project results, completedInstallations, or pagination
    let community = await Community.getAllCommunitiesWithProjectCount();
    let clients = [];
    let staffMembers = [];
    let departments = [];

    if (!FromDesignJobs) {
      [clients, staffMembers, departments] = await Promise.all([
        Client.getAllClientsDataFilters(),
        getAllWorkflow(),
        Department.getAllDepartments(),
      ]);
    }
    reply.send({
      status: 1,
      community: community,
      clients: clients,
      staffMembers: staffMembers || [],
      departments: departments || [],
      message: "Filter data fetched successfully"
    });
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

// BACKUP: Original getAllProjects controller - commented out for backup
// const getAllProjects = async (request, reply) => {
//   try {
//     // let status = 2;
//     let userType = request.body.userType.value;
//     let userId = request.body.userId.value;
//     let hasPermission = request.body.hasPermission;
//     let sort = request.body.sort;
//     let fromDate = request?.body?.from;
//     let toDate = request?.body?.to;
//     let dueData = request?.body?.dueData;
//     let filterProjectType = request?.body?.filterProjectType;
//     let currentTab = request?.body?.currentTab;
//     let page = request?.body?.page || 1;
//     let limit = request?.body?.limit || 6;
//     let search = request?.body?.search || '';
//     let jobClassFilter = request?.body?.jobClassFilter || [];
//     let jobTypesFilter = request?.body?.jobTypesFilter || [];
//     let clientFilter = request?.body?.clientFilter || [];
//     let userFilter = request?.body?.userFilter || [];
//     let projectFilter = request?.body?.projectFilter || [];
//     
//     let results = await Project.getAllProjects(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       null,
//       sort,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       page,
//       limit,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//     );

//     console.log('getAllProjects results:', results?.length || 0);
//     console.log('currentTab:', currentTab);
//     console.log('filterProjectType:', filterProjectType);


//     for (const data of results) {
//       let attachment = await Request.getAllRequestAttachmentsForCards(data.request_id, data.isFromDesignOrder)
//       data.attachment = attachment || []

//     }



//     let allInstalation = await Installation.fetchAllApointments(
//       userId,
//       userType,
//       hasPermission
//     );
//     let community = await Community.getAllCommunitiesWithProjectCount();
//     // let community = await Community.getAllCommunities();
//     let clients = await Client.getAllClientsDataFilters();
//     const staffMembers = await getAllWorkflow();
//     
//     let completedInstallations = await Project.getAllcompletedInstallations(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       sort,
//       false,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       page,
//       limit,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//     );
//     
//     console.log('getAllcompletedInstallations results:', completedInstallations?.length || 0);
//     
//     // Add project members to each project
//     for (const project of results) {
//       const projectMembers = await Project.getAllProjectMembers(project.id);
//       project.project_members = projectMembers || [];
//     }
//     
//     // Add project members to completed installations
//     for (const project of completedInstallations) {
//       const projectMembers = await Project.getAllProjectMembers(project.id);
//       project.project_members = projectMembers || [];
//     }
//     
//     let filteredProjects;
//     if (currentTab === 'ALL') {
//       // For 'ALL' tab, return all projects without filtering
//       filteredProjects = results;
//     } else {
//       // For specific tabs, filter out projects with installations
//       filteredProjects = results.filter((project) => {
//         return !allInstalation.some(
//           (installation) => installation.project_id === project.id
//         );
//       });
//     }

//     for (const data of completedInstallations) {
//       let attachment = await Request.getAllRequestAttachmentsForCards(data.request_id, data.isFromDesignOrder)
//       data.attachment = attachment || []

//     }

//     // Get total count for pagination
//     let totalCount = await Project.getTotalProjectsCount(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       null,
//       sort,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//     );
//     
//     let totalCompletedCount = await Project.getTotalCompletedInstallationsCount(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       sort,
//       false,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//     );

//     const totalPages = Math.ceil(totalCount / limit);
//     const pagination = {
//       currentPage: page,
//       totalPages: totalPages,
//       totalCount: totalCount,
//       limit: limit,
//       hasNextPage: page < totalPages,
//       hasPrevPage: page > 1
//     };

//     // Use correct count for tabs that show completed installations
//     if (['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       const completedTotalPages = Math.ceil(totalCompletedCount / limit);
//       pagination.totalPages = completedTotalPages;
//       pagination.totalCount = totalCompletedCount;
//       pagination.hasNextPage = page < completedTotalPages;
//     }

//     if (!empty(results) && !['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       reply.send({
//         status: 1,
//         results: filteredProjects,
//         community: community,
//         clients: clients,
//         staffMembers: staffMembers || [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//       });
//     } else if (!empty(completedInstallations) && ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       reply.send({
//         status: 1,
//         results: [],
//         community: community,
//         clients: clients,
//         staffMembers: staffMembers || [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//       });
//     } else if (!empty(results)) {
//       reply.send({
//         status: 1,
//         results: filteredProjects,
//         community: community,
//         clients: clients,
//         staffMembers: staffMembers || [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//       });
//     } else if (!empty(completedInstallations)) {
//       reply.send({
//         status: 1,
//         results: [],
//         community: community,
//         clients: clients,
//         staffMembers: staffMembers || [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//       });
//     } else {
//       reply.send({
//         status: 0,
//         results,
//         community: community,
//         completedInstallations: completedInstallations || [],
//         staffMembers: staffMembers || [],
//         message: "Error fetching data",
//         pagination: pagination,
//       });
//     }
//   } catch (error) {
//     console.log(error);
//     reply.status(500).send("Server error" + error);
//   }
// };

// NEW OPTIMIZED CONTROLLER - Get only project data (results, completedInstallations, pagination)
const getAllProjects = async (request, reply) => {
  try {
    const userType = request.body.userType.value;
    const userId = request.body.userId.value;
    const hasPermission = request.body.hasPermission;
    const sort = request.body.sort;
    const fromDate = request?.body?.from;
    const toDate = request?.body?.to;
    const dueData = request?.body?.dueData;
    const filterProjectType = request?.body?.filterProjectType;
    const currentTab = request?.body?.currentTab;
    const page = Number(request?.body?.page) || 1;
    const limit = Number(request?.body?.limit) || 6;
    const search = request?.body?.search || '';
    const jobClassFilter = request?.body?.jobClassFilter || [];
    const jobTypesFilter = request?.body?.jobTypesFilter || [];
    const clientFilter = request?.body?.clientFilter || [];
    const userFilter = request?.body?.userFilter || [];
    const projectFilter = request?.body?.projectFilter || [];
    const departmentFilter = request?.body?.departmentFilter || [];
    const splitOrder = request?.body?.splitOrder || false;

    const projectTabs = new Set(['Hold', 'Pre-Production', 'Production']);
    const completedTabs = new Set(['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card']);
    const currentTabs = projectTabs.has(currentTab);
    const shouldFetchProjects = currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL';
    const shouldFetchCompletedInstallations = !currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL';
    const shouldSkipInstallationFilter = currentTab === 'ALL' || currentTab === 'Change Order';

    const buildProjectArgs = (tab, currentPage, currentLimit) => ([
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      tab,
      currentPage,
      currentLimit,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
    ]);

    const buildCompletedArgs = (tab, currentPage, currentLimit, forAllTab = false) => ([
      hasPermission,
      true,
      userType,
      userId,
      sort,
      false,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      tab,
      currentPage,
      currentLimit,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
      forAllTab,
    ]);

    const getAllTabComparator = () => {
      if (dueData) {
        return (a, b) => {
          const aDate = a.installation_date ? Number(a.installation_date) : 0;
          const bDate = b.installation_date ? Number(b.installation_date) : 0;
          return aDate - bDate;
        };
      }

      if (sort === 'custom_order') {
        return (a, b) => {
          const aOrder = a.card_order != null ? Number(a.card_order) : Number.MAX_SAFE_INTEGER;
          const bOrder = b.card_order != null ? Number(b.card_order) : Number.MAX_SAFE_INTEGER;
          return aOrder - bOrder;
        };
      }

      if (sort === 'new') {
        return (a, b) => {
          const aId = a.id ? Number(a.id) : 0;
          const bId = b.id ? Number(b.id) : 0;
          return bId - aId;
        };
      }

      if (sort === 'old') {
        return (a, b) => {
          const aId = a.id ? Number(a.id) : 0;
          const bId = b.id ? Number(b.id) : 0;
          return aId - bId;
        };
      }

      if (sort === 'last_updated') {
        return (a, b) => {
          const aTs = a.timestamp ? Number(a.timestamp) : 0;
          const bTs = b.timestamp ? Number(b.timestamp) : 0;
          return bTs - aTs;
        };
      }

      return null;
    };

    let results = [];
    let completedInstallations = [];

    if (currentTab === 'ALL') {
      const tabsUsingProjectCount = ['Hold', 'Pre-Production', 'Production', 'Change Order', 'Rejected'];
      const tabsUsingCompletedCount = ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'];
      const bigLimit = 10000;

      const [projectBuckets, completedBuckets] = await Promise.all([
        Promise.all(
          tabsUsingProjectCount.map((tab) => Project.getAllProjects(...buildProjectArgs(tab, 1, bigLimit)))
        ),
        Promise.all(
          tabsUsingCompletedCount.map((tab) =>
            Project.getAllcompletedInstallations(...buildCompletedArgs(tab, 1, bigLimit, true))
          )
        ),
      ]);

      const allCards = [
        ...projectBuckets.flatMap((tabResults) => (Array.isArray(tabResults) ? tabResults : [])),
        ...completedBuckets.flatMap((tabResults) => (Array.isArray(tabResults) ? tabResults : [])),
      ];

      const comparator = getAllTabComparator();
      if (comparator) {
        allCards.sort(comparator);
      }

      const start = (page - 1) * limit;
      results = allCards.slice(start, start + limit);
    } else {
      const [projectResults, completedResults] = await Promise.all([
        shouldFetchProjects
          ? Project.getAllProjects(...buildProjectArgs(currentTab, page, limit))
          : Promise.resolve([]),
        shouldFetchCompletedInstallations
          ? Project.getAllcompletedInstallations(...buildCompletedArgs(currentTab, page, limit))
          : Promise.resolve([]),
      ]);

      results = Array.isArray(projectResults) ? projectResults : [];
      completedInstallations = Array.isArray(completedResults) ? completedResults : [];
    }

    let filteredProjects = results;
    const needsInstallationFilter = (
      !shouldSkipInstallationFilter &&
      Array.isArray(results) &&
      results.length > 0 &&
      results.some((project) => Number(project.status) === 3)
    );

    if (needsInstallationFilter) {
      const allInstalation = await Installation.fetchAllApointments(
        userId,
        userType,
        hasPermission
      );

      if (Array.isArray(allInstalation) && allInstalation.length > 0) {
        const installedProjectIds = new Set(allInstalation.map((installation) => installation.project_id));

        filteredProjects = results.filter((project) => (
          Number(project.status) !== 3 || !installedProjectIds.has(project.id)
        ));
      }
    }

    const departments = [];
    const pagination = {
      currentPage: page,
      limit: limit,
    };

    const sendSuccess = (responseResults) => reply.send({
      status: 1,
      results: responseResults,
      message: "Data fetched successfully",
      completedInstallations,
      pagination: pagination,
      departments: departments,
    });

    if (!empty(results) && !completedTabs.has(currentTab)) {
      return sendSuccess(filteredProjects);
    }

    if (!empty(completedInstallations)) {
      return sendSuccess([]);
    }

    if (!empty(results)) {
      return sendSuccess(filteredProjects);
    }

    reply.send({
      status: 0,
      results,
      completedInstallations: completedInstallations || [],
      message: "Error fetching data",
      pagination: pagination,
      departments: departments,
    });
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};
// const getAllProjects = async (request, reply) => {
//   try {
//     // let status = 2;
//     let userType = request.body.userType.value;
//     let userId = request.body.userId.value;
//     let hasPermission = request.body.hasPermission;
//     let sort = request.body.sort;
//     let fromDate = request?.body?.from;
//     let toDate = request?.body?.to;
//     let dueData = request?.body?.dueData;
//     let filterProjectType = request?.body?.filterProjectType;
//     let currentTab = request?.body?.currentTab;
//     let page = request?.body?.page || 1;
//     let limit = request?.body?.limit || 6;
//     let search = request?.body?.search || '';
//     let jobClassFilter = request?.body?.jobClassFilter || [];
//     let jobTypesFilter = request?.body?.jobTypesFilter || [];
//     let clientFilter = request?.body?.clientFilter || [];
//     let userFilter = request?.body?.userFilter || [];
//     let projectFilter = request?.body?.projectFilter || [];
//     let departmentFilter = request?.body?.departmentFilter || [];
//     let splitOrder = request?.body?.splitOrder || false;
//     let currentTabs = '';
//     if (currentTab === 'Hold' || currentTab === 'Pre-Production' || currentTab === 'Production') {
//       currentTabs = true;
//     } else {
//       currentTabs = false;
//     }

//     console.log('currentTabs:', currentTabs);
//     let results = [];
//     let completedInstallations = [];

//     if (currentTab === 'ALL') {
//       // Same logic as count: fetch from each tab and combine so list length matches count (147)
//       const tabsUsingProjectCount = ['Hold', 'Pre-Production', 'Production', 'Change Order', 'Rejected'];
//       const tabsUsingCompletedCount = ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'];
//       const bigLimit = 10000;
//       let combinedResults = [];
//       for (const tab of tabsUsingProjectCount) {
//         const tabResults = await Project.getAllProjects(
//           hasPermission,
//           true,
//           userType,
//           userId,
//           null,
//           sort,
//           fromDate,
//           toDate,
//           dueData,
//           filterProjectType,
//           tab,
//           1,
//           bigLimit,
//           search,
//           jobClassFilter,
//           jobTypesFilter,
//           clientFilter,
//           userFilter,
//           projectFilter,
//           departmentFilter,
//           splitOrder,
//         );
//         if (Array.isArray(tabResults)) combinedResults = combinedResults.concat(tabResults);
//       }
//       let combinedCompleted = [];
//       const forAllTab = true;
//       for (const tab of tabsUsingCompletedCount) {
//         const tabCompleted = await Project.getAllcompletedInstallations(
//           hasPermission,
//           true,
//           userType,
//           userId,
//           sort,
//           false,
//           fromDate,
//           toDate,
//           dueData,
//           filterProjectType,
//           tab,
//           1,
//           bigLimit,
//           search,
//           jobClassFilter,
//           jobTypesFilter,
//           clientFilter,
//           userFilter,
//           projectFilter,
//           departmentFilter,
//           splitOrder,
//           forAllTab,
//         );
//         if (Array.isArray(tabCompleted)) combinedCompleted = combinedCompleted.concat(tabCompleted);
//       }
//       // Combine cards from all tabs
//       let allCards = [...combinedResults, ...combinedCompleted];

//       // Apply global sorting across ALL tabs so behaviour matches
//       // individual tabs (including By Due and sort options).
//       if (dueData) {
//         // By Due: order globally by installation_date ascending.
//         allCards = allCards.sort((a, b) => {
//           const aDate = a.installation_date ? Number(a.installation_date) : 0;
//           const bDate = b.installation_date ? Number(b.installation_date) : 0;
//           return aDate - bDate;
//         });
//       } else if (sort === 'custom_order') {
//         allCards = allCards.sort((a, b) => {
//           const aOrder = a.card_order != null ? Number(a.card_order) : Number.MAX_SAFE_INTEGER;
//           const bOrder = b.card_order != null ? Number(b.card_order) : Number.MAX_SAFE_INTEGER;
//           return aOrder - bOrder;
//         });
//       } else if (sort === 'new') {
//         // Newest: order by creation (id DESC)
//         allCards = allCards.sort((a, b) => {
//           const aId = a.id ? Number(a.id) : 0;
//           const bId = b.id ? Number(b.id) : 0;
//           return bId - aId;
//         });
//       } else if (sort === 'old') {
//         // Oldest: order by creation (id ASC)
//         allCards = allCards.sort((a, b) => {
//           const aId = a.id ? Number(a.id) : 0;
//           const bId = b.id ? Number(b.id) : 0;
//           return aId - bId;
//         });
//       } else if (sort === 'last_updated') {
//         // Recently Updated: order by last change (timestamp DESC)
//         allCards = allCards.sort((a, b) => {
//           const aTs = a.timestamp ? Number(a.timestamp) : 0;
//           const bTs = b.timestamp ? Number(b.timestamp) : 0;
//           return bTs - aTs;
//         });
//       }

//       // Paginate over combined, globally-sorted list (same total as count sum)
//       const start = (page - 1) * limit;
//       results = allCards.slice(start, start + limit);
//       completedInstallations = []; // merged into results for ALL tab
//     } else {
//       results = (currentTabs || filterProjectType === 'ALL') ? await Project.getAllProjects(
//         hasPermission,
//         true,
//         userType,
//         userId,
//         null,
//         sort,
//         fromDate,
//         toDate,
//         dueData,
//         filterProjectType,
//         currentTab,
//         page,
//         limit,
//         search,
//         jobClassFilter,
//         jobTypesFilter,
//         clientFilter,
//         userFilter,
//         projectFilter,
//         departmentFilter,
//         splitOrder,
//       ) : [];

//       completedInstallations = (!currentTabs || filterProjectType === 'ALL') ? await Project.getAllcompletedInstallations(
//         hasPermission,
//         true,
//         userType,
//         userId,
//         sort,
//         false,
//         fromDate,
//         toDate,
//         dueData,
//         filterProjectType,
//         currentTab,
//         page,
//         limit,
//         search,
//         jobClassFilter,
//         jobTypesFilter,
//         clientFilter,
//         userFilter,
//         projectFilter,
//         departmentFilter,
//         splitOrder,
//       ) : [];
//     }

//     let allInstalation = await Installation.fetchAllApointments(
//       userId,
//       userType,
//       hasPermission
//     );
//     let departments = [];

//     // console.log('getAllProjects results:', results?.length || 0);
//     // console.log('currentTab:', currentTab);
    
//     // COMMENTED OUT: Unnecessary project members loops
//     // for (const project of results) {
//     //   const projectMembers = await Project.getAllProjectMembers(project.id);
//     //   project.project_members = projectMembers || [];
//     // }
    
//     // for (const project of completedInstallations) {
//     //   const projectMembers = await Project.getAllProjectMembers(project.id);
//     //   project.project_members = projectMembers || [];
//     // }
    
//     let filteredProjects;
//     if (currentTab === 'ALL' || currentTab === 'Change Order') {
//       // For 'ALL' tab and 'Change Order' tab, return all projects without filtering
//       filteredProjects = results;
//     } else {
//       // For specific tabs, filter out projects with installations
//       filteredProjects = results.filter((project) => {
//         return !allInstalation.some(
//           (installation) => installation.project_id === project.id && project.status ==3
//           // (installation) => installation.project_id === project.id
//         );
//       });
//     }

//     // COMMENTED OUT: Unnecessary attachment loading loop
//     // for (const data of completedInstallations) {
//     //   let attachment = await Request.getAllRequestAttachmentsForCards(data.request_id, data.isFromDesignOrder)
//     //   data.attachment = attachment || []
//     // }

//     // COMMENTED OUT: Count logic moved to separate endpoint
//     // let totalCount = (currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getTotalProjectsCount(
//     //   hasPermission,
//     //   true,
//     //   userType,
//     //   userId,
//     //   null,
//     //   sort,
//     //   fromDate,
//     //   toDate,
//     //   dueData,
//     //   filterProjectType,
//     //   currentTab,
//     //   search,
//     //   jobClassFilter,
//     //   jobTypesFilter,
//     //   clientFilter,
//     //   userFilter,
//     //   projectFilter,
//     //   departmentFilter,
//     // ) : 0;
    
//     // let totalCompletedCount = (!currentTabs  || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getTotalCompletedInstallationsCount(
//     //   hasPermission,
//     //   true,
//     //   userType,
//     //   userId,
//     //   sort,
//     //   false,
//     //   fromDate,
//     //   toDate,
//     //   dueData,
//     //   filterProjectType,
//     //   currentTab,
//     //   search,
//     //   jobClassFilter,
//     //   jobTypesFilter,
//     //   clientFilter,
//     //   userFilter,
//     //   projectFilter,
//     //   departmentFilter,
//     // ) : 0;

//     // const totalPages = Math.ceil(totalCount / limit);
//     const pagination = {
//       currentPage: page,
//       // totalPages: totalPages,
//       // totalCount: totalCount,
//       limit: limit,
//       // hasNextPage: page < totalPages,
//       // hasPrevPage: page > 1
//     };

//     // COMMENTED OUT: Count logic moved to separate endpoint
//     // if (['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//     //   const completedTotalPages = Math.ceil(totalCompletedCount / limit);
//     //   pagination.totalPages = completedTotalPages;
//     //   pagination.totalCount = totalCompletedCount;
//     //   pagination.hasNextPage = page < completedTotalPages;
//     // }

//     if (!empty(results) && !['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       reply.send({
//         status: 1,
//         results: filteredProjects,
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//         departments: departments,
//       });
//     } else if (!empty(completedInstallations) && ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       reply.send({
//         status: 1,
//         results: [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//         departments: departments,
//       });
//     } else if (!empty(results)) {
//       reply.send({
//         status: 1,
//         results: filteredProjects,
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//         departments: departments,
//       });
//     } else if (!empty(completedInstallations)) {
//       reply.send({
//         status: 1,
//         results: [],
//         message: "Data fetched successfully",
//         completedInstallations,
//         pagination: pagination,
//         departments: departments,
//       });
//     } else {
//       reply.send({
//         status: 0,
//         results,
//         completedInstallations: completedInstallations || [],
//         message: "Error fetching data",
//         pagination: pagination,
//         departments: departments,
//       });
//     }
//   } catch (error) {
//     console.log(error);
//     reply.status(500).send("Server error" + error);
//   }
// };

const getAllProjectsCommunityCount = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let filterProjectType = request?.body?.filterProjectType;
    let currentTab = request?.body?.currentTab;
    let page = request?.body?.page || 1;
    let limit = request?.body?.limit || 6;
    let search = request?.body?.search || '';
    let jobClassFilter = request?.body?.jobClassFilter || [];
    let jobTypesFilter = request?.body?.jobTypesFilter || [];
    let clientFilter = request?.body?.clientFilter || [];
    let userFilter = request?.body?.userFilter || [];
    let projectFilter = request?.body?.projectFilter || [];
    let departmentFilter = request?.body?.departmentFilter || [];
    let splitOrder = request?.body?.splitOrder || false;
    let currentTabs = '';
    if (currentTab === 'Hold' || currentTab === 'Pre-Production' || currentTab === 'Production') {
      currentTabs = true;
    } else {
      currentTabs = false;
    }

    console.log('currentTabs:', currentTabs);
    let results = (currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getAllProjectsForCommunityCount(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      currentTab,
      page,
      limit,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
    ) : 0;

    console.log('getAllProjectsForCommunityCount results:', results || 0);
    console.log('currentTab:', currentTab);
    console.log('filterProjectType:', filterProjectType);

    let allInstalation = await Installation.fetchAllApointments(
      userId,
      userType,
      hasPermission
    );
    // let community = await Community.getAllCommunitiesWithProjectCount();
    let departments = [] //await Department.getAllDepartments();
    
    let completedInstallations = (!currentTabs  || filterProjectType === 'ALL' || currentTab === 'ALL') ?await Project.getAllcompletedInstallationsForCommunityCount(
      hasPermission,
      true,
      userType,
      userId,
      sort,
      false,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      currentTab,
      page,
      limit,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
    ) : [];
    
    console.log('getAllcompletedInstallations results:', completedInstallations?.length || 0);
        
    let filteredProjects;
    if (currentTab === 'ALL' || currentTab === 'Change Order') {
      // For 'ALL' tab and 'Change Order' tab, return all projects without filtering
      filteredProjects = results || [];
    } else {
      // For specific tabs, filter out projects with installations
      filteredProjects = results?.filter((project) => {
        return !allInstalation.some(
          (installation) => installation.project_id === project.id && project.status ==3
          // (installation) => installation.project_id === project.id
        );
      });
    }

    const pagination = {
      currentPage: page,
      limit: limit,
    };

    if (!empty(results) && !['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
      reply.send({
        status: 1,
        results: filteredProjects?.length || 0,
        message: "Data fetched successfully",
        completedInstallations,
        pagination: pagination,
        departments: departments,
      });
    } else if (!empty(completedInstallations) && ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
      reply.send({
        status: 1,
        results: 0,
        message: "Data fetched successfully",
        completedInstallations: completedInstallations?.length || 0,
        pagination: pagination,
        departments: departments,
      });
    } else if (!empty(results)) {
      reply.send({
        status: 1,
        results: filteredProjects?.length || 0,
        message: "Data fetched successfully",
        completedInstallations: completedInstallations?.length || 0,
        pagination: pagination,
        departments: departments,
      });
    } else if (!empty(completedInstallations)) {
      reply.send({
        status: 1,
        results: 0,
        message: "Data fetched successfully",
        completedInstallations: completedInstallations?.length || 0,
        pagination: pagination,
        departments: departments,
      });
    } else {
      reply.send({
        status: 0,
        results: results?.length || 0,
        completedInstallations: completedInstallations?.length || 0,
        message: "Error fetching data",
        pagination: pagination,
        departments: departments,
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

// Optimized separate endpoint for getting project counts
const getAllProjectsCount = async (request, reply) => {
  try {
    const userType = request.body.userType.value;
    const userId = request.body.userId.value;
    const hasPermission = request.body.hasPermission;
    const sort = request.body.sort;
    const fromDate = request?.body?.from;
    const toDate = request?.body?.to;
    const dueData = request?.body?.dueData;
    const filterProjectType = request?.body?.filterProjectType;
    const currentTab = request?.body?.currentTab;
    const limit = Number(request?.body?.limit) || 6;
    const search = request?.body?.search || '';
    const jobClassFilter = request?.body?.jobClassFilter || [];
    const jobTypesFilter = request?.body?.jobTypesFilter || [];
    const clientFilter = request?.body?.clientFilter || [];
    const userFilter = request?.body?.userFilter || [];
    const projectFilter = request?.body?.projectFilter || [];
    const departmentFilter = request?.body?.departmentFilter || [];
    const splitOrder = request?.body?.splitOrder || false;

    const projectTabs = new Set(['Hold', 'Pre-Production', 'Production']);
    const completedTabs = new Set(['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card']);
    const currentTabs = projectTabs.has(currentTab);
    const shouldFetchProjectCount = currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL';
    const shouldFetchCompletedCount = !currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL';

    const buildProjectCountArgs = (tab) => ([
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      tab,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
    ]);

    const buildCompletedCountArgs = (tab, forAllTab = false) => ([
      hasPermission,
      true,
      userType,
      userId,
      sort,
      false,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      tab,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
      splitOrder,
      forAllTab,
    ]);

    const normalizeCount = (value) => ((value != null && !isNaN(value)) ? Number(value) : 0);

    let totalCount = 0;
    let totalCompletedCount = 0;

    if (currentTab === 'ALL') {
      const tabsUsingProjectCount = ['Hold', 'Pre-Production', 'Production', 'Change Order', 'Rejected'];
      const tabsUsingCompletedCount = ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'];

      const [projectCounts, completedCounts] = await Promise.all([
        Promise.all(
          tabsUsingProjectCount.map((tab) => Project.getTotalProjectsCount(...buildProjectCountArgs(tab)))
        ),
        Promise.all(
          tabsUsingCompletedCount.map((tab) =>
            Project.getTotalCompletedInstallationsCount(...buildCompletedCountArgs(tab, true))
          )
        ),
      ]);

      totalCount = projectCounts.reduce((sum, count) => sum + normalizeCount(count), 0);
      totalCompletedCount = completedCounts.reduce((sum, count) => sum + normalizeCount(count), 0);
    } else {
      const [projectCount, completedCount] = await Promise.all([
        shouldFetchProjectCount
          ? Project.getTotalProjectsCount(...buildProjectCountArgs(currentTab))
          : Promise.resolve(0),
        shouldFetchCompletedCount
          ? Project.getTotalCompletedInstallationsCount(...buildCompletedCountArgs(currentTab))
          : Promise.resolve(0),
      ]);

      totalCount = normalizeCount(projectCount);
      totalCompletedCount = normalizeCount(completedCount);
    }

    const activeCount = currentTab === 'ALL'
      ? totalCount + totalCompletedCount
      : completedTabs.has(currentTab)
        ? totalCompletedCount
        : totalCount;
    const pagination = {
      totalPages: Math.ceil(activeCount / limit),
      totalCount: activeCount,
      limit: limit,
    };

    reply.send({
      status: 1,
      pagination: pagination,
      message: "Count fetched successfully",
    });
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};
// const getAllProjectsCount = async (request, reply) => {
//   try {
//     let userType = request.body.userType.value;
//     let userId = request.body.userId.value;
//     let hasPermission = request.body.hasPermission;
//     let sort = request.body.sort;
//     let fromDate = request?.body?.from;
//     let toDate = request?.body?.to;
//     let dueData = request?.body?.dueData;
//     let filterProjectType = request?.body?.filterProjectType;
//     let currentTab = request?.body?.currentTab;
//     let limit = request?.body?.limit || 6;
//     let search = request?.body?.search || '';
//     let jobClassFilter = request?.body?.jobClassFilter || [];
//     let jobTypesFilter = request?.body?.jobTypesFilter || [];
//     let clientFilter = request?.body?.clientFilter || [];
//     let userFilter = request?.body?.userFilter || [];
//     let projectFilter = request?.body?.projectFilter || [];
//     let departmentFilter = request?.body?.departmentFilter || [];
//     let splitOrder = request?.body?.splitOrder || false;
//     let currentTabs = '';
//     if (currentTab === 'Hold' || currentTab === 'Pre-Production' || currentTab === 'Production') {
//       currentTabs = true;
//     } else {
//       currentTabs = false;
//     }

//     // Get total count for pagination
//     let totalCount = (currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getTotalProjectsCount(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       null,
//       sort,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//       departmentFilter,
//       splitOrder,
//     ) : 0;
    
//     let totalCompletedCount = (!currentTabs  || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getTotalCompletedInstallationsCount(
//       hasPermission,
//       true,
//       userType,
//       userId,
//       sort,
//       false,
//       fromDate,
//       toDate,
//       dueData,
//       filterProjectType,
//       currentTab,
//       search,
//       jobClassFilter,
//       jobTypesFilter,
//       clientFilter,
//       userFilter,
//       projectFilter,
//       departmentFilter,
//       splitOrder,
//     ) : 0;

//     // ALL tab: log each tab's count separately for debugging
//     if (currentTab === 'ALL') {
//       const tabsUsingProjectCount = ['Hold', 'Pre-Production', 'Production', 'Change Order', 'Rejected'];
//       const tabsUsingCompletedCount = ['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'];
//       console.log('--- ALL TAB: Count per tab ---');
//       let sum = 0;
//       const forAllTab = true;
//       for (const tab of tabsUsingProjectCount) {
//         try {
//           const n = await Project.getTotalProjectsCount(hasPermission, true, userType, userId, null, sort, fromDate, toDate, dueData, filterProjectType, tab, search, jobClassFilter, jobTypesFilter, clientFilter, userFilter, projectFilter, departmentFilter, splitOrder);
//           const count = (n != null && !isNaN(n)) ? Number(n) : 0;
//           sum += count;
//           console.log('  ' + tab + ': ' + count);
//         } catch (err) {
//           console.log('  ' + tab + ': ERROR ' + (err && err.message ? err.message : err));
//         }
//       }
//       for (const tab of tabsUsingCompletedCount) {
//         try {
//           const n = await Project.getTotalCompletedInstallationsCount(hasPermission, true, userType, userId, sort, false, fromDate, toDate, dueData, filterProjectType, tab, search, jobClassFilter, jobTypesFilter, clientFilter, userFilter, projectFilter, departmentFilter, splitOrder, forAllTab);
//           const count = (n != null && !isNaN(n)) ? Number(n) : 0;
//           sum += count;
//           console.log('  ' + tab + ': ' + count);
//         } catch (err) {
//           console.log('  ' + tab + ': ERROR ' + (err && err.message ? err.message : err));
//         }
//       }
//       console.log('  --- Sum of all tabs: ' + sum + ' | getTotalProjectsCount(ALL): ' + totalCount + ' ---');
//       totalCount = sum;
//     }

//     let totalPages, pagination;
    
//     // Use correct count for tabs that show completed installations
//     if (['Installs', 'Pickup', 'Shipping', 'Completed', 'T & M Review', 'Cost Card'].includes(currentTab)) {
//       totalPages = Math.ceil(totalCompletedCount / limit);
//       pagination = {
//         totalPages: totalPages,
//         totalCount: totalCompletedCount,
//         limit: limit,
//       };
//     } else {
//       totalPages = Math.ceil(totalCount / limit);
//       pagination = {
//         totalPages: totalPages,
//         totalCount: totalCount,
//         limit: limit,
//       };
//     }

//     reply.send({
//       status: 1,
//       pagination: pagination,
//       message: "Count fetched successfully",
//     });
//   } catch (error) {
//     console.log(error);
//     reply.status(500).send("Server error" + error);
//   }
// };
const getAllEstimateProjects = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let filterProjectType = request?.body?.filterProjectType;
    let currentTab = request?.body?.currentTab;
    let page = request?.body?.page || 1;
    let limit = request?.body?.limit || 6;
    let search = request?.body?.search || '';
    let jobClassFilter = request?.body?.jobClassFilter || [];
    let jobTypesFilter = request?.body?.jobTypesFilter || [];
    let clientFilter = request?.body?.clientFilter || [];
    let userFilter = request?.body?.userFilter || [];
    let projectFilter = request?.body?.projectFilter || [];
    let departmentFilter = request?.body?.departmentFilter || [];
    let currentTabs = '';
    if (currentTab === 'Hold' || currentTab === 'New' || currentTab === 'In Progress' || currentTab === 'Drafts') {
      currentTabs = true;
    } else {
      currentTabs = false;
    }

    console.log('currentTabs:', currentTabs);
    let results = (currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getAllEstimateProjects(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      currentTab,
      page,
      limit,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
    ) : [];

    console.log('getAllProjects results:', results?.length || 0);
    console.log('currentTab:', currentTab);
    console.log('filterProjectType:', filterProjectType);

    let departments = [] //await Department.getAllDepartments();

    let filteredProjects = results;

    const pagination = {
      currentPage: page,
      limit: limit,
    };

    if (!empty(results)) {
      reply.send({
        status: 1,
        results: filteredProjects,
        message: "Data fetched successfully",
        pagination: pagination,
        departments: departments,
      });
    } else {
      reply.send({
        status: 0,
        results,
        message: "Error fetching data",
        pagination: pagination,
        departments: departments,
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllEstimateProjectsCount = async (request, reply) => {
  try {
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let filterProjectType = request?.body?.filterProjectType;
    let currentTab = request?.body?.currentTab;
    let limit = request?.body?.limit || 6;
    let search = request?.body?.search || '';
    let jobClassFilter = request?.body?.jobClassFilter || [];
    let jobTypesFilter = request?.body?.jobTypesFilter || [];
    let clientFilter = request?.body?.clientFilter || [];
    let userFilter = request?.body?.userFilter || [];
    let projectFilter = request?.body?.projectFilter || [];
    let departmentFilter = request?.body?.departmentFilter || [];
    
    let currentTabs = '';
    if (currentTab === 'Hold' || currentTab === 'New' || currentTab === 'In Progress' || currentTab === 'Drafts') {
      currentTabs = true;
    } else {
      currentTabs = false;
    }

    // Get total count for pagination
    let totalCount = (currentTabs || filterProjectType === 'ALL' || currentTab === 'ALL') ? await Project.getTotalEstimateProjectsCount(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      filterProjectType,
      currentTab,
      search,
      jobClassFilter,
      jobTypesFilter,
      clientFilter,
      userFilter,
      projectFilter,
      departmentFilter,
    ) : 0;
    
    let totalPages, pagination;
    
    // Use correct count for tabs that show completed installations
    totalPages = Math.ceil(totalCount / limit);
    pagination = {
      totalPages: totalPages,
      totalCount: totalCount,
      limit: limit,
    };

    reply.send({
      status: 1,
      pagination: pagination,
      message: "Count fetched successfully",
    });
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllProjectsProgress = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let selectedTab = request?.body?.selectedTab;
    
    // DEBUG: Log the selectedTab value to understand what's being received
    console.log('DEBUG - selectedTab received:', selectedTab);
    console.log('DEBUG - selectedTab type:', typeof selectedTab);
    console.log('DEBUG - selectedTab === "movedToInstalls":', selectedTab === 'movedToInstalls');
    let results = await Project.getAllProjectsProgress(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      selectedTab
    );

    // Fetch tasks for each project to show workflow steps
    if (!empty(results)) {
      const resultsWithTasks = await Promise.all(
        results.map(async (project) => {
          try {
            const tasks = await ProjectTask.getAllProjectTasks(
              project.id,
              userId,
              userType,
              hasPermission
            );
            // Only include essential task data for performance
            project.tasks = tasks.map((task) => ({
              ID: task.ID,
              name: task.name,
              status: task.status,
              order_id: task.order_id,
              isTaskInprogress: task.isTaskInprogress,
            }));
            return project;
          } catch (error) {
            console.error(`Error fetching tasks for project ${project.id}:`, error);
            project.tasks = [];
            return project;
          }
        })
      );

      reply.send({
        status: 1,
        results: resultsWithTasks,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        results,
        completedInstallations: [],
        message: "Error fetching data",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error.message);
  }
};

// const getProjectById = async (request, reply) => {
//   try {
//     let id = request.body.id.value;
//     const { userId, userType, hasPermission } = request.body;
//     let projects = await Project.getProjectById(id);
//     let projectCategories = await Project.getAllProjectCategories(true);
//     let projectTypes = await Project.getAllProjectTypes(true);
//     let community = await Community.getAllCommunities();
//     let states = await Project.getAllStates(true);
//     let acceptedRequests = await Project.acceptedRequests(projects.request_id);
//     let projectMembers = await Project.getAllProjectMembers(id);
//     let projectTask = await ProjectTask.getAllProjectTasks(
//       id,
//       userId,
//       userType,
//       hasPermission
//     );
//     let projectAttachments = await Project.fetchAllAttachments(id);
//     let teamMembers = await Project.fetchAllTeamMembers(true);

//     for (const newData of projectTask) {
//       let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(
//         newData.ID,
//         userType,
//         userId
//       );
//       let newUserId = (userType == 1 || userType == 8) ? null : userId;
//       let stafftimelogs = await ProjectTask.fetchStaffTaskTimelog(
//         false,
//         newUserId,
//         newData.ID,
//         false,
//         false
//       );
//       newData.total_hours = 0;
//       let newhours = 0;
//       if (stafftimelogs) {
//         if (false) {
//           // if(projectSubTask?.length > 0){
//           for (const subData of stafftimelogs) {
//             let subTaskArray = subData?.sub_task_id?.split(",") || [];
//             for (const sub of subTaskArray) {
//               for (const data of projectSubTask) {
//                 let hours = 0;
//                 if (parseInt(sub) === data.ID) {
//                   const startMoment = moment.unix(subData.start_time);
//                   let endMoment;
//                   if (subData.end_time !== null) {
//                     endMoment = moment.unix(subData.end_time);
//                   } else {
//                     endMoment = moment();
//                   }
//                   const duration = moment.duration(endMoment.diff(startMoment));
//                   hours = duration.asHours();
//                   if (!isNaN(hours)) {
//                     if (isNaN(data.total_hours)) {
//                       data.total_hours = 0;
//                     }
//                     data.total_hours += hours;
//                   }
//                 }
//               }
//             }
//           }
//         } else {
//           for (const subData of stafftimelogs) {
//             let subTaskArray = subData?.sub_task_id ? subData?.sub_task_id?.split(",") : [] || [];
//             for (const sub of subTaskArray) {
//               let hours = 0;
//               if (parseInt(subData.task_id) === newData.ID) {
//                 const startMoment = moment.unix(subData.start_time);
//                 let endMoment;
//                 if (subData.end_time !== null) {
//                   endMoment = moment.unix(subData.end_time);
//                 } else {
//                   endMoment = moment();
//                 }
//                 const duration = moment.duration(endMoment.diff(startMoment));
//                 hours = duration.asHours();
//                 if (!isNaN(hours)) {
//                   newhours += hours;
//                 }
//               }
//             }
//           }
//         }
//       }
//       if (projectSubTask?.length > 0) {
//         const newhours = projectSubTask.reduce(
//           (total, subtask) => total + (subtask.total_hours || 0),
//           0
//         );
//         newData.total_hours = formatHoursToHHMMSS(newhours);
//       }
//       newData.total_hours = formatHoursToHHMMSS(newhours);
//     }
//     if (userType != 3 && userType != 1 && userType != 8) {
//       let projectTaskFilteredPromises = projectTask.map(async (task) => {
//         let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(task.ID, userType, userId);
//         return projectSubTask.length > 0 || true;
//       });

//       let projectTaskFilteredResults = await Promise.all(projectTaskFilteredPromises);
//       projectTask = projectTask.filter((_, index) => projectTaskFilteredResults[index]);
//     }

//     if (!empty(projects)) {
//       reply.send({
//         status: 1,
//         result: projects,
//         projectCategories,
//         projectTypes,
//         community,
//         states,
//         acceptedRequests,
//         projectMembers,
//         projectTask,
//         projectAttachments,
//         teamMembers,
//       });
//     } else {
//       reply.send({ status: 0, message: "Job not found" });
//     }
//   } catch (error) {
//     console.log("Server error:" + error);
//     reply.status(500).send("Server error:" + error);
//   }
// };

const fetchMirroredProjectFromFacility = async ({
  originRequestId,
  userId,
  userType,
  hasPermission,
  targetFacilityId
}) => {
  const targetFacility = filteredSignwiseInstalations.find(
    f => f.id === Number(targetFacilityId)
  );

  if (!targetFacility?.url) return null;

const targetProjectId = await SplitManagementModel.getProjectIdFromOtherFacility(targetFacilityId, originRequestId);


  // 🔹 STEP 2: Fetch project using resolved ID
  const projectResponse = await axios.post(
    `${targetFacility.url}project/get-project-by-id`,
    {
      id: { value: targetProjectId },
      userId,
      userType,
      hasPermission
    }
  );

  return projectResponse?.data || null;
};

const getProjectById = async (request, reply) => {
  try {
    let id = request.body.id.value;
    const { userId, userType, hasPermission } = request.body;
    let projects = await Project.getProjectById(id);
    const originRequestId = projects?.request_id;
    let isSplit = projects?.is_split_order;
    const facilityTypes = (projects?.facility_type || "")
      .split(",")
      .map(v => v.trim())
      .filter(v => v !== ""); // Remove empty strings
    let mirrorFacility = projects?.for_parent_facility == 2 ? true : false;
    const targettedFacilityId = facilityTypes.filter(id => id !== String(FACILITY_ID));

    if (isSplit && mirrorFacility && targettedFacilityId.length > 0) {
      const mirroredData = await fetchMirroredProjectFromFacility({
        originRequestId: projects?.origin_facility_request_id,
        userId,
        userType,
        hasPermission,
        targetFacilityId: targettedFacilityId[0], // usually one
      });

      if (mirroredData) {
        reply.send({
          status: 1,
          result: mirroredData.result,
          projectCategories: mirroredData.projectCategories,
          projectTypes: mirroredData.projectTypes,
          community: mirroredData.community,
          states: mirroredData.states,
          acceptedRequests: mirroredData.acceptedRequests,
          projectMembers: mirroredData.projectMembers,
          projectTask: mirroredData.projectTask,
          projectAttachments: mirroredData.projectAttachments,
          teamMembers: mirroredData.teamMembers,
          originRequestId: originRequestId,
          originParentRequestId: projects?.origin_facility_request_id,
        });
        return;
      }
    }

    let projectCategories = await Project.getAllProjectCategories(true);
    let projectTypes = await Project.getAllProjectTypes(true);
    let community = await Community.getAllCommunities();
    let states = await Project.getAllStates(true);
    let acceptedRequests = await Project.acceptedRequests(projects.request_id);
    let projectMembers = await Project.getAllProjectMembers(id);
    let projectTask = await ProjectTask.getAllProjectTasks(
      id,
      userId,
      userType,
      hasPermission
    );
    let projectAttachments = await Project.fetchAllAttachments(id);
    let teamMembers = await Project.fetchAllTeamMembers(true);

    for (const newData of projectTask) {
      let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(
        newData.ID,
        userType,
        userId
      );
      let newUserId = (userType == 1 || userType == 8) ? null : userId;
      let stafftimelogs = await ProjectTask.fetchStaffTaskTimelog(
        false,
        newUserId,
        newData.ID,
        false,
        false
      );
      newData.total_hours = 0;
      let newhours = 0;
      if (stafftimelogs) {
        if (false) {
          // if(projectSubTask?.length > 0){
          for (const subData of stafftimelogs) {
            let subTaskArray = subData?.sub_task_id?.split(",") || [];
            for (const sub of subTaskArray) {
              for (const data of projectSubTask) {
                let hours = 0;
                if (parseInt(sub) === data.ID) {
                  const startMoment = moment.unix(subData.start_time);
                  let endMoment;
                  if (subData.end_time !== null) {
                    endMoment = moment.unix(subData.end_time);
                  } else {
                    endMoment = moment();
                  }
                  const duration = moment.duration(endMoment.diff(startMoment));
                  hours = duration.asHours();
                  if (!isNaN(hours)) {
                    if (isNaN(data.total_hours)) {
                      data.total_hours = 0;
                    }
                    data.total_hours += hours;
                  }
                }
              }
            }
          }
        } else {
          for (const subData of stafftimelogs) {
            let subTaskArray = subData?.sub_task_id ? subData?.sub_task_id?.split(",") : [] || [];
            for (const sub of subTaskArray) {
              let hours = 0;
              if (parseInt(subData.task_id) === newData.ID) {
                const startMoment = moment.unix(subData.start_time);
                let endMoment;
                if (subData.end_time !== null) {
                  endMoment = moment.unix(subData.end_time);
                } else {
                  endMoment = moment();
                }
                const duration = moment.duration(endMoment.diff(startMoment));
                hours = duration.asHours();
                if (!isNaN(hours)) {
                  newhours += hours;
                }
              }
            }
          }
        }
      }
      if (projectSubTask?.length > 0) {
        const newhours = projectSubTask.reduce(
          (total, subtask) => total + (subtask.total_hours || 0),
          0
        );
        newData.total_hours = formatHoursToHHMMSS(newhours);
      }
      newData.total_hours = formatHoursToHHMMSS(newhours);
    }
    if (userType != 3 && userType != 1 && userType != 8) {
      let projectTaskFilteredPromises = projectTask.map(async (task) => {
        let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(task.ID, userType, userId);
        return projectSubTask.length > 0 || true;
      });

      let projectTaskFilteredResults = await Promise.all(projectTaskFilteredPromises);
      projectTask = projectTask.filter((_, index) => projectTaskFilteredResults[index]);
    }

    if (!empty(projects)) {
      const formattedDescription = (projects.description || '').replace(/\r?\n/g, '\n');
      projects.description = formattedDescription;
      projects.description_lines = formattedDescription ? formattedDescription.split('\n') : [];

      reply.send({
        status: 1,
        result: projects,
        projectCategories,
        projectTypes,
        community,
        states,
        acceptedRequests,
        projectMembers,
        projectTask,
        projectAttachments,
        teamMembers,
      });
    } else {
      reply.send({ status: 0, message: "Job not found" });
    }
  } catch (error) {
    console.log("Server error:" + error);
    reply.status(500).send("Server error:" + error);
  }
};

const getAllProjectCategories = async (request, reply) => {
  let projectCategories = await Project.getAllProjectCategories(true);
  let projectTypes = await Project.getAllProjectTypes(true);
  reply.send({
    status: 1,
    projectCategories,
    projectTypes,
    message: "Data fetched successfully",
  });
};
const getAllNoChargeTypes = async (request, reply) => {
  let AllNoChargeType = await Project.getAllNoChargeTypes(true);
  reply.send({
    status: 1,
    AllNoChargeType,
    message: "Data fetched successfully",
  });
};
/////////////////////////////////Quickbooks
const addClassToQuickBooks = async (classData,isEdit=false) => {
  try {
    if(isEdit){
      const existingClassId = await findClassByName(classData.name)
      if(existingClassId){
        return existingClassId
      }
    }
    console.log('Refreshing access token...');
    const token = await getNewAccessToken();

    const apiUrl = PRODUCTION 
      ? `https://quickbooks.api.intuit.com/v3/company/${realmId}/class` 
      : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}/class`;

    // QuickBooks class data structure
    let quickBooksClassData = {
      Name: classData.name, // Name of the class to add
      Active: true, // Set to true to mark the class as active
      SubClass: classData?.subClass ? true : false, // If the class has a parent class
      ParentRef: classData?.parentClassId ? { value: String(classData.parentClassId) } : undefined, // Parent class reference
    };

    console.log("QuickBooks Class Data:", JSON.stringify(quickBooksClassData, null, 2));

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

    if (response.status === 200) {
      const classQbId = response.data.Class.Id;
      console.log("Class has been successfully added to QuickBooks:", response.data);
      return classQbId;
    } else {
      console.error("Failed to add the class to QuickBooks:", response.data);
      return null;
    }
  } catch (error) {
    console.error("Error adding class to QuickBooks:", error.response ? error.response.data : error.message);
    const faultType = error.response?.data?.Fault?.type;
    if (faultType === 'ValidationFault') {
      console.error("Validation error adding class to QuickBooks:", JSON.stringify(error.response?.data, null, 2));
    } else {
      console.error("Other error adding class to QuickBooks:", error.response?.data || error.message);
    }
    return null;
  }
};

const updateClassInQuickBooks = async (classId, classData) => {
  try {
    console.log('Refreshing access token for update...', classData);
    const token = await getNewAccessToken();

    // Step 1: Fetch the existing class to get SyncToken (required for updates)
    const getClassUrl = PRODUCTION 
      ? `https://quickbooks.api.intuit.com/v3/company/${realmId}/class/${classId}` 
      : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}/class/${classId}`;

    const getResponse = await axios.get(getClassUrl, {
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
        Accept: 'application/json'
      }
    });

    if (getResponse.status !== 200 || !getResponse.data.Class) {
      console.error("Failed to fetch existing class from QuickBooks:", getResponse.data);
      return null;
    }

    const existingClass = getResponse.data.Class;

    // Step 2: Build the update payload with required fields (Id and SyncToken)
    let quickBooksClassData = {
      Id: existingClass.Id,
      SyncToken: existingClass.SyncToken, // Required for updates
      Name: classData.name, // Updated name of the class
      Active: classData.active !== undefined ? classData.active : (existingClass.Active !== undefined ? existingClass.Active : true),
      SubClass: classData.subClass !== undefined ? classData.subClass : (existingClass.SubClass || false),
      sparse: true, // Perform a partial update
    };

    // Only include ParentRef if it's being updated or exists
    if (classData.parentClassId) {
      quickBooksClassData.ParentRef = { value: String(classData.parentClassId) };
      quickBooksClassData.SubClass = true;
    } else if (existingClass.ParentRef) {
      quickBooksClassData.ParentRef = existingClass.ParentRef;
    }

    console.log("QuickBooks Class Update Data:", JSON.stringify(quickBooksClassData, null, 2));

    // Step 3: POST to the update endpoint (not PUT)
    const updateUrl = PRODUCTION 
      ? `https://quickbooks.api.intuit.com/v3/company/${realmId}/class?operation=update` 
      : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}/class?operation=update`;

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

    if (response.status === 200) {
      console.log("Class has been successfully updated in QuickBooks:", response.data);
      return response.data.Class.Id; // Returning the updated class ID
    } else {
      console.error("Failed to update the class in QuickBooks:", response.data);
      return null;
    }
  } catch (error) {
    console.error("Error updating class in QuickBooks:", error.response ? error.response.data : error.message);
    const faultType = error.response?.data?.Fault?.type;
    if (faultType === 'ValidationFault') {
      console.error("Validation error updating class in QuickBooks:", JSON.stringify(error.response?.data, null, 2));
    } else {
      console.error("Other error updating class in QuickBooks:", error.response?.data || error.message);
    }
    return null;
  }
};

const findClassByName = async (name) => {
  try {
    console.log('Refreshing access token to find class by name...', name);
    const token = await getNewAccessToken();

    const apiUrl = PRODUCTION 
      ? `https://quickbooks.api.intuit.com/v3/company/${realmId}/query` 
      : `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}/query`;

    // Query QuickBooks for the class based on its name
    const query = `SELECT * FROM Class WHERE Name = '${name}'`;  // SQL-like query syntax

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

    if (response.status === 200) {
      const classes = response.data.QueryResponse.Class;
      
      if (classes && classes.length > 0) {
        const foundClass = classes[0]; // Assuming there's only one match
        console.log("Class found:", foundClass);
        return foundClass.Id; // Return the class ID
      } else {
        console.log(`Class with name "${name}" not found.`);
        return null;
      }
    } else {
      console.error("Failed to fetch classes from QuickBooks:", response.data);
      return null;
    }
  } catch (error) {
    console.error("Error finding class by name:", error.response ? error.response.data : error.message);
    if (error.response?.data?.Fault) {
      console.error("QuickBooks Fault:", JSON.stringify(error.response.data.Fault, null, 2));
    }
    return null;
  }
};
// (async () => {
//   let qbid = 1147863
//   let classData ={
//     name: "skyniche job class",
//   }
//   const classId = await findClassByName(classData)
//   console.log("classId",classId)
// })()
/////////////////////////////////

const addProjectType = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  console.log("Project-----------------", moment().unix());
  projectType["name"] = req.body.name;
  projectType["timestamp"] = moment().unix();
  projectType["added_by"] = req.body.userId;
  projectType["status"] = 1;
  let projectNameExist = await Project.isProjectTypeExist(projectType["name"]);
  if (!projectNameExist) {
    try{
      let qbResult = await addClassToQuickBooks(projectType)
      if (qbResult) {
        projectType['quickBookId'] = qbResult
      }
    } catch (error) {
      console.log("qb error",error)
    }
    let projectTypeId = await Project.addProjectType(projectType);
    console.log("Project12333333333-----------------", projectTypeId);
    if (projectTypeId) {
      console.log("Project12333333333-----------------");
      let notificationMsg = `New job type "${projectType.name}" has been added.`;
      let notificationUrl = "projects";
      const incrementResult_User = await Admin.incrementField(
        projectType.added_by,
        "noti_count",
        1
      );
      console.log("incrementResult--to--user-----------", incrementResult_User);
      let notificationData_user = {
        user_id: projectType.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: projectType.added_by,
      };
      console.log("notificationData--user------------", notificationData_user);
      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );
      console.log(
        "addNotificationResult--user-------",
        addNotificationResult_user
      );
      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      console.log("adminIds====", adminIds);
      for (const adminId of adminIds) {
        console.log("adminId----------", adminId);
        if (adminId != projectType.added_by) {
          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: projectType.added_by,
          };
          console.log("notificationData------------", notificationData);
          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
          console.log("addNotificationResult-------", addNotificationResult);
        }
      }
      reply.send({
        status: 1,
        message: "Job Type has been  added successfully!.",
      });
    } else {
      reply.send({ status: 0, message: "Failed to add the job" });
    }
  }
};
const getProjectTypeById = async (req, reply) => {
  let projectTypeId = req.body.id;
  let projectType = await Project.getProjectTypeById(id);
  if (!empty(projectType)) {
    reply.send({ status: 1, result: projectType });
  } else {
    reply.send({ status: 0, message: "Job Type not found" });
  }
};
const editProjectType = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  let projectTypeId = req.body.id;
  projectType["name"] = req.body.name;

  let projectNameExist = await Project.isProjectTypeExist(
    projectType["name"],
    projectTypeId
  );
  if (!projectNameExist) {
    try{
      const ExistingQbId = req.body.quickbookId
      let qbResult =ExistingQbId ? await updateClassInQuickBooks(ExistingQbId, projectType) : await addClassToQuickBooks(projectType,isEdit=true)
      if (qbResult && !ExistingQbId) {
        projectType['quickBookId'] = qbResult
      }
    } catch (error) {
      console.log("qb error",error)
    }
    let projectTypeData = await Project.updateProjectType(
      projectType,
      projectTypeId
    );

    if (projectTypeData) {
      let notificationMsg = `Job Type "${projectType.name}" has been added.`;
      let notificationUrl = "projects/project-types";
      const incrementResult_User = await Admin.incrementField(
        req.body.added_by,
        "noti_count",
        1
      );

      let notificationData_user = {
        user_id: req.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: req.body.added_by,
      };

      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};

      for (const adminId of adminIds) {
        if (adminId != req.body.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: req.body.added_by,
          };

          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
        }
      }
      reply.send({
        status: 1,
        message: "Job Type has been  updated successfully!.",
      });
    } else {
      reply.send({ status: 0, message: "Failed to update job type." });
    }
  }
};
const deleteProjectType = async (request, reply) => {
  try {
    let { id, status } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    if (!empty(id)) {
      let projectType = await Project.getProjectTypeById(id);

      if (status == 2) {
        let deleted = await Project.deleteProjectType(id);

        if (deleted) {
          // // Notification
          let notificationMsg = `The job Type  "${projectType.name}" has been deleted.`;
          let notificationUrl = "projects";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 1,
            message: `The job type "${projectType.name}" has been deleted successfully!`,
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the product!` });
        }
      } else if (status == 1) {
        let deleted = await Project.updateProjectType({ status: status }, id);

        if (deleted) {
          // // Notification
          let notificationMsg = `The job "${projectType.name}" has been made active.`;
          let notificationUrl = "products";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 2,
            message: `The job "${projectType.name}" has been made active!`,
          });
        } else {
          reply.send({ status: 3, message: "Unable to activate the job!" });
        }
      } else if (status == 0) {
        let deleted = await Project.updateProjectType({ status: status }, id);

        if (deleted) {
          // Notification
          let notificationMsg = `The Job "${projectType.name}" has been made inactive.`;
          let notificationUrl = "products";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }

          reply.send({
            status: 4,
            message: `The job "${projectType.name}" has been made Inactive!`,
          });
        } else {
          reply.send({
            status: 5,
            message: "Unable to deactivate the job!",
          });
        }
      }
    } else {
      console.log("Error................");
      reply.send({ status: 500, message: "Error!" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};
const addProjectCategory = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  console.log("Project-----------------", moment().unix());
  projectType["name"] = req.body.name;
  projectType["timestamp"] = moment().unix();
  projectType["added_by"] = req.body.userId;
  projectType["status"] = 1;
  let projectNameExist = await Project.isProjectCategoryExist(
    projectType["name"]
  );
  if (!projectNameExist) {
    let projectTypeId = await Project.addProjectCategory(projectType);
    console.log("Project12333333333-----------------", projectTypeId);
    if (projectTypeId) {
      console.log("Project12333333333-----------------");
      let notificationMsg = `New job Category "${projectType.name}" has been added.`;
      let notificationUrl = "projects";
      const incrementResult_User = await Admin.incrementField(
        projectType.added_by,
        "noti_count",
        1
      );
      console.log("incrementResult--to--user-----------", incrementResult_User);
      let notificationData_user = {
        user_id: projectType.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: projectType.added_by,
      };
      console.log("notificationData--user------------", notificationData_user);
      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );
      console.log(
        "addNotificationResult--user-------",
        addNotificationResult_user
      );
      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      console.log("adminIds====", adminIds);
      for (const adminId of adminIds) {
        console.log("adminId----------", adminId);
        if (adminId != projectType.added_by) {
          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: projectType.added_by,
          };
          console.log("notificationData------------", notificationData);
          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
          console.log("addNotificationResult-------", addNotificationResult);
        }
      }
      reply.send({
        status: 1,
        message: "Job Category has been  added successfully!.",
      });
    } else {
      reply.send({ status: 0, message: "Failed to add the job" });
    }
  }
};
const addNoChargeType = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  console.log("Project-----------------", moment().unix());
  projectType["name"] = req.body.name;
  projectType["timestamp"] = moment().unix();
  projectType["added_by"] = req.body.userId;
  projectType["status"] = 1;
  let projectNameExist = await Project.isNoChargeTypeExist(
    projectType["name"]
  );
  if (!projectNameExist) {
    let projectTypeId = await Project.addNoChargeType(projectType);
    console.log("Project12333333333-----------------", projectTypeId);
    if (projectTypeId) {
      console.log("Project12333333333-----------------");
      let notificationMsg = `New No charge type "${projectType.name}" has been added.`;
      let notificationUrl = "projects";
      const incrementResult_User = await Admin.incrementField(
        projectType.added_by,
        "noti_count",
        1
      );
      console.log("incrementResult--to--user-----------", incrementResult_User);
      let notificationData_user = {
        user_id: projectType.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: projectType.added_by,
      };
      console.log("notificationData--user------------", notificationData_user);
      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );
      console.log(
        "addNotificationResult--user-------",
        addNotificationResult_user
      );
      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      console.log("adminIds====", adminIds);
      for (const adminId of adminIds) {
        console.log("adminId----------", adminId);
        if (adminId != projectType.added_by) {
          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: projectType.added_by,
          };
          console.log("notificationData------------", notificationData);
          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
          console.log("addNotificationResult-------", addNotificationResult);
        }
      }
      reply.send({
        status: 1,
        message: `No charge type has been  added successfully!.`,
      });
    } else {
      reply.send({ status: 0, message: "Failed to add No charge type" });
    }
  }
};
const getProjectCategoryById = async (req, reply) => {
  let projectTypeId = req.body.id;
  let projectType = await Project.getProjectCategoryById(id);
  if (!empty(projectType)) {
    reply.send({ status: 1, result: projectType });
  } else {
    reply.send({ status: 0, message: "Job Category not found" });
  }
};
const editProjectCategory = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  let projectTypeId = req.body.id;
  projectType["name"] = req.body.name;

  let projectNameExist = await Project.isProjectCategoryExist(
    projectType["name"],
    projectTypeId
  );
  if (!projectNameExist) {
    let projectCategory = await Project.updateProjectCategory(
      projectType,
      projectTypeId
    );

    if (projectCategory) {
      let notificationMsg = `Job Category "${projectType.name}" has been added.`;
      let notificationUrl = "projects/project-types";
      const incrementResult_User = await Admin.incrementField(
        projectType.added_by,
        "noti_count",
        1
      );

      let notificationData_user = {
        user_id: req.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: req.body.added_by,
      };

      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};

      for (const adminId of adminIds) {
        if (adminId != req.body.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: req.body.added_by,
          };

          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
        }
      }
      reply.send({
        status: 1,
        message: "Job Category has been  updated successfully!.",
      });
    } else {
      reply.send({ status: 0, message: "Failed to update job Category." });
    }
  }
};
const editNoChargeType = async (req, reply) => {
  let projectType = {};
  let currentDate = Math.round(moment().valueOf() / 1000);
  let projectTypeId = req.body.id;
  projectType["name"] = req.body.name;

  let projectNameExist = await Project.isNoChargeTypeExist(
    projectType["name"],
    projectTypeId
  );
  if (!projectNameExist) {
    let projectCategory = await Project.updateNoChargeType(
      projectType,
      projectTypeId
    );

    if (projectCategory) {
      let notificationMsg = `No charge type "${projectType.name}" has been added.`;
      let notificationUrl = "projects/project-types";
      const incrementResult_User = await Admin.incrementField(
        projectType.added_by,
        "noti_count",
        1
      );

      let notificationData_user = {
        user_id: req.body.added_by,
        url: notificationUrl,
        timestamp: currentDate,
        message: notificationMsg,
        status: 1,
        from_id: req.body.added_by,
      };

      const addNotificationResult_user = await Admin.addNotification(
        notificationData_user
      );

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};

      for (const adminId of adminIds) {
        if (adminId != req.body.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: req.body.added_by,
          };

          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
        }
      }
      reply.send({
        status: 1,
        message: "No charge type has been  updated successfully!.",
      });
    } else {
      reply.send({ status: 0, message: "Failed to update No charge type." });
    }
  }
};
const deleteProjectCategory = async (request, reply) => {
  try {
    let { id, status } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    if (!empty(id)) {
      let projectType = await Project.getProjectCategoryById(id);

      if (status == 2) {
        let deleted = await Project.deleteProjectCategory(id);

        if (deleted) {
          // // Notification
          let notificationMsg = `The Job Category  "${projectType.name}" has been deleted.`;
          let notificationUrl = "projects";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 1,
            message: `The Job type "${projectType.name}" has been deleted successfully!`,
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the Job type!` });
        }
      } else if (status == 1) {
        let deleted = await Project.updateProjectCategory(
          { status: status },
          id
        );

        if (deleted) {
          // // Notification
          let notificationMsg = `The Job "${projectType.name}" has been made active.`;
          let notificationUrl = "products";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 2,
            message: `The Job "${projectType.name}" has been made active!`,
          });
        } else {
          reply.send({ status: 3, message: "Unable to activate the Job!" });
        }
      } else if (status == 0) {
        let deleted = await Project.updateProjectCategory(
          { status: status },
          id
        );

        if (deleted) {
          // Notification
          let notificationMsg = `The Job "${projectType.name}" has been made inactive.`;
          let notificationUrl = "projects";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }

          reply.send({
            status: 4,
            message: `The Job "${projectType.name}" has been made Inactive!`,
          });
        } else {
          reply.send({
            status: 5,
            message: "Unable to deactivate the Job!",
          });
        }
      }
    } else {
      console.log("Error................");
      reply.send({ status: 500, message: "Error!" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};
const deleteNoChargeType = async (request, reply) => {
  try {
    let { id, status } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    if (!empty(id)) {
      let projectType = await Project.getNoChargeTypeById(id);

      if (status == 2) {
        let deleted = await Project.deleteNoChargeType(id);

        if (deleted) {
          // // Notification
          let notificationMsg = `The No charge type  "${projectType.name}" has been deleted.`;
          let notificationUrl = "projects";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 1,
            message: `The No charge type "${projectType.name}" has been deleted successfully!`,
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the No charge type!` });
        }
      } else if (status == 1) {
        let deleted = await Project.updateProjectCategory(
          { status: status },
          id
        );

        if (deleted) {
          // // Notification
          let notificationMsg = `The No charge type "${projectType.name}" has been made active.`;
          let notificationUrl = "products";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
          reply.send({
            status: 2,
            message: `The No charge type "${projectType.name}" has been made active!`,
          });
        } else {
          reply.send({ status: 3, message: "Unable to activate the No charge type!" });
        }
      } else if (status == 0) {
        let deleted = await Project.updateNoChargeType(
          { status: status },
          id
        );

        if (deleted) {
          // Notification
          let notificationMsg = `The No charge type "${projectType.name}" has been made inactive.`;
          let notificationUrl = "projects";

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};

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

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

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }

          reply.send({
            status: 4,
            message: `The No charge type "${projectType.name}" has been made Inactive!`,
          });
        } else {
          reply.send({
            status: 5,
            message: "Unable to deactivate the No charge type!",
          });
        }
      }
    } else {
      console.log("Error................");
      reply.send({ status: 500, message: "Error!" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};
const viewProjectTask = async (req, reply) => {
  let { taskId, projectId, userId, isMirrored = false, targetFacilityId = null } = req.body;

  console.log('isMirrored', isMirrored)
  // if condition for mirrored project
  if(isMirrored && targetFacilityId){
    const targetFacility = filteredSignwiseInstalations.find(
      f => f.id === Number(targetFacilityId)
    );
    if (!targetFacility?.url) return null;
    console.log('targetFacility?.url',targetFacility?.url)
  const projectResponse = await axios.post(
    `${targetFacility.url}project/view-project-task`,
    {
      taskId: taskId,
      userId : userId,
      projectId:projectId
    }
  );
  if (projectResponse?.data) {
    const mirroredData = projectResponse.data;

    // Send the mirrored data response in the same structure as the provided code
    reply.send({
      status: 1,
      result: mirroredData?.result,
      projectMembers:mirroredData?.projectMembers,
      projectPost:mirroredData?.projectPost,
      msg: "Job task fetched successfully",// Assuming originRequestId is in the mirrored data
    });
    return;
  }}
  let projectTask = await ProjectTask.getProjectTaskBytaskId(taskId);
  let projectMembers = await Project.getAllProjectMembers(projectId);
  let projectPost = null;
  if (userId) {
    projectPost = await ProjectPost.getAllProjectPostsByTask(taskId, userId);
  }
  console.log("##############Project22", projectPost);
  if (projectTask) {
    reply.send({
      status: 1,
      result: projectTask,
      projectMembers,
      projectPost,
      msg: "Job task fetched successfully",
    });
  } else {
    reply.send({
      status: 0,
      projectMembers,
      msg: "Failed to fetch job task",
    });
  }
};
const addProjectMember = async (req, reply) => {
  try {
    let { projectId, projectMembers } = req.body;
    let projects = await Project.getProjectById(projectId);
    let success = false;
    let pmData = {};
    for (const pm of projectMembers) {
      pmData = {
        project_id: projectId,
        staff_id: !empty(pm["id"]) ? pm["id"] : 0,
        partner_id: null,
        contact_id: null,
        lead_id: null,
      };

      let insertId = await Project.addProjectMember(pmData);
      // const incrementResult_User = await Admin.incrementField(projectManager.user_id, "noti_count", 1);

      // let notificationData_user = {
      //     user_id: projectMembers.id,
      //     url: notificationUrl,
      //     timestamp: currentDate,
      //     message: "has assigned you to the project: " + projects.name,
      //     status: 1,
      //     from_id: projects.added_by,
      // };

      // const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      if (insertId) success = true;
    }
    if (success) {
      reply.send({ status: 1, msg: "New members added to job " });
    } else {
      reply.send({ status: 0, msg: "Failed to add new members" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};

const assignNewMembersToSubtasksBySkill = async (req, reply) => {
  try {
    const projectId = Number(req.body?.projectId);
    const memberIds = (req.body?.memberIds || [])
      .map((id) => Number(id))
      .filter((id) => Number.isFinite(id) && id > 0);

    if (!Number.isFinite(projectId) || projectId <= 0) {
      return reply.send({ status: 0, msg: "Invalid projectId" });
    }

    if (!memberIds.length) {
      return reply.send({
        status: 1,
        msg: "No new members to sync",
        matched: 0,
        inserted: 0,
        skippedExisting: 0,
      });
    }

    const subtasks = await ProjectTask.getProjectSubTasksWithSkillsByProjectId(projectId);
    if (!subtasks.length) {
      return reply.send({
        status: 1,
        msg: "No subtasks found for this job",
        matched: 0,
        inserted: 0,
        skippedExisting: 0,
      });
    }

    // Use MySQL FIND_IN_SET (same as get-all-users-by-service), not JS parsing of sm.services
    const pairsToInsert = await ProjectTask.getSubtaskStaffPairsBySkillFindInSet(
      projectId,
      memberIds,
      subtasks
    );

    if (!pairsToInsert.length) {
      return reply.send({
        status: 1,
        msg: "No skill-based subtask match found",
        matched: 0,
        inserted: 0,
        skippedExisting: 0,
      });
    }

    const uniquePairs = [];
    const seenPairs = new Set();
    for (const pair of pairsToInsert) {
      const key = `${pair.subtask_id}:${pair.staff_id}`;
      if (seenPairs.has(key)) continue;
      seenPairs.add(key);
      uniquePairs.push(pair);
    }

    const existingPairs = await ProjectTask.getExistingProjectSubTaskMemberPairs(
      [...new Set(uniquePairs.map((pair) => pair.subtask_id))],
      [...new Set(uniquePairs.map((pair) => pair.staff_id))]
    );
    const existingPairSet = new Set(
      (existingPairs || []).map((pair) => `${Number(pair.subtask_id)}:${Number(pair.staff_id)}`)
    );

    let inserted = 0;
    let skippedExisting = 0;
    for (const pair of uniquePairs) {
      const key = `${pair.subtask_id}:${pair.staff_id}`;
      if (existingPairSet.has(key)) {
        skippedExisting += 1;
        continue;
      }
      const created = await ProjectTask.AddMembersToSubTask(pair);
      if (created) inserted += 1;
    }

    return reply.send({
      status: 1,
      msg: "Skill-based subtask member sync completed",
      matched: uniquePairs.length,
      inserted,
      skippedExisting,
    });
  } catch (error) {
    console.error("assignNewMembersToSubtasksBySkill error", error);
    return reply.status(500).send({ status: 0, msg: "Server error" });
  }
};
const viewAllProjectSubTask = async (req, reply) => {
  try {
    let { taskId, userType, userId, isMirrored = false, targetFacilityId = null,filterSubTask = false,teamId = null } = req.body;

    // if condition for mirrored project
    if(isMirrored && targetFacilityId){
      const targetFacility = filteredSignwiseInstalations.find(
        f => f.id === Number(targetFacilityId)
      );
      if (!targetFacility?.url) return null;
      console.log('targetFacility?.url',targetFacility?.url)
    const projectResponse = await axios.post(
      `${targetFacility.url}project/fetch-all-project-sub-task`,
      {
        taskId: taskId,
        userId : userId,
        userType:userType,
        filterSubTask:filterSubTask,
        teamId:teamId
      }
    );
    if (projectResponse?.data) {
      const mirroredData = projectResponse.data;
  
      // Send the mirrored data response in the same structure as the provided code
      reply.send({
        status: 1,
        result: mirroredData?.result,
        skills:mirroredData?.skills,
        msg: "Job sub tasks fetched successfully",
      });
      return;
    }}
  let projectSubTask = null;
  if(teamId){
    projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskIdWithTeam(
      taskId,
      userType,
      userId,
      teamId
    );
  }else{
    projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(
      taskId,
      userType,
      userId
    );
  }
    // let skills = await ProjectTask.projectSubTaskSkills(taskId,filterSubTask,teamId);
    let skills = await ProjectTask.projectSubTaskSkills(taskId);
    let newUserId = (userType == 1 || userType == 8) ? null : userId;
    let stafftimelogs = await ProjectTask.fetchStaffTaskTimelog(
      false,
      newUserId,
      taskId,
      false,
      false
    );
    if (stafftimelogs) {
      console.log('stafftimelogs================', stafftimelogs);
      for (const subData of stafftimelogs) {
        let subTaskArray = subData?.sub_task_id ? subData?.sub_task_id?.split(",") : [] || [];
        for (const sub of subTaskArray) {
          for (const data of projectSubTask) {
            let hours = 0;
            if (parseInt(sub) === data.ID) {
              const startMoment = moment.unix(subData.start_time);
              let endMoment;
              if (subData.end_time !== null) {
                endMoment = moment.unix(subData.end_time);
              } else {
                endMoment = moment();
              }
              const duration = moment.duration(endMoment.diff(startMoment));
              hours = duration.asHours();
              console.log("hours---", hours);
              if (!isNaN(hours)) {
                if (isNaN(data.total_hours)) {
                  data.total_hours = 0;
                }
                data.total_hours += hours;
              }
            }
          }
        }
      }
    }

    // console.log('stafftimelogs---',stafftimelogs);
    // console.log('projectSubTask---',projectSubTask);

    projectSubTask?.forEach((task) => {
      task.total_hours = formatSubTaskHoursToHHMMSS(task.total_hours);
    });

    if (projectSubTask) {
      reply.send({
        status: 1,
        result: projectSubTask,
        skills,
        msg: "Job sub tasks fetched successfully",
      });
    } else {
      reply.send({ status: 0, msg: "Failed to fetch all job sub task" });
    }
  } catch (error) {
    console.log("viewAllProjectSubTask error", error);
  }
};
const deleteProject = async (request, reply) => {
  try {
    let { id, status } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    if (!empty(id)) {
      let project = await Project.getProjectById(id);

      // const allAdminIds = await Admin.getAllUserIds();
      const projectMembers = await Project.getAllMemberUserIdsByProjectId(id);
      const clientUser = await Client.getClientById(project?.customer_id);
      const clientUserId = clientUser?.user_id || null;

      if (status == 2) {
        let jobCostDeleted = false;
        let recipe = 1;
        let selectedMaterials = await JobCost.fetchAllJobCostByProjectId(
          id,
          (userId = 1),
          recipe
        );
        let addlSelectedMaterials = await JobCost.fetchAllJobCostByProjectId(
          id,
          (userId = 1),
          0
        );
        if (selectedMaterials?.length > 0) {
          for (const element of selectedMaterials) {
            const material = await Product.getMaterialById(element.product_id);
            if (!empty(material)) {
              let newQty = material[0]?.qty + element.quantity;
              let totalCost = material[0]?.unit_cost * newQty;

              if (newQty >= parseInt(material[0].qty)) {
                const data = {
                  qty: newQty,
                  total_cost: totalCost,
                };
                const updated = await Product.updateMaterialStock(
                  element.product_id,
                  data
                );
                if (updated) {
                  jobCostDeleted = await JobCost.deleteJobCost(
                    element.id,
                    recipe
                  );
                } else {
                  console.log("Failed to update stock");
                  reply.send({ status: 0, message: "Failed to update stock" });
                }
              } else {
                console.log(`Stock is lesser than entered qty`);
              }
            }
          }
        }
        if (addlSelectedMaterials?.length > 0) {
          for (const element of addlSelectedMaterials) {
            const material = await Product.getMaterialById(element.product_id);
            if (!empty(material)) {
              let newQty = material[0]?.qty + element.quantity;
              let totalCost = material[0]?.unit_cost * newQty;

              if (newQty >= parseInt(material[0].qty)) {
                const data = {
                  qty: newQty,
                  total_cost: totalCost,
                };
                const updated = await Product.updateMaterialStock(
                  element.product_id,
                  data
                );
                if (updated) {
                  jobCostDeleted = await JobCost.deleteJobCost(
                    element.id,
                    recipe
                  );
                } else {
                  console.log("Failed to update stock");
                  reply.send({ status: 0, message: "Failed to update stock" });
                }
              } else {
                console.log(`Stock is lesser than entered qty`);
              }
            }
          }
        }
        let installations = await Installation.getInstallationsByProjectId(id);
        console.log("installationssssssss", installations)
        let installationDeleted =
          await Installation.deleteInstallationByProjectId(id);
        let timelogDeleted = await ProjectTask.deleteStaffTaskTimelogs(id);
        let requestDeleted = await Request.deleteRequestById(
          project.request_id
        );
        let jobDeleted = await Project.deleteProject(id);

        // const allAdminIds = await Admin.getAllUserIds();
        // const projectMembers = await Project.getAllMemberUserIdsByProjectId(id);
        // const clientUser = await Client.getClientById(project?.customer_id);
        // const clientUserId = clientUser?.user_id || null;


        // const usersToUpdate = [...new Set([clientUserId, ...allAdminIds, ...projectMembers].filter(Boolean))];

        // const updateJobTabCounts = async (userId, projectId) => {
        //   const record = await Project.getJobsTabCountByUser(userId);
        //   if (!record) return;
        //   console.log("fetching  1")
        //   const tabFields = [
        //     'pre_production',
        //     'production',
        //     'installs',
        //     'pickup',
        //     'shipping',
        //     'hold',
        //     'in_production'
        //   ];

        //   for (const field of tabFields) {
        //     console.log("fetching  2 field", field)
        //     const fieldIds = `${field}_count_ids`;
        //     const countField = `${field}_count`;
        //     const rawIds = record[fieldIds] || '';
        //     const ids = rawIds.split(',').map(id => id.trim());

        //     if (ids.includes(projectId.toString())) {
        //       console.log("fetching  4")
        //       await Project.jobTabIncrementField(userId, countField, -1, fieldIds, projectId, false);
        //       await Request.salesOrderIncrementField(userId, countField, -1, fieldIds, project?.request_id, false);
        //       if (field === 'pre_production') {
        //         await Request.salesOrderIncrementField(userId, 'in_production_count', -1, 'in_production_count_ids', project?.request_id, false);
        //         console.log(`Sales Order: Removed project ${projectId} from in_production_count for user ${userId}`);
        //       }
        //       console.log(`Jobs tab: Removed project ${projectId} and ${project?.request_id} from ${field} tab for user ${userId}`);
        //       break;
        //     }
        //   }
        // };

        // await Promise.all(usersToUpdate.map(userId => updateJobTabCounts(userId, id)));
        // console.log(" Job tab count updated for deleted project");

        // if (installations?.length > 0) {
        //   console.log("installationsssss 1", project?.customer_id)
        //   // const clientUser = await Client.getClientById(project?.customer_id);
        //   // const clientUserId = clientUser?.user_id;
        //   // const allAdminIds = await Admin.getAllAdminUserIds();
        //   // const projectMembers = await Project.getAllMemberUserIdsByProjectId(id);
        //   console.log("installationsssss 1",)

        //   // Combine & dedupe
        //   // const usersToUpdate = [...new Set([clientUserId, ...allAdminIds, ...projectMembers].filter(Boolean))];

        //   // 3. Loop installations and reduce count
        //   // for (const install of installations) {
        //   //   console.log("installations installations", install)
        //   //   const previousStatus = install.status;
        //   //   const installationId = install.id;
        //   //   console.log("installationsssss 3", installationId)
        //   //   const updateCounts = async (userId) => {
        //   //     if (install?.complete_status === 1) {
        //   //       if (previousStatus === 1) {
        //   //         await Installation.installationTabIncrementField(userId, "staged_count", -1, "staged_count_ids", installationId, false);
        //   //       } else if (previousStatus === 2) {
        //   //         await Installation.installationTabIncrementField(userId, "installing_count", -1, "installing_count_ids", installationId, false);
        //   //       } else if (previousStatus === 3 || previousStatus === 4) {
        //   //         await Installation.installationTabIncrementField(userId, "completed_count", -1, "completed_count_ids", installationId, false);
        //   //       } else if (previousStatus === 5) {
        //   //         await Installation.installationTabIncrementField(userId, "returned_count", -1, "returned_count_ids", installationId, false);
        //   //       }
        //   //     }
        //   //     if (install?.complete_status === 2) {
        //   //       if (previousStatus === 1) {
        //   //         await Installation.pickupTabIncrementField(userId, "staged_count", -1, "staged_count_ids", installationId, false);
        //   //       } else if (previousStatus === 3 || previousStatus === 4) {
        //   //         await Installation.pickupTabIncrementField(userId, "completed_count", -1, "completed_count_ids", installationId, false);
        //   //       }
        //   //     }
        //   //     if (install?.complete_status === 3) {
        //   //       if (previousStatus === 1) {
        //   //         await Installation.shippingTabIncrementField(userId, "staged_count", -1, "staged_count_ids", installationId, false);
        //   //       } else if (previousStatus === 3 || previousStatus === 4) {
        //   //         await Installation.shippingTabIncrementField(userId, "completed_count", -1, "completed_count_ids", installationId, false);
        //   //       } else if (previousStatus === 5) {
        //   //         await Installation.shippingTabIncrementField(userId, "returned_count", -1, "returned_count_ids", installationId, false);
        //   //       }
        //   //     }
        //   //   };
        //   //   await Promise.all(usersToUpdate.map(uid => updateCounts(uid)));
        //   // }

        //   // console.log("Successfully reduced installation counts for deleted project.");
        // }

        // console.log("id-----", id);
        // console.log("project.request_id-----", project.request_id);
        // console.log("installationDeleted-----", installationDeleted);
        // console.log("timelogDeleted-----", timelogDeleted);
        // console.log("requestDeleted-----", requestDeleted);
        // console.log("jobDeleted-----", jobDeleted);
        // console.log("jobCostDeleted-----", jobCostDeleted);
        
        // ✅ OPTIMIZATION: Send response immediately after critical operations
        if (jobDeleted) {
          reply.send({
            status: 1,
            message: `The Job "${project.name}" has been deleted successfully!`,
          });

          // ✅ OPTIMIZATION: Handle all notifications/emails/SMS async (non-blocking)
          const handleNotificationsAsync = async () => {
            try {
              // Admin notifications (parallelized)
              let notificationMsg = `The Job "${project.name}" has been deleted.`;
              let notificationUrl = "projects";

              let adminIds = await Admin.getAllAdminIds();
              const adminNotificationPromises = adminIds.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: project.userid,
                });
              });
              await Promise.all(adminNotificationPromises);

              // Email and SMS notifications (parallelized)
              let adminMangerIds = await Admin.getAllAdminAndManagerUserIds();
              const allUsersToCheck = [
                ...new Set(
                  [clientUserId, ...adminMangerIds, ...projectMembers]
                    .filter(Boolean)
                    .map(id => Number(id))
                    .filter(id => !isNaN(id))
                )
              ];
              console.log('allUsersTocheckkkkkkk', allUsersToCheck)
              
              const emailSmsPromises = allUsersToCheck.map(async (userIdToCheck) => {
                try {
                  console.log('useriddddd', userIdToCheck)
                  const approver = await Admin.getUserNotificationAndPermissionSettings(userIdToCheck);
                  console.log('approverrrrrrrrr', approver)
                  if (!approver) return;

                  const itemType = "Job";
                  const itemName = project?.name;

                  console.log('itemName', itemName, 'itemType', itemType)

                  const emailPromise = (async () => {
                    if (approver?.emailEnabled === 1 && approver?.email) {
                      console.log('emaillllllllll')
                      const subject = `⚠️ ${itemType} Deleted: ${itemName}`;
                      const welcome = `Hello ${approver.name},`;
                      const email_content = `The ${itemType.toLowerCase()} "${itemName}" has been deleted from the system. Please review your records if necessary.`;

                      console.log('emaillllllllll 1')
                      let message = deletedItemEmailTemplate({
                        user: approver,
                        itemType: itemType,
                        itemName: itemName,
                        baseUrl: BASE_URL,
                      });
                      console.log('emaillllllllll 3')
                      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,
                      };
                      console.log('emaillllllllll 4')
                      try {
                        await transporter.sendMail(mailOptions);
                        console.log(`✅ Delete email sent to: ${approver.email}`);
                      } catch (err) {
                        console.error(`❌ Error sending delete email:`, err);
                      }
                    }
                  })();

                  const smsPromise = (async () => {
                    if (approver?.smsEnabled === 1) {
                      const smsContent =
                        `⚠️ ${itemType} Deleted\n` +
                        `📄 ${itemType}: "${itemName}"\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(`✅ Delete SMS sent to ${approver.name || 'User'} (${recipientPhone})`);
                      } catch (err) {
                        console.error(`❌ Failed to send Delete SMS:`, err);
                      }
                    }
                  })();

                  await Promise.all([emailPromise, smsPromise]);
                } catch (err) {
                  console.error(`❌ Error sending notifications to user ${userIdToCheck}:`, err);
                }
              });

              await Promise.all(emailSmsPromises);
            } catch (error) {
              console.error('Error in async notifications handler:', error);
            }
          };

          handleNotificationsAsync().catch(error => {
            console.error('Error in async operations:', error);
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the Job!` });
        }
      } else if (status == 1) {
        // ✅ CRITICAL: Update project status
        let deleted = await Project.updateProject(id, { status: status });

        // ✅ OPTIMIZATION: Send response immediately after critical operations
        if (deleted) {
          reply.send({
            status: 2,
            message: `The Job "${project.name}" has been made to active!`,
          });

          // ✅ OPTIMIZATION: Handle notifications async (non-blocking)
          const handleNotificationsAsync = async () => {
            try {
              let notificationMsg = `The Job "${project.name}" has been deactivated.`;
              let notificationUrl = "projects";

              let adminIds = await Admin.getAllAdminIds();
              
              // Admin notifications (parallelized)
              const adminNotificationPromises = adminIds.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: project.userid,
                });
              });
              await Promise.all(adminNotificationPromises);
            } catch (error) {
              console.error('Error in async notifications handler:', error);
            }
          };

          handleNotificationsAsync().catch(error => {
            console.error('Error in async operations:', error);
          });
        } else {
          reply.send({ status: 3, message: "Unable to activate the Job!" });
        }
      } else if (status == 0) {
        // ✅ CRITICAL: Update project status
        let deleted = await Project.updateProject(id, { status: status });

        // ✅ OPTIMIZATION: Send response immediately after critical operations
        if (deleted) {
          reply.send({
            status: 4,
            message: `The Job "${project.name}" has been made Inactive!`,
          });

          // ✅ OPTIMIZATION: Handle notifications async (non-blocking)
          const handleNotificationsAsync = async () => {
            try {
              let notificationMsg = `The Job "${project.name}" has been deactivated.`;
              let notificationUrl = "projects";

              let adminIds = await Admin.getAllAdminIds();
              
              // Admin notifications (parallelized)
              const adminNotificationPromises = adminIds.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: project.userid,
                });
              });
              await Promise.all(adminNotificationPromises);
            } catch (error) {
              console.error('Error in async notifications handler:', error);
            }
          };

          handleNotificationsAsync().catch(error => {
            console.error('Error in async operations:', error);
          });
        } else {
          reply.send({
            status: 5,
            message: "Unable to deactivate the Job!",
          });
        }
      }


    } else {
      console.log("Error................");
      reply.send({ status: 500, message: "Error!" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};

const addProjectPost = async (req, reply) => {
  try {
    const { values, userId, taskId, projectId } = req.body;
    let currentTime = moment().unix();
    if (!empty(values.description)) {
      let postData = {};
      postData["message"] = values.description;
      postData["task_id"] = taskId;
      postData["timestamp"] = currentTime;
      postData["added_by"] = userId;
      postData["status"] = 1;
      let postId = await ProjectPost.addProjectPost(postData);

      if (postId) {
        let notificationMsg = `New post has been added.`;
        let notificationUrl = "project/view-task/" + taskId;

        const incrementResult_User = await Admin.incrementField(
          postData.added_by,
          "noti_count",
          1
        );

        let notificationData_user = {
          user_id: postData.added_by,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: postData.added_by,
        };

        const addNotificationResult_user = await Admin.addNotification(
          notificationData_user
        );

        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};

        for (const adminId of adminIds) {
          if (adminId != postData.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: postData.added_by,
            };

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        reply.send({
          status: 1,
          message: "Post has been added successfully!",
        });
      } else {
        reply.send({
          status: 2,
          message: "Failed to add new Post.",
        });
      }
    }
  } catch (error) {
    console.log(error);
  }
};
const editProjectPost = async (req, reply) => {
  try {
    const { values, userId, postId, taskId } = req.body;

    if (!empty(values.description)) {
      let postData = {};
      postData["message"] = values.description;
      let updated = await ProjectPost.updateProjectPost(postId, postData);

      if (updated) {
        let notificationMsg = `A post has been updated.`;
        let notificationUrl = "project/view-task/" + taskId;

        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 != postData.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: userId,
            };

            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        reply.send({
          status: 1,
          message: "Post has been updated successfully!",
        });
      } else {
        reply.send({
          status: 2,
          message: "Failed to update Post.",
        });
      }
    }
  } catch (error) {
    console.log(error);
  }
};
const LikeProjectPost = async (req, res) => {
  try {
    const { userId, postId } = req.body;
    let data = await ProjectPost.ispostLiked(userId, postId);
    if (!empty(data)) {
      await ProjectPost.deleteProjectpostLike(userId, postId);
    } else {
      await ProjectPost.addProjectPostLike({
        user_id: userId,
        post_id: postId,
      });
    }
    let count = await ProjectPost.getprojectpostlikesCount(postId);
    res.send({
      status: 1,
      count: count,
    });
  } catch (error) {
    console.log(error);
  }
};

const starredPost = async (req, res) => {
  try {
    const { userId, postId } = req.body;
    let data = await ProjectPost.isPostStarred(userId, postId);
    if (!empty(data)) {
      await ProjectPost.deleteStarredPost(userId, postId);
    } else {
      await ProjectPost.addStarredPost({ user_id: userId, post_id: postId });
    }
    res.send({
      status: 1,
    });
  } catch (error) {
    console.log(error);
  }
};

const deleteProjectPost = async (req, res) => {
  try {
    const { userId, postId } = req.body;
    let projectpost = {};
    projectpost["status"] = 2;
    if (!empty(postId)) {
      let data = await ProjectPost.getprojectPostByid(postId);
      let deleted = await ProjectPost.updateProjectPost(postId, projectpost);
      if (deleted) {
        // noti
        let notification_msg = "A post has been deleted.";
        let notification_url = "projects/view-project-task/";

        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};

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

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

          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
        }
        res.send({
          status: 1,
          message: "The post has been deleted successfully",
        });
      } else {
        res.send({
          status: 0,
        });
      }
    }
  } catch (error) {
    console.log(error);
  }
};
const addprojectPostComments = async (req, res) => {
  try {
    console.log(req.body, "--------------body");
    const { postId, userId, sendMsg, comment_id } = req.body;
    let postComment = {};
    let currentTime = moment().unix();
    if (!empty(sendMsg)) {
      postComment["message"] = sendMsg;
      if (!empty(comment_id)) {
        postComment["comment_id"] = comment_id;
      }
      postComment["post_id"] = postId;
      postComment["timestamp"] = currentTime;
      postComment["added_by"] = userId;
      postComment["status"] = 1;
      let postCommentId = await ProjectPost.addPostCommnets(postComment);
      if (postCommentId) {
        let postData = {};
        let count = await ProjectPost.getprojectPostCommentscount(postId);
        console.log(count, "----------count");
        postData["project_post"] = await ProjectPost.getprojectPostByid(postId);
        postData["users_replace"] = await ProjectPost.getAllUserReplace();
        if (empty(comment_id)) {
          postData["post_comment"] =
            await ProjectPost.getProjectPostCommentViewById(
              postCommentId,
              userId
            );
          res.send({
            status: 0,
            reply: false,
            postData,
            count,
          });
        } else {
          postData["post_comment_reply"] =
            await ProjectPost.getProjectPostCommentViewById(
              postCommentId,
              userId
            );
          res.send({
            status: 1,
            reply: true,
            postData,
          });
        }
      }
    } else {
      res.send({
        status: 0,
      });
    }
  } catch (error) {
    console.log("nushara" + error);
  }
};
const getprojectPostByid = async (req, res) => {
  try {
    const { postId } = req.body;
    if (!empty(postId)) {
      let data = await ProjectPost.getprojectPostByid(postId);
      if (!empty(data)) {
        res.send({
          status: 1,
          data,
        });
      } else {
        res.send({
          status: 0,
        });
      }
    } else {
      res.send({
        status: 0,
      });
    }
  } catch (error) {
    console.log(error);
  }
};
const likeProjectPostComments = async (req, res) => {
  try {
    const { commentId, userId } = req.body;
    let data = await ProjectPost.isPostCommentLiked(commentId, userId);
    console.log(data, "----------datadatadata");
    if (!empty(data)) {
      await ProjectPost.deleteProjectPostCommentLike(userId, commentId);
    } else {
      await ProjectPost.addProjectPostCommentLike({
        user_id: userId,
        comment_id: commentId,
      });
    }
    res.send({
      status: 1,
    });
  } catch (error) {
    console.log(error);
  }
};

const deletProjectPostComment = async (req, res) => {
  try {
    const { commentId, userId } = req.body;
    let commentData = {};
    commentData["status"] = 2;
    if (!empty(commentId)) {
      let comments = await ProjectPost.getprojectPostCommentById(commentId);
      console.log(comments, "-----------cmt");
      let deleted = await ProjectPost.updateprojectPostComments(
        commentId,
        commentData
      );
      console.log(deleted, "-----------deete ");
      if (deleted) {
        let count = await ProjectPost.getprojectPostCommentscount(
          comments["post_id"]
        );
        res.send({
          status: 1,
          count,
          message: "The comment has been deleted successfully",
        });
      } else {
        res.send({
          status: 0,
        });
      }
    } else {
      res.send({
        status: 0,
      });
    }
  } catch (error) {
    console.log(error);
  }
};
const viewAllPostComments = async (req, res) => {
  try {
    const { userId, postId, commentId } = req.body;
    let data = await ProjectPost.getAllProjectPostComments(
      postId,
      0,
      userId,
      commentId
    );
    if (data) {
      res.send({
        status: 1,
        data,
      });
    } else {
      res.send({
        status: 0,
      });
    }
  } catch (error) {
    console.log(error);
  }
};
const deleteProjectPostAttachments = async (req, res) => {
  try {
  } catch (error) {
    console.log(error);
  }
};
// public function delete_project_post_attachment($id, $post_id)
// 	{
// 		if ($id != '') {
// 			$data = $this->project_model->get_project_post_by_id($post_id);
// 			$deleted = $this->project_model->delete_project_post_attachment($id);
// 			if ($deleted) {
// 				// Notification
// 				$notification_msg = "A post attachment has been deleted.";
// 				$notification_url = "projects/view-project-task/" . $data['task_id'];

// 				$admin_ids = $this->admin_model->get_all_admin_ids();
// 				foreach ($admin_ids as $admin_id) {
// 					// Alert assigned user of updation
// 					$this->admin_model->increment_field($admin_id, "noti_count", 1);
// 					$this->admin_model->add_notification(
// 						array(
// 							"user_id" => $admin_id,
// 							"url" => $notification_url,
// 							"timestamp" => time(),
// 							"message" => $notification_msg,
// 							"status" => 1,
// 							"from_id" => $this->session->userdata('user_id'),

// 						)
// 					);
// 				}
// 				echo json_encode(array('status' => 1, 'msg' => "The attachment has been deleted successfully"));
// 			} else {
// 				echo json_encode(array('status' => 0, 'msg' => "Failed to delete attachment"));
// 			}
// 		} else {
// 			echo json_encode(array('status' => 0, 'msg' => "Failed to delete attachment"));
// 		}
// 	}
const addProjectPostAttachments = async (req, res) => {
  try {
    let { userId, userType, attachments, projectId } = req.body;
    const allUrls = [
      ...attachments.image,
      ...attachments.video,
      ...attachments.other,
    ];
    const urlObjects = [];
    allUrls.forEach((url) => {
      if (url) {
        let extension;
        if (url.includes("video")) {
          extension = "video";
        } else if (url.includes("image")) {
          extension = "image";
        } else {
          extension = "other";
        }

        const urlObject = { img: url, extension: extension };

        urlObjects.push(urlObject);
      }
      let inserted = "";
      for (let i = 0; i < urlObjects.length; i++) {
        let data = {};
        if (urlObjects[i].img) {
          (data.userid = userId),
            (data.post_id = taskId),
            (data.project_id = projectId),
            (data.file_url = urlObjects[i].img);
          (data.extension = urlObjects[i].extension),
            (data.timestamp = moment().unix());
          inserted = "";
        }
      }
    });
  } catch (error) {
    console.log(error);
  }
};
const updateProjectCompletion = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectId = request.body.projectId;
    let projectData = {};

    projectData.completion = request.body.completion;

    console.log("$$$$$$$$$$$$$$$$$$$ projectData : ", projectData);

    try {
      let result = await Project.updateProject(projectId, projectData);
      if (result) {
        let projects = await Project.getProjectById(projectId);
        // let notificationMsg = `The project "${projects.name}" has been updated.`;
        // let notificationUrl = "project/view-project/"+projectId;

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

        // 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: "Job progress updated successfully !.",
        });
      } else {
        reply.send({ status: 0, message: "Failed to update the job" });
      }
    } catch (error) {
      console.log("error : ", error);
      reply.send({ status: 0, message: "Failed to update the job" });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};
const updateProjectTaskCompletion = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectId = request.body.projectId;
    let projectData = {};
    let taskId = request.body.taskId;
    projectData.complete = request.body.completion;

    try {
      let result = await ProjectTask.updateProjectTask(projectData, taskId);
      if (result) {
        // let projects = await Project.getProjectById(projectId);
        // let notificationMsg = `The project "${projects.name}" has been updated.`;
        // let notificationUrl = "project/view-project/"+projectId;

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

        // 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: "Job task progress updated successfully !.",
        });
      } else {
        reply.send({
          status: 0,
          message: "Failed to update the job task progress",
        });
      }
    } catch (error) {
      console.log("error : ", error);
      reply.send({
        status: 0,
        message: "Failed to update the job task progress",
      });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};
const updateProjectSubTaskCompletion = async (request, reply) => {
  try {
    let currentDate = Math.round(moment().valueOf() / 1000);
    let projectId = request.body.projectId;
    let projectData = {};
    let taskId = request.body.taskId;
    let task = request.body.task;
    projectData.complete = request.body.completion;

    console.log("$$$$$$$$$$$$$$$$$$$ projectData : ", projectData);

    try {
      let result = await ProjectTask.updateProjectSubTask(projectData, taskId);
      if (result) {
        let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(
          task,
          (userType = 1)
        );

        const sumCompletion = projectSubTask.reduce(
          (acc, task) => acc + task.complete,
          0
        );
        const averageCompletion = sumCompletion / projectSubTask.length;
        let project = {};
        project.complete = averageCompletion;
        let result = await ProjectTask.updateProjectTask(project, task);

        let allSubtask = await ProjectTask.getAllProjectTasks(
          projectId,
          (userType = 1)
        );
        const sumCompletionTask = allSubtask.reduce(
          (acc, task) => acc + task.complete,
          0
        );
        const averageCompletionTask = sumCompletionTask / allSubtask.length;
        let projectTask = {};

        projectTask.completion = averageCompletionTask;

        let resultStatus = await Project.updateProject(projectId, projectTask);

        // let notificationMsg = `The project "${projects.name}" has been updated.`;
        // let notificationUrl = "project/view-project/"+projectId;

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

        // 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: "Job task progress updated successfully !.",
        });
      } else {
        reply.send({
          status: 0,
          message: "Failed to update the job task progress",
        });
      }
    } catch (error) {
      console.log("error : ", error);
      reply.send({
        status: 0,
        message: "Failed to update the job task progress" + error,
      });
    }
  } catch (error) {
    console.log("Server error", error);
    reply.status(500).send({ message: "Server error" + error });
  }
};
const fetchProjectByClientId = async (req, res) => {
  try {
    let { clientId, userId, userType } = req.body;
    let data = [];
    if (userType === 3) {
      let id = await Client.fetchClientIDFromUID(userId);
      data = await Project.fetchprojectsByClientId(id);
    } else {
      data = await Project.fetchprojectsByClientId(clientId);
    }
    res.send({
      data: data,
    });
  } catch (error) {
    console.log(error);
  }
};

const fetchprojectsByTeamId = async (req, res) => {
  try {
    let { teamId } = req.body;
    let data = await Project.fetchprojectsByTeamId(teamId);
    let designData = await Project.fetchDesignOrdersByTeamId(teamId)
    if (data?.length > 0 || designData?.length > 0) {
      res.send({ status: 1, data: data, designData: designData });
    } else {
      res.send({ status: 0, message: "No projects" });
    }
  } catch (error) {
    console.log(error);
  }
};

const saveJobCardOrder = async (req, res) => {
  try {
    const { updatedCards } = req.body;
    await Project.updateCardOrder(updatedCards);
    res.status(200).send({ status: 1, message: "Order saved" });
  } catch (error) {
    console.log("saveJobCardOrder error : ", error);
    res
      .status(500)
      .send({ status: 500, message: "Error saving order", error: error });
  }
};


const getAllDesignOrderJobs = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let currentTab = request?.body?.currentTab
    let search = request?.body?.filterName
    let filterClient = request?.body?.filterClient
    let page = request?.body?.page || 1;
    let limit = request?.body?.limit || 6;
    const fromCalendar = false;
    let results = await Project.getAllDesignOrderJobs(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      currentTab,
      filterClient,
      fromCalendar,
      page,
      limit,
      search
    );
    
    let totalCount = await Project.getTotalDesignOrderJobsCount(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      currentTab,
      filterClient,
      search
    );
    
    let designOrderCount = await Request.getDesignOrderJobCount(userType, userId)
    let clients = await Client.getAllClientsDataFilters();

    let totalPages = Math.ceil(totalCount / limit);
    const pagination = {
      totalPages: totalPages,
      totalCount: totalCount,
      limit: limit,
      currentPage: page,
    };

    if (!empty(results)) {
      reply.send({
        status: 1,
        results: results,
        clients: clients,
        designOrderCount: designOrderCount,
        pagination: pagination,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        results,
        clients: clients,
        designOrderCount: designOrderCount,
        pagination: pagination,
        message: "No data found",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllDesignOrderJobsCalendar = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let currentTab = request?.body?.currentTab
    let filterClient = request?.body?.filterClient
    let currentMonth = request?.body?.currentMonth
    
    // Calculate date range for current month, previous month, and next month
    let fromTimestamp, toTimestamp;
    if (currentMonth) {
      const startOfMonth = moment(currentMonth, 'YYYY-MM').subtract(1, 'month').startOf('month');
      const endOfMonth = moment(currentMonth, 'YYYY-MM').add(1, 'month').endOf('month');
      fromTimestamp = startOfMonth.unix();
      toTimestamp = endOfMonth.unix();
    }
    let fromCalendar = true;
    
    let results = await Project.getAllDesignOrderJobs(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromTimestamp ? moment.unix(fromTimestamp).format('YYYY-MM-DD') : fromDate,
      toTimestamp ? moment.unix(toTimestamp).format('YYYY-MM-DD') : toDate,
      dueData,
      currentTab,
      filterClient,
      fromCalendar
    );

    if (!empty(results)) {
      reply.send({
        status: 1,
        results: results,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        results,
        message: "No data found",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllDesignOrderJobsCount = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let designOrderCount = await Request.getAllDesignOrderJobCount(userType, userId)


    if (!empty(designOrderCount)) {
      reply.send({
        status: 1, userType, userId,
        designOrderCount: designOrderCount,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        designOrderCount: designOrderCount,
        message: "No data found",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllEstimateJobs = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let hasPermission = request.body.hasPermission;
    let sort = request.body.sort;
    let fromDate = request?.body?.from;
    let toDate = request?.body?.to;
    let dueData = request?.body?.dueData;
    let currentTab = request?.body?.currentTab
    let search = request?.body?.filterName
    let filterClient = request?.body?.filterClient
    let page = request?.body?.page || 1;
    let limit = request?.body?.limit || 6;
    
    let results = await Project.getAllEstimateJobs(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      currentTab,
      filterClient,
      page,
      limit,
      search
    );
    
    let totalCount = await Project.getTotalEstimateJobsCount(
      hasPermission,
      true,
      userType,
      userId,
      null,
      sort,
      fromDate,
      toDate,
      dueData,
      currentTab,
      filterClient,
      search
    );
    
    let designOrderCount = await Request.getDesignOrderJobCount(userType, userId)
    let clients = await Client.getAllClientsDataFilters();

    let totalPages = Math.ceil(totalCount / limit);
    const pagination = {
      totalPages: totalPages,
      totalCount: totalCount,
      limit: limit,
      currentPage: page,
    };

    if (!empty(results)) {
      reply.send({
        status: 1,
        results: results,
        clients: clients,
        designOrderCount: designOrderCount,
        pagination: pagination,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        results,
        clients: clients,
        designOrderCount: designOrderCount,
        pagination: pagination,
        message: "No data found",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error" + error);
  }
};

const getAllEstimateJobsCount = async (request, reply) => {
  try {
    // let status = 2;
    let userType = request.body.userType.value;
    let userId = request.body.userId.value;
    let designOrderCount = await Request.getAllDesignOrderJobCount(userType, userId)


    if (!empty(designOrderCount)) {
      reply.send({
        status: 1, userType, userId,
        designOrderCount: designOrderCount,
        message: "Data fetched successfully",
      });
    } else {
      reply.send({
        status: 0,
        designOrderCount: designOrderCount,
        message: "No data found",
      });
    }
  } catch (error) {
    console.log(error);
    reply.status(500).send("Server error : " + error);
  }
};
 
const getDesignOrderProjectById = async (request, reply) => {
  try {
    let id = request.body.id.value;
    const { userId, userType, hasPermission } = request.body;
    let projects = await Project.getDesignOrderProjectById(id);
    let community = await Community.getAllCommunities();
    let projectMembers = await Request.getAllDesignOrderProjectMembers(id);
    
    const getAllAdmins = await Project.AdminsForMessaging(userId);
    
    // Get only the first admin (not all admins)
    const allAdmins = getAllAdmins.length > 0 ? getAllAdmins : [];
    
    // Combine project members with one admin and remove duplicates
    const combined = [
      ...projectMembers,
      ...allAdmins
    ];
    
    projectMembers = Array.from(
      new Map(
        combined
          .filter(user => user?.user_id) // filter out null or undefined user_id
          .map(user => [user.user_id, user]) // remove duplicates by user_id
      ).values()
    );
    
    let projectTask = await Request.getAllDesignOrderTasks(
      id,
      userId,
      userType,
      hasPermission
    );
    // let projectAttachments = await Project.fetchAllAttachments(id);
    let teamMembers = await Project.fetchAllTeamMembers(true);

    //////////////////////////////////////////////
    for (const newData of projectTask) {
      let projectSubTask = await Request.getAllDesignOrderProjectSubTaskBytaskId(
        newData.id,
        userType,
        userId
      );
      let newUserId = (userType == 1 || userType == 8) ? null : userId;
      let stafftimelogs = await Request.fetchDesignOrderStaffTaskTimelog(
        false,
        newUserId,
        newData.id,
        false,
        false
      );
      newData.total_hours = 0;
      let newhours = 0;
      if (stafftimelogs) {
        for (const subData of stafftimelogs) {
          let subTaskArray = subData?.sub_task_id ? subData?.sub_task_id?.split(",") : [] || [];
          for (const sub of subTaskArray) {
            let hours = 0;
            if (parseInt(subData.task_id) === newData.id) {
              const startMoment = moment.unix(subData.start_time);
              let endMoment;
              if (subData.end_time !== null) {
                endMoment = moment.unix(subData.end_time);
              } else {
                endMoment = moment();
              }
              const duration = moment.duration(endMoment.diff(startMoment));
              hours = duration.asHours();
              if (!isNaN(hours)) {
                newhours += hours;
              }
            }
          }
        }
      }
      newData.total_hours = formatHoursToHHMMSS(newhours);
    }

    /////////////////////////////////////////////////////////////////
    // if (userType != 3 && userType != 1 && userType != 8) {
    //   let projectTaskFilteredPromises = projectTask.map(async (task) => {
    //     let projectSubTask = await ProjectTask.getAllProjectSubTaskBytaskId(task.ID,userType,userId);
    //     return projectSubTask.length > 0 || true;
    //   });

    //   let projectTaskFilteredResults = await Promise.all(projectTaskFilteredPromises);
    //   projectTask = projectTask.filter((_, index) => projectTaskFilteredResults[index]);
    // }

    if (!empty(projects)) {
      reply.send({
        status: 1,
        result: projects,
        // projectCategories,
        community,
        projectMembers,
        projectTask,
        // projectAttachments,
        teamMembers,
      });
    } else {
      reply.send({ status: 0, message: "Job not found" });
    }
  } catch (error) {
    console.log("Server error:" + error);
    reply.status(500).send("Server error:" + error);
  }
};
const getDesignOrderProjectTaskById = async (request, reply) => {
  try {
    const { id, userId, userType, hasPermission, taskId } = request.body;
    let projectTask = await Request.getAllDesignOrderTasks(
      id,
      userId,
      userType,
      hasPermission,
      taskId
    );
    let projectMembers = await Request.getAllDesignOrderProjectMembers(id);
    
    // For designers (userType 11), include one admin user who has design order permissions
    if (userType === 11) {
      const getAllAdmins = await Project.AdminsForMessaging(userId);
      
      // Get only the first admin (not all admins)
      const oneAdmin = getAllAdmins.length > 0 ? [getAllAdmins[0]] : [];
      
      // Combine project members with one admin and remove duplicates
      const combined = [
        ...projectMembers,
        ...oneAdmin
      ];
      
      projectMembers = Array.from(
        new Map(
          combined
            .filter(user => user?.user_id) // filter out null or undefined user_id
            .map(user => [user.user_id, user]) // remove duplicates by user_id
        ).values()
      );
    }
    
    if (!empty(projectTask)) {
      reply.send({ status: 1, result: projectTask, projectMembers });
    } else if (!empty(projectMembers)) {
      reply.send({ status: 1, result: [], projectMembers });
    } else {
      reply.send({ status: 0, message: "Job not found" });
    }
  } catch (error) {
    console.log("Server error:" + error);
    reply.status(500).send("Server error:" + error);
  }
};

const viewAllDesignOrderProjectSubTask = async (req, reply) => {
  try {
    let { taskId, userType, userId } = req.body;
    let projectSubTask = await Request.getAllDesignOrderProjectSubTaskBytaskId(
      taskId,
      userType,
      userId
    );
    let skills = await Request.designOrderProjectSubTaskSkills(taskId);
    let newUserId = (userType == 1 || userType == 8) ? null : userId;
    let stafftimelogs = await Request.fetchDesignOrderStaffTaskTimelog(
      false,
      newUserId,
      taskId,
      false,
      false
    );
    if (stafftimelogs) {
      console.log('stafftimelogs================', stafftimelogs);
      for (const subData of stafftimelogs) {
        let subTaskArray = [];
        //  subTaskArray = subData?.sub_task_id?.split(",") || [];

        if (typeof subData?.sub_task_id === 'string') {
          subTaskArray = subData.sub_task_id?.split(",") || [];
        } else if (Array.isArray(subData?.sub_task_id)) {
          // Handle case if sub_task_id is already an array
          subTaskArray = subData.sub_task_id;
        }
        console.log('projectSubTask', projectSubTask, "subTaskArray", subTaskArray)

        for (const sub of subTaskArray) {
          for (const data of projectSubTask) {
            let hours = 0;
            if (parseInt(sub) === data.id) {
              const startMoment = moment.unix(subData.start_time);
              let endMoment;
              if (subData.end_time !== null) {
                endMoment = moment.unix(subData.end_time);
              } else {
                endMoment = moment();
              }
              const duration = moment.duration(endMoment.diff(startMoment));
              hours = duration.asHours();
              console.log("hours---", hours);
              if (!isNaN(hours)) {
                if (isNaN(data.total_hours)) {
                  data.total_hours = 0;
                }
                data.total_hours += hours;
              }
            }
          }
        }
      }
    }

    // console.log('stafftimelogs---',stafftimelogs);
    // console.log('projectSubTask---',projectSubTask);

    projectSubTask?.forEach((task) => {
      task.total_hours = formatSubTaskHoursToHHMMSS(task.total_hours);
    });

    if (projectSubTask) {
      reply.send({
        status: 1,
        result: projectSubTask,
        skills,
        msg: "Job sub tasks fetched successfully",
      });
    } else {
      reply.send({ status: 0, msg: "Failed to fetch all job sub task" });
    }
  } catch (error) {
    console.log("viewAllProjectSubTask error", error);
  }
};
const addDesignOrderJobMember = async (req, reply) => {
  try {
    let { projectId, projectMembers, userId } = req.body;
    let projects = await Project.getDesignOrderProjectById(projectId);
    let success = false;
    let pmData = {};
    let addedMemberNames = [];
    const RequestActivity = require('../models/RequestActivity');
    const moment = require('moment');
    let currentDate = moment().unix();
    
    for (const pm of projectMembers) {
      pmData = {
        design_order_id: projectId,
        staff_id: !empty(pm["id"]) ? pm["id"] : 0,
        partner_id: null,
        contact_id: null,
        lead_id: null,
      };

      let alreadyExisting = await Request.projectMemberExist(pmData);
      let insertId = await Request.addDesignOrdersProjectMember(pmData);
      
      // Get member name for update entry
      if (insertId && !empty(pm["id"])) {
        const memberDetails = await Request.getAllDesignOrderProjectMembers(projectId, insertId);
        if (memberDetails && memberDetails.length > 0 && memberDetails[0].name) {
          addedMemberNames.push(memberDetails[0].name);
        } else if (pm.name) {
          addedMemberNames.push(pm.name);
        }
      }
      
      // const incrementResult_User = await Admin.incrementField(projectManager.user_id, "noti_count", 1);

      // let notificationData_user = {
      //     user_id: projectMembers.id,
      //     url: notificationUrl,
      //     timestamp: currentDate,
      //     message: "has assigned you to the project: " + projects.name,
      //     status: 1,
      //     from_id: projects.added_by,
      // };

      // const addNotificationResult_user = await Admin.addNotification(notificationData_user);
      if (insertId) success = true;
    }
    
    // Add update entry for Job Log
    if (success && addedMemberNames.length > 0 && userId) {
      const userData = await Admin.getUserById(userId);
      const userName = userData && userData[0] ? `${userData[0].first_name} ${userData[0].last_name}` : 'Unknown User';
      const memberNamesList = addedMemberNames.join(', ');
      const activityMsg = `<strong>${userName}</strong> added member(s) <strong>${memberNamesList}</strong> to the design order "<strong>${projects.name}</strong>".`;
      
      let requestActivity = {
        design_order_id: projectId,
        activity: activityMsg,
        added_by: userId,
        timestamp: currentDate
      };
      await RequestActivity.addDesignOrderUpdate(requestActivity);
    }
    
    if (success) {
      reply.send({ status: 1, msg: "New members added to job " });
    } else {
      reply.send({ status: 0, msg: "Failed to add new members" });
    }
  } catch (error) {
    reply.status(500).send({ message: "Server error" + error });
  }
};

const fetchAllDesignsFromTask = async (req, res) => {
  try {
    const { id ,requestId,projectId,mirrored,targetFacilityId} = req.body
    if (!requestId) {
      return res.send({ status: 0, message: 'Request ID is required' });
    }
    let parentRequestId = null
    if(requestId){
    const getOriginParentRequestId = await Request.getOriginParentRequestId(requestId)
    parentRequestId = getOriginParentRequestId[0]?.origin_facility_request_id
    }
    if(mirrored && targetFacilityId && parentRequestId){
      const targetFacility = filteredSignwiseInstalations.find(
        f => f.id === Number(targetFacilityId)
      );
      if (!targetFacility?.url) return null;
      const projectResponse = await axios.post(
        `${targetFacility.url}project-task/fetch-all-designs-from-task`,
        {
          id,requestId:parentRequestId,projectId
        }
      );
      if(projectResponse?.data){
        return res.send({ status: 1, attachments: projectResponse?.data?.attachments })
      }else{
        return res.send({ status: 0, message: "Failed to fetch attachments" })
      }
    }
    let attachments = await ProjectTask.fetchAllAttachmentByTask(id)
    let reqIdFromAttachments = requestId || attachments?.[0]?.request_id
    let reqAttachmentsFiles = await ProjectTask.fetchAllFilesFromRequest(reqIdFromAttachments,projectId)
    console.log('reqAttachmentsFiles', reqAttachmentsFiles)
    const files = []

    
    if (reqAttachmentsFiles && reqAttachmentsFiles.length > 0) {
      reqAttachmentsFiles.forEach(file => {
        const ext = file.extension?.toLowerCase();

        // list of non-image allowed extensions
        const nonImageExts = ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt"];

        if (nonImageExts.includes(ext)) {
          files.push(file);
        }
      });
    }
    attachments = [...attachments, ...files]

    if (attachments) {
      res.send({ status: 1, attachments })
    } else {
      res.send({ status: 0 })
    }
  } catch (error) {
    console.log("error", error)
    res.send("Server error:" + error);

  }
}

const getAllJobsTabCount = async (req, res) => {
  try {
    let userId = req.body.userId

    let data = await Project.getJobsTabCountByUser(userId);
    res.send({
      status: 1,
      data: data,
      message: 'Jobs count fetched successful'
    })
  } catch (error) {
    console.log(error)
    res.send({ status: 0, message: 'Failed to fetch Jobs tab counts' });
  }
}

const reduceJobsTabCount = async (req, reply) => {
  try {
    const { project_id, userId } = req.body;
    console.log(`Successfully jobs`, project_id, userId);
    const userCount = await Project.getJobsTabByUserData(userId);
    if (!userCount) {
      return reply.status(400).send({ status: 0, message: "User record not found" });
    }
    const countFields = {
      hold_count: "hold_count_ids",
      pre_production_count: "pre_production_count_ids",
      production_count: "production_count_ids",
      installs_count: "installs_count_ids",
      pickup_count: "pickup_count_ids",
      shipping_count: "shipping_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(project_id.toString())) {
        await Project.jobTabIncrementField(userId, countField, -1, idsField, project_id, false);
        updatedField = idsField;
        updatedCountField = countField;
        break;
      }
    }

    if (!updatedField) {
      return reply.status(400).send({ status: 0, message: "Sales order 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 Sales order count:", error);
    reply.status(500).send({ status: 0, message: "Server error", error });
  }
};

const getProjectStatusById = async (req, res) => {
  try {
    const { projectId } = req.body;

    const response = await Project.fetchProjectStatusById(projectId);
    res.send({ status: 1, result: response })
  } catch (error) {
    res.send({ status: 0, message: "Server error", error: error.message });
  }
}

const fetchServiceByTask = async (req, res) => {
  try {
    const { projectId, taskId } = req.body;
    let allServices = [];
    if (projectId && taskId) {
      allServices = await recipeModel.fetchAllServicesByProject(projectId, taskId);
    }
    if (allServices?.length > 0) {
      res.send({ status: 1, allServices });
    } else {
      res.send({ status: 0, allServices: [], message: "No services found" });
    }
  } catch (error) {
    console.log("Error fetching", error);
    res.send({ status: 500, message: "Server Error", error: error });
  }
};

const fetchAllUsersByTask = async (req, res) => {
  try {
    const { project_id, userType, userId, isMirrored, targetFacilityId } = req.body;
    console.log('project_id', project_id);

    if(isMirrored && targetFacilityId ){
      const targetFacility = filteredSignwiseInstalations.find(
        f => f.id === Number(targetFacilityId)
      );
      if (!targetFacility?.url) return null;
      const projectResponse = await axios.post(
        `${targetFacility.url}project/get-all-users-by-tasks`,
        {
          project_id: project_id, userType, userId 
        }
      );
      if(projectResponse?.data){
        return res.send({ status: 1, data: projectResponse?.data?.data })
      }else{
        return res.send({ status: 0, message: "Failed to fetch users by task" })
      }
    }

    let newUserId = (userType == 1 || userType == 8) ? null : userId;

    // Fetch task and subtask related data
    let results = await Project.fetchAllUsersByTaskModel(project_id);
    console.log('results-----------', results);

    // Fetch installer and driver data
    let installerDriverData = await Project.fetchAllInstallerDriver(project_id) || []
    console.log('installerDriverData-----------', installerDriverData);

    // Process Task and Subtask Time Logs
    if (results && results.length > 0) {
      for (let i = 0; i < results.length; i++) {
        const subtaskId = results[i].subtask_id || null;

        let totalHours = 0;
        let totalMinutes = 0;

        // Fetch time logs using fetchStaffUserProjectTimelog for tasks
        let stafftimelogs = await ProjectTask.fetchStaffUserProjectTimelog(
          newUserId,
          project_id, // Pass projectId to the query
          false // No logIdArray for this case
        );

        console.log(`Staff Time Logs for Subtask ID ${subtaskId}:`, stafftimelogs);

        if (stafftimelogs && stafftimelogs.length > 0) {
          for (const subData of stafftimelogs) {
            let subTaskArray = subData?.sub_task_id ? subData?.sub_task_id?.split(",") : [] || [];
            for (const sub of subTaskArray) {
              let hours = 0;
              let minutes = 0;
              // if (parseInt(subData.task_id) === results[i].task_id && subData?.user_id === results[i]?.staff_user_id) {
              // Check if task_id, user_id, AND subtask_id match
              if (parseInt(subData.task_id) === results[i].task_id && 
                  subData?.user_id === results[i]?.staff_user_id &&
                  parseInt(sub.trim()) === results[i].subtask_id) {
                const startMoment = moment.unix(subData.start_time);
                let endMoment;
                if (subData.end_time !== null) {
                  endMoment = moment.unix(subData.end_time);
                } else {
                  endMoment = moment();
                }
                const duration = moment.duration(endMoment.diff(startMoment));
                hours = duration.hours();
                minutes = duration.minutes();

                if (!isNaN(hours)) {
                  totalHours += hours;
                  totalMinutes += minutes;
                }
              }
            }
          }
        }

        const extraHours = Math.floor(totalMinutes / 60);
        totalHours += extraHours;
        totalMinutes = totalMinutes % 60;

        results[i].total_hours = totalHours;
        results[i].total_minutes = totalMinutes;
      }
    }

    if (installerDriverData && installerDriverData.length > 0) {
      for (let i = 0; i < installerDriverData.length; i++) {
        const installerData = installerDriverData[i];

        let totalHours = 0;
        let totalMinutes = 0;

        let installerTimelogs = await ProjectTask.fetchStaffUserProjectTimelog(
          installerData.staff_user_id,
          project_id,
          false
        );

        console.log(`Installer/Driver Time Logs for ${installerData.staff_name}:`, installerTimelogs);

        if (installerTimelogs && installerTimelogs.length > 0) {
          for (const log of installerTimelogs) {
            if (log.installation_id && installerData.installation_id && 
              parseInt(log.installation_id) === parseInt(installerData.installation_id)) {
            const startMoment = moment.unix(log.start_time);
            let endMoment;
            if (log.end_time !== null) {
              endMoment = moment.unix(log.end_time);
            } else {
              endMoment = moment();
            }
            const duration = moment.duration(endMoment.diff(startMoment));
            totalHours += duration.hours();
            totalMinutes += duration.minutes();
          }
        }
        }

        // Convert total minutes to hours
        const extraHours = Math.floor(totalMinutes / 60);
        totalHours += extraHours;
        totalMinutes = totalMinutes % 60;

        installerDriverData[i].total_hours = totalHours;
        installerDriverData[i].total_minutes = totalMinutes;

        installerDriverData[i].installation = true;
      }
    }

    const combinedData = [...results, ...installerDriverData]

    // Filter out records where staff_user_id is null
    const filteredData = combinedData.filter(item => item.staff_user_id !== null);

    res.send({ status: 1, data: filteredData });
  } catch (error) {
    console.error("Error fetching users by subtask:", error);
    res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};
const deleteStaffTaskTimelogsByServiceId = async (request, reply) => {
  try {
    const { serviceId, projectId, userId, isProductionLabor } = request.body;
    
    if (!serviceId || !projectId || !userId) {
      return reply.send({
        status: 0,
        message: 'Missing required parameters: serviceId, projectId, userId'
      });
    }

    let result;
    
    // If production labor, delete timelogs and payouts where service_id and installation_id are NULL
    if (isProductionLabor) {
      result = await ProjectTask.deleteTimelogsAndPayoutsByProductTasks(projectId);
      console.log('resultProductionLabor', result);
    }
    
    // Always delete by serviceId (runs every time, not just in else case)
    result = await ProjectTask.deleteStaffTaskTimelogsByServiceId(serviceId, projectId);
    
    if (result.status === 1) {
      reply.send({
        status: 1,
        message: result.message,
        deletedTimelogs: result.deletedTimelogs,
        deletedPayouts: result.deletedPayouts,
        totalDeleted: result.totalDeleted
      });
    } else {
      reply.send({
        status: 0,
        message: result.message,
        error: result.error
      });
    }
  } catch (error) {
    console.error('Error in deleteStaffTaskTimelogsByServiceId controller:', error);
    reply.send({
      status: 0,
      message: 'Internal server error',
      error: error.message
    });
  }
};

const fetchAllUsersByTimeAndMaterial = async (req, res) => {
  try {
    const { project_id, userType, userId } = req.body;
    console.log('project_id for time and material', project_id);

    let newUserId = (userType == 1 || userType == 8) ? null : userId;

    // Fetch project members for time and material projects
    let results = await Project.fetchAllUsersByTimeAndMaterialModel(project_id);
    console.log('time and material results-----------', results);

    // Process Project Members Time Logs for time and material projects
    if (results && results.length > 0) {
      for (let i = 0; i < results.length; i++) {
        let totalHours = 0;
        let totalMinutes = 0;

        // Fetch time logs using fetchStaffUserProjectTimelog for project members
        let stafftimelogs = await ProjectTask.fetchStaffUserProjectTimelog(
          newUserId,
          project_id, // Pass projectId to the query
          false // No logIdArray for this case
        );

        console.log(`Staff Time Logs for Project Member ${results[i].staff_name}:`, stafftimelogs);

        if (stafftimelogs && stafftimelogs.length > 0) {
          for (const subData of stafftimelogs) {
            // For time and material, we don't have task/subtask, so we check by user_id and project_id
            if (subData?.user_id === results[i]?.staff_user_id) {
              const startMoment = moment.unix(subData.start_time);
              let endMoment;
              if (subData.end_time !== null) {
                endMoment = moment.unix(subData.end_time);
              } else {
                endMoment = moment();
              }
              const duration = moment.duration(endMoment.diff(startMoment));
              let hours = duration.hours();
              let minutes = duration.minutes();

              if (!isNaN(hours)) {
                totalHours += hours;
                totalMinutes += minutes;
              }
            }
          }
        }

        const extraHours = Math.floor(totalMinutes / 60);
        totalHours += extraHours;
        totalMinutes = totalMinutes % 60;

        results[i].total_hours = totalHours;
        results[i].total_minutes = totalMinutes;
        results[i].time_and_material = true; // Mark as time and material project
      }
    }

    res.send({ status: 1, data: results });
  } catch (error) {
    console.error("Error fetching users by time and material:", error);
    res.status(500).send({ status: 0, message: "Server error", error: error.message });
  }
};

const getTeamMembersByServiceId = async (req, reply) => {
  try {
    const { serviceId, all } = req.body;
    
    // Validate required parameters
    if (!serviceId) {
      return reply.send({
        status: 0,
        message: 'Service ID is required'
      });
    }

    let teamMembers = [];
    
    // Handle both single service ID and multiple service IDs
    if (Array.isArray(serviceId)) {
      // Multiple service IDs - get team members for each service and combine unique results
      const allTeamMembers = [];
      for (const id of serviceId) {
        const members = await staffmember.getTeamMembersByServiceId(id, all || false);
        if (members && members.length > 0) {
          allTeamMembers.push(...members);
        }
      }
      
      // Remove duplicates based on staff member ID
      const uniqueMembers = allTeamMembers.filter((member, index, self) => 
        index === self.findIndex(m => m.id === member.id)
      );
      
      teamMembers = uniqueMembers;
    } else {
      // Single service ID
      teamMembers = await staffmember.getTeamMembersByServiceId(serviceId, all || false);
    }
    
    if (teamMembers && teamMembers.length > 0) {
      reply.send({
        status: 1,
        message: 'Team members fetched successfully',
        data: teamMembers,
        count: teamMembers.length
      });
    } else {
      reply.send({
        status: 0,
        message: 'No team members found for the specified service(s)',
        data: [],
        count: 0
      });
    }
  } catch (error) {
    console.error('Error in getTeamMembersByServiceId controller:', error);
    reply.send({
      status: 0,
      message: 'Internal server error',
      error: error.message
    });
  }
};

const getAllTeamMembersForEmail = async (request, reply) => {
  try {
    const teamMembers = await Project.getAllTeamMembersForEmail();
    reply.send({
      status: 1,
      message: "Team members fetched successfully",
      teamMembers: teamMembers,
    });
  } catch (error) {
    console.log("error in getAllTeamMembersForEmail", error);
    reply.status(500).send("Server error");
  }
};

module.exports = {
  addProject,
  getSpecificDataForAddProject,
  getAllProjects,
  getAllProjectsCommunityCount,
  getAllProjectsCount,
  getProjectFilterData,
  getProjectById,
  updateProject,
  getDataForAddProject,
  addProjectType,
  getAllProjectCategories,
  getAllNoChargeTypes,
  getProjectTypeById,
  editProjectType,
  deleteProjectType,
  viewProjectTask,
  addProjectMember,
  viewAllProjectSubTask,
  deleteProject,
  addProjectCategory,
  addNoChargeType,
  getProjectCategoryById,
  editProjectCategory,
  deleteProjectCategory,
  deleteNoChargeType,
  editNoChargeType,
  addProjectPost,
  LikeProjectPost,
  starredPost,
  deleteProjectPost,
  addprojectPostComments,
  getprojectPostByid,
  editProjectPost,
  likeProjectPostComments,
  deletProjectPostComment,
  viewAllPostComments,
  deleteProjectPostAttachments,
  addProjectPostAttachments,
  updateProjectCompletion,
  fetchProjectByClientId,
  fetchprojectsByTeamId,
  updateProjectTaskCompletion,
  updateProjectSubTaskCompletion,
  saveJobCardOrder,
  getAllDesignOrderJobs,
  getDesignOrderProjectById,
  getDesignOrderProjectTaskById,
  addDesignOrderJobMember,
  viewAllDesignOrderProjectSubTask,
  getAllEstimateProjects,
  getAllEstimateProjectsCount,
  getAllProjectsProgress,
  getAllDesignOrderJobsCount,
  getAllEstimateJobs,
  getAllEstimateJobsCount,
  fetchAllDesignsFromTask,
  getAllJobsTabCount,
  reduceJobsTabCount,
  getProjectStatusById,
  fetchServiceByTask,
  fetchAllUsersByTask,
  fetchAllUsersByTimeAndMaterial,
  deleteStaffTaskTimelogsByServiceId,
  getTeamMembersByServiceId,
  assignNewMembersToSubtasksBySkill,
  getAllDesignOrderJobsCalendar,
  getAllTeamMembersForEmail,
};
