const sequelize = require("../config/dbconnection");
const Settings = require("../models/settings");
const Admin = require("../models/admin");
const Client = require('../models/client')
const Request = require('../models/request')
const Quickbook = require('../quickbook/quickbook')
const moment = require("moment");
const { empty } = require("../Helpers/Common");
const Community  = require("../models/community");
const Recipe=require("../models/recipe");
const Projects = require('../models/Projects');
const JobCost = require('../models/jobCost');
const Products = require('../models/product');
const SplitManagement = require('../models/SplitManagementModel');

const getAllSettings = async (request, reply) => {
  let { userId, userType,isClientUserRoles } = request.body;
  let data = {};
  data["services"] = await Settings.getAllServices(true);
  data["user_roles"] = await Settings.getAllUserRoles(true,userId,userType,isClientUserRoles);
  data["partner_types"] = await Settings.getAllPartnerTypes(true);
  data["permissions"] = await Settings.getAllPermissions(userId,userType);
  let userData = await Admin.getUserById(userId);
  data["user_data"] = userData[0];
  if (userType == 3) {
    data["payment_methods"] = await Admin.getAllPaymentMethods();
    data["partner_data"] = await Admin.getPartnerByUserId(userId);
    data["user_skills"] = await Settings.getSkillsById(
      "partner_services",
      "partner_id",
      data.partner_data["id"]
    );
  } else if (userType != 1) {
    let teamData = await Admin.getTeamByUserId(userId);
    data["team_data"] = teamData[0];
    data["user_skills"] = await Settings.getSkillsById(
      "team_services",
      "team_id",
      data.team_data["id"]
    );
  }
  reply.send({
    status: 1,
    message: "All Settings fetched successfully",
    results: data,
  });
};

const addUserRole = async (request, reply) => {
  const { name, userId, isClientUserRole ,userType} = request.body;
  const permissions = request.body.permissions;
  let currentDate = Math.round(moment().valueOf() / 1000);
  let userRole = {};
  const isUserRoleExist = await Settings.isUserRoleExist(name);
  if (!isUserRoleExist) {
    userRole["name"] = name;
    userRole["user_permissions"] = permissions;
    userRole["timestamp"] = currentDate;
    userRole["added_by"] = userId;
    userRole["status"] = 1;
    userRole["staff_permission"] = 1;
    userRole["isClientUserRole"] = isClientUserRole ? 1 : 0
    userRole["is_added_by_client"] = userType == 3 ? 1 :0;

    const userRoleResult = await Settings.addUserRole(userRole);
    if (userRoleResult) {
      // Notification
      let notificationMsg = `New user role "${name}" has been created.`;
      let notificationUrl = "settings";

      // Alert to user of new added user role

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

      // Alert to all admins of new added user role

      let adminIds = await Admin.getAllAdminIds();
      let notificationData = {};
      for (const adminId of adminIds) {
        if (adminId != userId) {
          const incrementResult = await Admin.incrementField(
            adminId,
            "noti_count",
            1
          );
          notificationData = {
            user_id: adminId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult = await Admin.addNotification(
            notificationData
          );
        }
      }
      reply.send({ status: 1, message: `New user role "${name}" has been created successfully.`, notification:notificationMsg });
    } else {
      reply.send({ status: 0, message: "Failed to add user_role!" });
    }
  } else {
    reply.send({ status: 2, message: "User Role already exists!" });
  }
};

const editUserRole = async (request, reply) => {
  const { name, userId, userRoleId } = request.body;
  const permissions = request.body.permissions;
  let currentDate = Math.round(moment().valueOf() / 1000);
  let userRole = {};
  userRole["name"] = name;
  userRole["user_permissions"] = permissions;
  const userRoleResult = await Settings.updateUserRole(userRoleId, userRole);
  if (userRoleResult) {
    // Notification
    let notificationMsg = `User role "${name}" has been updated.`;
    let notificationUrl = "settings";

    // Alert to user of edited user role

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

    // Alert to all admins of edited user role

    let adminIds = await Admin.getAllAdminIds();
    let notificationData = {};
    for (const adminId of adminIds) {
      if (adminId != userId) {
        const incrementResult = await Admin.incrementField(
          adminId,
          "noti_count",
          1
        );
        notificationData = {
          user_id: adminId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };
        const addNotificationResult = await Admin.addNotification(
          notificationData
        );
      }
    }
    reply.send({ status: 1, message: `The user role "${name}" has been updated successfully.`, notification : notificationMsg });
  } else {
    reply.send({ status: 0, message: "Failed to update user role!" });
  }
};

const deleteUserRole = async (request, reply) => {
  try {
    let userRole = {};
    userRole["status"] = request.body.status;
    const { userRoleId, userId } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    if (userRoleId != "") {
      let data = await Settings.getUserRoleById(userRoleId);
      console.log("data------------", data);
      let deleted = await Settings.updateUserRole(userRoleId, userRole);
      console.log("deleted-----------------", deleted);
      if (userRole["status"] === 2) {
        if (deleted) {
          // Notification
          let notificationMsg = `The user role ${data.name} has been deleted.`;
          let notificationUrl = "settings";
          // Alert to user of edited user role

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

          // Alert to all admins of edited user role

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              await Admin.incrementField(adminId, "noti_count", 1);
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              await Admin.addNotification(notificationData);
            }
          }
          reply.send({
            status: 1,
            message: `The user role ${data.name} has been deleted successfully!`,
            notification: notificationMsg
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the user role!` });
        }
      } else if (userRole["status"] === 1) {
        if (deleted) {
          // Notification
          let notificationMsg = `The user role ${data.name} has been made active.`;
          let notificationUrl = "settings";

          // Alert to user of edited user role

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

          // Alert to all admins of edited user role

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              await Admin.incrementField(adminId, "noti_count", 1);
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              await Admin.addNotification(notificationData);
            }
          }
          reply.send({ status: 3, message: notificationMsg });
        } else {
          reply.send({
            status: 4,
            message: "Unable to activate the user role!",
          });
        }
      } else if (userRole["status"] === 0) {
        if (deleted) {
          // Notification
          let notificationMsg = `The user role ${data.name} has been made inactive.`;
          let notificationUrl = "settings";

          // Alert to user of edited user role

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

          // Alert to all admins of edited user role

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              await Admin.incrementField(adminId, "noti_count", 1);
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              await Admin.addNotification(notificationData);
            }
          }
          reply.send({ status: 5, message: notificationMsg });
        } else {
          reply.send({
            status: 6,
            message: "Unable to deactivate the user role!",
          });
        }
      }
    }
  } catch (error) {
    console.log(error);
    reply.send({ status: 500, message: "Server Error!" });
  }
};

const getUserRoleById = async (request, reply) => {
  const userRoleId = request.body.userRoleId;
  const result = await Settings.getUserRoleById(userRoleId);
  if (result) {
    reply.send({
      status: 1,
      message: "User role data fetched successfully",
      result: result,
    });
  } else {
    reply.send({ status: 0, message: "User role fetching error" });
  }
};

const addService = async (request, reply) => {
  try {
    const { serviceName, serviceId, userId, department } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    let service = {};
    let isServiceExist = await Settings.isServiceExist(serviceName, serviceId);
    if (!isServiceExist) {
      service["name"] = serviceName;
      service["timestamp"] = currentDate;
      service["added_by"] = userId;
      service["status"] = 1;
      service["department_id"] = department ? department.id : null;

      let serviceId = await Settings.addService(service);
      if (serviceId) {
        // Notification
        let notificationMsg = `New service ${service.name} has been created.`;
        let notificationUrl = "settings";

        // Alert to user of new added service

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

        // Alert to all admins of new added service

        let adminIds = await Admin.getAllAdminIds();
        let notificationData = {};
        for (const adminId of adminIds) {
          if (adminId != userId) {
            const incrementResult = await Admin.incrementField(
              adminId,
              "noti_count",
              1
            );
            notificationData = {
              user_id: adminId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };
            const addNotificationResult = await Admin.addNotification(
              notificationData
            );
          }
        }
        reply.send({
          status: 1,
          notification: notificationMsg,
          message: `New service "${service.name}" has been added successfully!`,
        });
      } else {
        reply.send({ status: 0, message: `Error adding service!` });
      }
    } else {
      reply.send({ status: 2, message: `Service already exist!` });
    }
  } catch (error) {
    console.log("Error adding service : ", error);
  }
};

const getServiceById = async (request,reply) => {
  try{
    const {serviceId} = request.body;
    let result = await Settings.getServiceById(serviceId);
    if(result){
      if(result.length === 1 ){
        return result[0];
      }
      else{
        return false;
      }
    }
    else {
      return false
    }
  }
  catch(error){
    console.log("getServiceById error",error)
  }
}

const editService = async (request, reply) => {
  const { serviceId,userId,department } = request.body;
  let currentDate = Math.round(moment().valueOf() / 1000);
  let service = {};
  service["name"] = request.body.serviceName;
  service["department_id"] = department ? department.id : null;
  let updated = await Settings.updateService(serviceId, service);
  if (updated) {
    // Notification
    let notificationMsg = `The service ${service.name} has been updated.`;
    let notificationUrl = "settings";

    // Alert to user of updated service
    const incrementResult_User = await Admin.incrementField(
      userId,
      "noti_count",
      1
    );
    let notificationData_user = {
      user_id: userId,
      url: notificationUrl,
      timestamp: currentDate,
      message: notificationMsg,
      status: 1,
      from_id: userId,
    };
    const addNotificationResult_user = await Admin.addNotification(
      notificationData_user
    );

    // Alert to all admins of updated service

    let adminIds = await Admin.getAllAdminIds();
    let notificationData = {};
    for (const adminId of adminIds) {
      if (adminId != userId) {
        const incrementResult = await Admin.incrementField(
          adminId,
          "noti_count",
          1
        );
        notificationData = {
          user_id: adminId,
          url: notificationUrl,
          timestamp: currentDate,
          message: notificationMsg,
          status: 1,
          from_id: userId,
        };
        const addNotificationResult = await Admin.addNotification(
          notificationData
        );
      }
    }
    reply.send({
      status: 1, notification: notificationMsg,
      message: `The service "${service.name}" has been updated successfully!`,
    });
  } else {
    reply.send({ status: 0, message: "Failed to update service!" });
  }
};

const deleteService = async (request, reply) => {
  try {
    const { serviceId, status, userId } = request.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
    let service = {};
    service["status"] = status;
    if (serviceId != "") {
      let data = await Settings.getServiceById(serviceId);
      console.log("data-----------------", data[0]);
      console.log("data['name']-----------------", data[0].name);
      let deleted = await Settings.updateService(serviceId, service);
      if (service["status"] == 2) {
        if (deleted) {
          // Notification
          let notificationMsg = `The service ${data[0].name} has been deleted.`;
          let notificationUrl = "settings";
          console.log("notificationMsg", notificationMsg);
          // Alert to user of deleted service
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );

          // Alert to all admins of deleted service
          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          reply.send({
            status: 1,
            message: `The service ${data[0].name} has been deleted successfully!`,
          });
        } else {
          reply.send({ status: 0, message: `Unable to delete the service!` });
        }
      } else if (service["status"] == 1) {
        if (deleted) {
          // Notification
          let notificationMsg = `The service ${data[0].name} has been made active.`;
          let notificationUrl = "settings";

          // Alert to user of activated service
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );

          // Alert to all admins of activated service
          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          reply.send({ status: 2, message: notificationMsg });
        } else {
          reply.send({ status: 3, message: "Unable to activate the service!" });
        }
      } else if (service["status"] == 0) {
        if (deleted) {
          // Notification
          let notificationMsg = `The service ${data[0].name} has been made inactive.`;
          let notificationUrl = "settings";

          // Alert to user of deactivated service
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );

          // Alert to all admins of deactivated service
          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          reply.send({ status: 4, message: notificationMsg });
        } else {
          reply.send({
            status: 5,
            message: "Unable to deactivate the service!",
          });
        }
      }
    }
  } catch (error) {
    reply.send({ status: 500, message: "Server error" });
    console.log("delete error ", error);
  }
};
///partner 
const addpartnerTypes=async(req,res)=>{
  try {
    let {values,userType,userId} = req.body;
    let currentDate = Math.round(moment().valueOf() / 1000);
     if(!empty(values)){
        let partnerExist  = await Settings.ispartnerTypeExist(values.name)
        let partnerTypedata={}
        if(!partnerExist){
          partnerTypedata['name'] = values.name
          partnerTypedata['bg_color'] = values.color
          partnerTypedata['description'] = values.description
          partnerTypedata['timestamp'] = currentDate
          partnerTypedata['added_by'] = userId
          partnerTypedata['status'] = 1
          
          let partnerTypeId = await Settings.addpartnerTypes(partnerTypedata)
          if(!empty(partnerTypeId)){
            //notifcation
            let notificationMsg=`New client type <strong>${partnerTypedata['name']}</strong> has been created.`;				
            let notificationUrl="settings";	

            const incrementResult_User = await Admin.incrementField(
              userId,
              "noti_count",
              1
            );
            let notificationData_user = {
              user_id: userId,
              url: notificationUrl,
              timestamp: currentDate,
              message: notificationMsg,
              status: 1,
              from_id: userId,
            };
            const addNotificationResult_user = await Admin.addNotification(
              notificationData_user
            );
    
            // Alert to all admins of new added service
    
            let adminIds = await Admin.getAllAdminIds();
            let notificationData = {};
            for (const adminId of adminIds) {
              if (adminId != userId) {
                const incrementResult = await Admin.incrementField(
                  adminId,
                  "noti_count",
                  1
                );
                notificationData = {
                  user_id: adminId,
                  url: notificationUrl,
                  timestamp: currentDate,
                  message: notificationMsg,
                  status: 1,
                  from_id: userId,
                };
                const addNotificationResult = await Admin.addNotification(
                  notificationData
                );
              }
            }
            res.send({
              status: 1,
              notification: notificationMsg,
              message: `New client type "${values.name}" has been added successfully!`,
            });
          }
        }else{
          res.send({
            status: 2,
            message: `The Client type is already exist`,
          })
        }
     }else{
      res.send({
        status: 0,
        message: `Error in adding client type`,
      })
     }
  } catch (error) {
    console.log(error,'error in adding partner type')
  }
}
let currentDate = Math.round(moment().valueOf() / 1000);
const editpartnerType=async(req,res)=>{
  try {
      const {values,userId,clientTypeId} = req.body
      if(!empty(values)){
        let partnerTypeData ={}
        partnerTypeData['name']=values.name
        partnerTypeData['description'] = values.description
        partnerTypeData['bg_color']=values.color
        let updated = await Settings.editpartnerType(clientTypeId,partnerTypeData)
        if(updated){
          let notificationMsg = `The client type  ${values.name} has been updated.`;
          let notificationUrl = "settings";
      
          // Alert to user of updated service
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );
      
          // Alert to all admins of updated service
      
          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          res.send({
            status: 1, notification: notificationMsg,
            message: `The client type  ${values.name} has been updated successfully!`,
          });
        }else{
          res.send({
            status:0,message:'Failed to  updating client type'
          })
        }
      }else{
        res.send({
          status:0,message:'Error in updating client type'
        })
      }
  } catch (error) {
    console.log(error,'error in updating client type')
  }
}
const getpartnerTypebyId=async(req,res)=>{
  try {
     const {id} = req.body
     if(!empty(id)){
       let data = await Settings.getPartnerTypeById(id) 
       res.send({
        status:1,data
       })
     }
  } catch (error) {
    console.log(error)
  }
}
const deletepartnerType = async(req,res)=>{
  try {
    const {clientTypeId,status,userId} = req.body
    if(!empty(clientTypeId)){
      let partnerTypeData={}
      partnerTypeData['status'] = status
      let data = await Settings.getPartnerTypeById(clientTypeId)
      let deleted = await Settings.editpartnerType(clientTypeId,partnerTypeData)
      
      if (partnerTypeData["status"] === 2) {
        if (deleted) {
          // Notification
          let notificationMsg = `The client type ${data.name} has been deleted.`;
          let notificationUrl = "settings";
          
          
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );

          // Alert to all admins of deleted service
          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          res.send({
            status: 1,
            message: `The client type ${data[0].name} has been deleted successfully!`,
          });
        } else {
          res.send({ status: 0, message: `Unable to delete the client type!` });
        }
      } else if (partnerTypeData["status"] === 1) {
        if (deleted) {
          // Notification
          let notificationMsg = `The cleint type ${data[0].name} has been made active.`;
          let notificationUrl = "settings";

          // Alert to user of activated service
          const incrementResult_User = await Admin.incrementField(
            userId,
            "noti_count",
            1
          );
          let notificationData_user = {
            user_id: userId,
            url: notificationUrl,
            timestamp: currentDate,
            message: notificationMsg,
            status: 1,
            from_id: userId,
          };
          const addNotificationResult_user = await Admin.addNotification(
            notificationData_user
          );

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          res.send({ status: 2, message: notificationMsg });
        } else {
          res.send({ status: 3, message: "Unable to activate the client type!" });
        }
      } else if (partnerTypeData["status"] === 0) {
        if (deleted) {
          // Notification
          let notificationMsg = `The client type ${data[0].name} has been made inactive.`;
          let notificationUrl = "settings";

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

          let adminIds = await Admin.getAllAdminIds();
          let notificationData = {};
          for (const adminId of adminIds) {
            if (adminId != userId) {
              const incrementResult = await Admin.incrementField(
                adminId,
                "noti_count",
                1
              );
              notificationData = {
                user_id: adminId,
                url: notificationUrl,
                timestamp: currentDate,
                message: notificationMsg,
                status: 1,
                from_id: userId,
              };
              const addNotificationResult = await Admin.addNotification(
                notificationData
              );
            }
          }
          res.send({ status: 4, message: notificationMsg });
        } else {
          res.send({
            status: 5,
            message: "Unable to deactivate the client type!",
          });
        }
      }
    }
  } catch (error) {
    console.log(error)
  }
}
const dashboardCount=async(req, res)=>{
  try{
    let clientCount = await Settings.getClientCount()
    let requestCount = await Settings.getRequestCount()
    let projectCount = await Settings.projectCount()
    let installationCount=await Settings.installationCount()
    console.log(installationCount, 'installationCount')
    res.send({status:1,clientCount,requestCount,projectCount,installationCount})
  }
  catch(error){
    console.log(error,"dashboard")
  }
}
const projectStatistics=async(req, res)=>{
  try{
    let all=req.body.all
    let selectedPhase=req.body?.selectedPhaseValue
    let { userType, userId }=req.body

    console.log('Selected Phase-------------',selectedPhase);
    
    let allProject=await Settings.getAllProjects(all,selectedPhase,userType,userId)
    
    allProject = allProject.filter(project => project.installation_acceptance !== 1)
    
    // For each project, get the exact same calculation as CompareJobCostChartMain
    const results = await Promise.all(allProject.map(async (project) => {
      try {
        // Use the same models and methods as fetchAllJobCostByProjectIdRecipe
        let recipe = 1;
        let selectedMaterials = await JobCost.fetchAllJobCostByProjectId(project.id, userId, recipe);
        let stockProducts = [];
        let projectDetails = await Projects.getProjectById(project.id);
        if(projectDetails?.project_category !== 15){
          stockProducts = await JobCost.fetchAllProductsStock(project.id, userId, recipe);
        }
        
        recipe = 0;
        let materials = await JobCost.fetchAllJobCostByProjectId(project.id, userId, recipe);
        let allPayOut = await JobCost.fetchAllPayOutByProjectId(project.id, userId);
        
        // Get all products for recipe filtering (same as fetchAllJobCostByProjectIdRecipe)
        let allProducts = [];
        if(projectDetails?.project_category === 15){
          allProducts = await Products.getAllLocations(project.request_id);
        } else {
          allProducts = await Products.getNonStockProducts(project.request_id);
        }
        
        const allProductIds = allProducts?.split(',').map(id => parseInt(id, 10)) || [];
        
        // Group materials (same as fetchAllJobCostByProjectIdRecipe)
        let groupedMaterials = materials?.reduce((acc, material) => {
          let existing = acc.find(item => item.product_id === material.product_id);
          if (existing) {
            existing.actual_unit_price = material.actual_unit_price;
            existing.quantity += material.quantity;
            existing.actual_quantity += material.actual_quantity;
            existing.total += material.total;
            existing.actual_total += material.actual_total;
          } else {
            acc.push({...material});
          }
          return acc;
        }, []) || [];
        
        // Categorize materials (from recipe vs not from recipe)
        const updatedMaterials = groupedMaterials?.map(material => {
          return {
            ...material,
            notFromRecipe: !allProductIds.includes(material.product_id),
          };
        }) || [];
        
        // Get services (same as fetchAllJobCostByProjectIdRecipe)
        let allServices = await Recipe.fetchAllServicesByRequest(project.request_id);
        const filteredServices = allServices.filter(service => {
          if (service.product_id != null) {
            return allProductIds.includes(service.product_id);
          }
          return true;
        });
        
        // Get finished products (same as frontend productListData)
        let productListData = await Products.getFinishedProducts();
        
        // Process selectedMaterials for RFP products (same as frontend)
        let receivedRfpProducts = selectedMaterials.filter(row => row.rfp === 1);
        let rfpProducts = receivedRfpProducts.map(product => ({
          ...product,
          jobcost_unit_cost: product.unit_cost,
          jobcost_quantity: product.quantity,
          jobcost_actual_unit_cost: product.actual_unit_cost,
          jobcost_actual_quantity: product.actual_quantity
        }));
        let selectedProducts = selectedMaterials.filter(row => row.rfp === 0);
        
        // Apply the same filtering as frontend - only include materials that have matching products
        const selectedProjects1 = selectedProducts?.map(selectedProduct => {
          const matchingProduct = productListData.find(product => product.id === selectedProduct.product_id);
          if (matchingProduct) {
            return {
              ...matchingProduct,
              product_id: selectedProduct.product_id,
              jobcost_quantity: selectedProduct.quantity,
              jobcost_unit_cost: selectedProduct.unit_price,
              jobcost_total: selectedProduct.total,
              jobcost_actual_quantity: selectedProduct.actual_quantity,
              jobcost_actual_unit_cost: selectedProduct.actual_unit_price,
              recipeName: selectedProduct.recipeName,
              taken: selectedProduct.taken,
              task_id: selectedProduct.task_id
            };
          }
          return null;
        }).filter(project => project !== null);
        
        const selectedProjects2 = materials?.map(selectedProduct => {
          const matchingProduct = productListData.find(product => product.id === selectedProduct.product_id);
          if (matchingProduct) {
            return {
              ...matchingProduct,
              product_id: selectedProduct.product_id,
              jobcost_quantity: selectedProduct.quantity,
              jobcost_unit_cost: selectedProduct.unit_price,
              jobcost_total: selectedProduct.total,
              jobcost_actual_quantity: selectedProduct.actual_quantity,
              jobcost_actual_unit_cost: selectedProduct.actual_unit_price,
              recipeName: selectedProduct.recipeName,
              taken: selectedProduct.taken,
              task_id: selectedProduct.task_id
            };
          }
          return null;
        }).filter(project => project !== null);
        
        // Create selectedProjects array (selectedMaterials + rfpProducts with product matching) - matches frontend line 264
        let selectedProjects = [...selectedProjects1, ...rfpProducts];
        
        // Combine filtered materials for budget calculation
        let allMaterialsForBudget = [...selectedProjects1, ...selectedProjects2, ...rfpProducts];
        
        // Calculate materialPayOut (materials not from recipe) - matches frontend line 267-269
        // This should use selectedProjects2 (materials with product matching) filtered by notFromRecipe != true
        let materialPayOut = selectedProjects2
          ?.filter(curr => curr.notFromRecipe != true)
          .reduce((acc, curr) => acc + (curr.jobcost_actual_quantity * curr.jobcost_actual_unit_cost), 0) || 0;

        // Calculate materialPayOut1 (materials from recipe) - matches frontend line 271-273
        // This should use selectedProjects2 (materials with product matching) filtered by notFromRecipe != true
        let materialPayOut1 = selectedProjects2
          ?.filter(curr => curr.notFromRecipe != true)
          .reduce((acc, curr) => acc + (curr.jobcost_total || 0), 0) || 0;

        // Calculate selectedProjectsCost (expected - all projects) - matches frontend grandTotalCost calculation
        // This should use selectedProjects (selectedMaterials + rfpProducts with product matching)
        let selectedProjectsCost = selectedProjects.reduce((acc, proj) => {
          const totalCost = proj.jobcost_total
            ? Number(proj.jobcost_total)
            : (Number(proj.jobcost_actual_unit_cost || proj.unit_cost || 0) * Number(proj.jobcost_actual_quantity || 0));
          return acc + totalCost;
        }, 0);

        // Calculate servicesCost (expected - all services) - matches frontend line 329-336
        let servicesCost = filteredServices.reduce((sum, service) => {
          const quantity = parseFloat(service.qty || 0);
          const unitCost = parseFloat(service.originalCost || service.unit_cost || 0);
          return sum + (quantity * unitCost);
        }, 0);

        // Calculate stock cost (expected - all stock) - matches frontend totalStockCost calculation
        let totalStockCost = stockProducts.reduce((sum, item) => {
          const cost = parseFloat(item.location_quantity || 0) * parseFloat(item.product_retail_price || 0);
          return sum + cost;
        }, 0);

        // Calculate actual costs (only taken=1 items) - matches frontend grandTotalCost1 calculation
        // This should use selectedProjects (selectedMaterials + rfpProducts with product matching) filtered by taken=1
        let selectedProjectsCostActual = selectedProjects
          ?.filter(i => i.taken == 1)
          ?.reduce((acc, proj) => acc + (proj.jobcost_total || 0), 0) || 0;

        let servicesCostActual = filteredServices.reduce((sum, service) => {
          if (projectDetails?.job_category_name === 'Time & Material') {
            if (service.taken == 1) {
              return sum + parseFloat(service.jobcost_total_cost || 0);
            }
          } else {
            if (service.taken == 1) {
              return sum + parseFloat(service.jobcost_total_cost || 0);
            }
          }
          return sum;
        }, 0);

        let totalStockCostActual = stockProducts.reduce((sum, item) => {
          if (item?.taken !== 1) return sum;
          const cost = parseFloat(item.jobcost_total_cost || 0);
          return sum + cost;
        }, 0);

        // Calculate payout amounts - matches frontend payout calculation
        let excessHourlyPayoutAmount = allPayOut
          ?.filter(payout => payout.is_auto_pay === 1 && !payout.service_id)
          ?.reduce((acc, curr) => acc + curr.amount, 0) || 0;

        let excessManualPayoutAmount = allPayOut
          ?.filter(payout => payout.is_auto_pay !== 1 && !payout.service_id)
          ?.reduce((acc, curr) => acc + curr.amount, 0) || 0;

        let additionalAmount = Math.max(0, (excessManualPayoutAmount || 0) + (excessHourlyPayoutAmount || 0));

        // Calculate expected (budget) - matches frontend grandTotalCost (line 337-342)
        let expected = materialPayOut + selectedProjectsCost + servicesCost + totalStockCost;

        // Calculate actual (expense) - matches frontend grandTotalCost1 (line 371-377)
        let actual = materialPayOut1 + selectedProjectsCostActual + servicesCostActual + totalStockCostActual + additionalAmount;

        console.log(`Project ${project.id} - Expected: ${expected}, Actual: ${actual}`);
        console.log(`  - materialPayOut: ${materialPayOut}, selectedProjectsCost: ${selectedProjectsCost}, servicesCost: ${servicesCost}, totalStockCost: ${totalStockCost}`);
        console.log(`  - materialPayOut1: ${materialPayOut1}, selectedProjectsCostActual: ${selectedProjectsCostActual}, servicesCostActual: ${servicesCostActual}, totalStockCostActual: ${totalStockCostActual}, additionalAmount: ${additionalAmount}`);
        
        return {
          ...project,
          budget: expected,
          expense: actual
        };
      } catch (error) {
        console.log(`Error calculating for project ${project.id}:`, error);
        return project;
      }
    }));
    
    res.send({status:1, data:results})
  }
  catch(error){
    console.log(error, "dashboard")
    res.send({status:500, error:error})
  }

}

// Optimized version for EcommerceYearlySales component - only returns essential data with pagination
const projectStatisticsOptimized = async(req, res) => {
  try {
    let all = req.body.all
    let selectedPhase = req.body?.selectedPhaseValue
    let { userType, userId } = req.body
    let page = req.body.page || 0
    let limit = req.body.limit || 20

    console.log('Selected Phase (Optimized)-------------', selectedPhase);
    
    // Get paginated project data with essential fields only
    let result = await Settings.getAllProjectsOptimizedWithPagination(all, selectedPhase, userType, userId, page, limit)
    let allProject = result?.data?.filter(project => project.installation_acceptance !== 1)

    // Calculate budget and expense for each project with simplified logic
    const results = await Promise.all(allProject.map(async (project) => {
      try {
        // Use the same models and methods as fetchAllJobCostByProjectIdRecipe
        let recipe = 1;
        let selectedMaterials = await JobCost.fetchAllJobCostByProjectId(project.id, userId, recipe);
        let stockProducts = [];
        // let projectDetails = await Projects.getProjectById(project.id);
        if(project?.project_category !== 15){
          stockProducts = await JobCost.fetchAllProductsStock(project.id, userId, recipe);
        }
        
        recipe = 0;
        let materials = await JobCost.fetchAllJobCostByProjectId(project.id, userId, recipe);
        let allPayOut = await JobCost.fetchAllPayOutByProjectId(project.id, userId);
        
        // Get all products for recipe filtering (same as fetchAllJobCostByProjectIdRecipe)
        let allProducts = [];
        if(project?.project_category === 15){
          allProducts = await Products.getAllLocations(project.request_id);
        } else {
          allProducts = await Products.getNonStockProducts(project.request_id);
        }
        
        const allProductIds = allProducts?.split(',').map(id => parseInt(id, 10)) || [];
        
        // Group materials (same as fetchAllJobCostByProjectIdRecipe)
        let groupedMaterials = materials?.reduce((acc, material) => {
          let existing = acc.find(item => item.product_id === material.product_id);
          if (existing) {
            existing.actual_unit_price = material.actual_unit_price;
            existing.quantity += material.quantity;
            existing.actual_quantity += material.actual_quantity;
            existing.total += material.total;
            existing.actual_total += material.actual_total;
          } else {
            acc.push({...material});
          }
          return acc;
        }, []) || [];
        
        // Categorize materials (from recipe vs not from recipe)
        const updatedMaterials = groupedMaterials?.map(material => {
          return {
            ...material,
            notFromRecipe: !allProductIds.includes(material.product_id),
          };
        }) || [];
        
        // Get services (same as fetchAllJobCostByProjectIdRecipe)
        let allServices = await Recipe.fetchAllServicesByRequest(project.request_id);
        const filteredServices = allServices.filter(service => {
          if (service.product_id != null) {
            return allProductIds.includes(service.product_id);
          }
          return true;
        });
        
        // Get finished products (same as frontend productListData)
        let productListData = await Products.getFinishedProducts();
        
        // Process selectedMaterials for RFP products (same as frontend)
        let receivedRfpProducts = selectedMaterials.filter(row => row.rfp === 1);
        let rfpProducts = receivedRfpProducts.map(product => ({
          ...product,
          jobcost_unit_cost: product.unit_cost,
          jobcost_quantity: product.quantity,
          jobcost_actual_unit_cost: product.actual_unit_cost,
          jobcost_actual_quantity: product.actual_quantity
        }));
        let selectedProducts = selectedMaterials.filter(row => row.rfp === 0);
        
        // Apply the same filtering as frontend - only include materials that have matching products
        const selectedProjects1 = selectedProducts?.map(selectedProduct => {
          const matchingProduct = productListData.find(product => product.id === selectedProduct.product_id);
          if (matchingProduct) {
            return {
              ...matchingProduct,
              product_id: selectedProduct.product_id,
              jobcost_quantity: selectedProduct.quantity,
              jobcost_unit_cost: selectedProduct.unit_price,
              jobcost_total: selectedProduct.total,
              jobcost_actual_quantity: selectedProduct.actual_quantity,
              jobcost_actual_unit_cost: selectedProduct.actual_unit_price,
              recipeName: selectedProduct.recipeName,
              taken: selectedProduct.taken,
              task_id: selectedProduct.task_id
            };
          }
          return null;
        }).filter(project => project !== null);
        
        const selectedProjects2 = materials?.map(selectedProduct => {
          const matchingProduct = productListData.find(product => product.id === selectedProduct.product_id);
          if (matchingProduct) {
            return {
              ...matchingProduct,
              product_id: selectedProduct.product_id,
              jobcost_quantity: selectedProduct.quantity,
              jobcost_unit_cost: selectedProduct.unit_price,
              jobcost_total: selectedProduct.total,
              jobcost_actual_quantity: selectedProduct.actual_quantity,
              jobcost_actual_unit_cost: selectedProduct.actual_unit_price,
              recipeName: selectedProduct.recipeName,
              taken: selectedProduct.taken,
              task_id: selectedProduct.task_id
            };
          }
          return null;
        }).filter(project => project !== null);
        
        // Create selectedProjects array (selectedMaterials + rfpProducts with product matching) - matches frontend line 264
        let selectedProjects = [...selectedProjects1, ...rfpProducts];
        
        // Combine filtered materials for budget calculation
        let allMaterialsForBudget = [...selectedProjects1, ...selectedProjects2, ...rfpProducts];
        
        // Calculate materialPayOut (materials not from recipe) - matches frontend line 267-269
        // This should use selectedProjects2 (materials with product matching) filtered by notFromRecipe != true
        let materialPayOut = selectedProjects2
          ?.filter(curr => curr.notFromRecipe != true)
          .reduce((acc, curr) => acc + (curr.jobcost_actual_quantity * curr.jobcost_actual_unit_cost), 0) || 0;

        // Calculate materialPayOut1 (materials from recipe) - matches frontend line 271-273
        // This should use selectedProjects2 (materials with product matching) filtered by notFromRecipe != true
        let materialPayOut1 = selectedProjects2
          ?.filter(curr => curr.notFromRecipe != true)
          .reduce((acc, curr) => acc + (curr.jobcost_total || 0), 0) || 0;

        // Calculate selectedProjectsCost (expected - all projects) - matches frontend grandTotalCost calculation
        // This should use selectedProjects (selectedMaterials + rfpProducts with product matching)
        let selectedProjectsCost = selectedProjects.reduce((acc, proj) => {
          const totalCost = proj.jobcost_total
            ? Number(proj.jobcost_total)
            : (Number(proj.jobcost_actual_unit_cost || proj.unit_cost || 0) * Number(proj.jobcost_actual_quantity || 0));
          return acc + totalCost;
        }, 0);

        // Calculate servicesCost (expected - all services) - matches frontend line 329-336
        let servicesCost = filteredServices.reduce((sum, service) => {
          const quantity = parseFloat(service.qty || 0);
          const unitCost = parseFloat(service.originalCost || service.unit_cost || 0);
          return sum + (quantity * unitCost);
        }, 0);

        // Calculate stock cost (expected - all stock) - matches frontend totalStockCost calculation
        let totalStockCost = stockProducts.reduce((sum, item) => {
          const cost = parseFloat(item.location_quantity || 0) * parseFloat(item.product_retail_price || 0);
          return sum + cost;
        }, 0);

        // Calculate actual costs (only taken=1 items) - matches frontend grandTotalCost1 calculation
        // This should use selectedProjects (selectedMaterials + rfpProducts with product matching) filtered by taken=1
        let selectedProjectsCostActual = selectedProjects
          ?.filter(i => i.taken == 1)
          ?.reduce((acc, proj) => acc + (proj.jobcost_total || 0), 0) || 0;

        let servicesCostActual = filteredServices.reduce((sum, service) => {
          if (project?.project_category == 12) {
            if (service.taken == 1) {
              return sum + parseFloat(service.jobcost_total_cost || 0);
            }
          } else {
            if (service.taken == 1) {
              return sum + parseFloat(service.jobcost_total_cost || 0);
            }
          }
          return sum;
        }, 0);

        let totalStockCostActual = stockProducts.reduce((sum, item) => {
          if (item?.taken !== 1) return sum;
          const cost = parseFloat(item.jobcost_total_cost || 0);
          return sum + cost;
        }, 0);

        // Calculate payout amounts - matches frontend payout calculation
        let excessHourlyPayoutAmount = allPayOut
          ?.filter(payout => payout.is_auto_pay === 1 && !payout.service_id)
          ?.reduce((acc, curr) => acc + curr.amount, 0) || 0;

        let excessManualPayoutAmount = allPayOut
          ?.filter(payout => payout.is_auto_pay !== 1 && !payout.service_id)
          ?.reduce((acc, curr) => acc + curr.amount, 0) || 0;

        let additionalAmount = Math.max(0, (excessManualPayoutAmount || 0) + (excessHourlyPayoutAmount || 0));

        // Calculate expected (budget) - matches frontend grandTotalCost (line 337-342)
        let expected = materialPayOut + selectedProjectsCost + servicesCost + totalStockCost;

        // Calculate actual (expense) - matches frontend grandTotalCost1 (line 371-377)
        let actual = materialPayOut1 + selectedProjectsCostActual + servicesCostActual + totalStockCostActual + additionalAmount;

        console.log(`Project ${project.id} - Expected: ${expected}, Actual: ${actual}`);
        console.log(`  - materialPayOut: ${materialPayOut}, selectedProjectsCost: ${selectedProjectsCost}, servicesCost: ${servicesCost}, totalStockCost: ${totalStockCost}`);
        console.log(`  - materialPayOut1: ${materialPayOut1}, selectedProjectsCostActual: ${selectedProjectsCostActual}, servicesCostActual: ${servicesCostActual}, totalStockCostActual: ${totalStockCostActual}, additionalAmount: ${additionalAmount}`);
        
        return {
          ...project,
          budget: expected,
          expense: actual
        };
      } catch (error) {
        console.log(`Error calculating for project ${project.id}:`, error);
        return project;
      }
    }));
    
    res.send({
      status: 1, 
      data: results,
      totalCount: result.totalCount,
      currentPage: page,
      totalPages: Math.ceil(result.totalCount / limit)
    })
  } catch(error) {
    console.log(error, "dashboard optimized")
    res.send({status: 500, error: error})
  }
}
const UpcomingprojectStatistics=async(req, res)=>{
  try{
    let all=req.body.all
    let page=req.body.page
    let { userType, userId } = req.body
    let allProject=await Settings.getAllProjectsforUpcoming(all,page,userType,userId)
    res.send({status:1, data:allProject})
  }
  catch(error){
    console.log(error, "dashboard")
  }

}
const updateCompanyprofile=async(req,res)=>{
  try {
    let {values,id} = req.body
    if(!empty(values)){
      let data={}
      data['name'] = values.name
      data['company_logo'] = values?.company_logo
      data['timestamp'] = Math.round(moment().valueOf() / 1000);
      let result = await Settings.updateCompanyprofile(data,id)
      if(result===true){
        res.send({
          status:1
        })
      }else{
        res.send({
          status:0
        })
      }
    }else{
      res.send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}

const updateCompanyLatLngController = async (req, res) => {
  try {
    let { lat, lng, id } = req.body;
    if (!lat || !lng || !id) {
      return res.status(400).send({ status: 0, message: "Missing required fields" });
    }

    let result = await Settings.updateCompanyLatLng(lat, lng, id);

    if (result) {
      res.send({ status: 1, message: "Company profile updated successfully" });
    } else {
      res.send({ status: 0, message: "Failed to update company profile" });
    }
  } catch (error) {
    console.error("Server error:", error);
    res.status(500).send({ status: 0, message: "Server error: " + error.message });
  }
};

const updateProjectLatLngController = async (req, res) => {
  try {
    let { lat, lng, id } = req.body;
    if (!lat || !lng || !id) {
      return res.status(400).send({ status: 0, message: "Missing required fields" });
    }

    let result = await Community.updateCommunityLatLng(lat, lng, id);

    if (result) {
      res.send({ status: 1, message: "Company profile updated successfully" });
    } else {
      res.send({ status: 0, message: "Failed to update company profile" });
    }
  } catch (error) {
    console.error("Server error:", error);
    res.status(500).send({ status: 0, message: "Server error: " + error.message });
  }
};

const getCompanyProfileDetails =async(req,res)=>{
 
  let data = await Settings.getCompanyProfileDetails()
  if(!empty(data)){
    res.send({
      status:1,data
    })
  }else{
    res.send({
      status:0
    })
  }
}
const updateSocialLinks=async(req,res)=>{
  try {
    const {userId,userType,name,value} = req.body
    let data={}
    if(!empty(name) && !empty(value)){
    if (name === 'facebook'){
      data['facebook_url']= value;
    } 
    if (name === 'twitter'){
      data['twitter_url']= value;
    } 
    if (name === 'youtube'){
      data['youtube_url']= value;
    } 
    if (name === 'google'){
      data['google_url']= value;
    } 
    if (name === 'linkedin'){
      data['linkedIn_url']= value;
    } 

    const result = await Admin.updateUser(userId,data)
    if(result===true){
      res.send({
        status:1
      })
    }else{
      res.send({
        status:0
      })
    }
  }
  } catch (error) {
    console.log(error)
  }
}

const getInstallAddressEmail = async (req, res) => {
  try {
    const data = await Settings.getCompanyProfileDetails();
    const email = (data && data[0] && data[0].install_address_email) ? data[0].install_address_email : '';
    res.send({ status: 1, email });
  } catch (error) {
    console.log(error);
    res.send({ status: 0, email: '' });
  }
};

const updateInstallAddressEmail = async (req, res) => {
  try {
    const { email } = req.body;
    const data = await Settings.getCompanyProfileDetails();
    if (!data || !data[0] || !data[0].id) {
      return res.send({ status: 0, message: 'Company profile not found' });
    }
    const result = await Settings.updateCompanyprofile(
      { install_address_email: email || '' },
      data[0].id
    );
    if (result === true) {
      res.send({ status: 1, message: 'Install address email saved' });
    } else {
      res.send({ status: 0, message: 'Failed to save' });
    }
  } catch (error) {
    console.log(error);
    res.send({ status: 0, message: 'Failed to save install address email' });
  }
};

const getAllRanks=async(req,res)=>{
  try {
    let data= await Settings.getAllRanks()
    if(!empty(data)){
      res.send({
        status:1,data
      })
    }else{
      res.send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const updateRank = async(req,res)=>{
  try {
    let {status,id} = req.body
    let data={}
    data['status'] = status
    let response = await Settings.updateRank(data,id)
    if(response===true){
      res.send({
        status:1
      })
    }else{
      res.send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const navigationControlSetting=async(req,res)=>{
  try {
    let data = await Settings.getNavigation()

    if(data){
      res.send({
        status:1,data
      })
    }else{
      res.send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const addJobTitle = async(req,res)=>{
  try {
    const {userId,values} = req.body
    if(!empty(values)){
      let data={}
      data['job_title'] = values.title
      const result = await Admin.updateUser(userId,data)
      if(result===true){
        res.send({
          status:1
        })
      }else{
        res.send({
          status:0
        })
      }
    }
  } catch (error) {
    console.log(error)
  }
}
const updateSettingsPCB=async(req,res)=>{
  try {
    let {userId,state} = req.body
    let data={}
     data['projects'] = state.projects ===true ? 1 : 0
     data['clients'] = state.clients ===true ? 1 : 0
     data['calendar'] = state.calendar ===true ? 1 : 0
     data['onboarding'] = state.onboarding ===true ? 1 : 0
     data['official_request'] = state.official_request ===true ? 1 : 0
     data['trafficwise'] = state.trafficwise ===true ? 1 : 0
     data['call_center'] = state.call_center ===true ? 1 : 0
     data['crm'] = state.crm ===true ? 1 : 0
     let result = await Settings.updatePCBPermission(data,userId)
     if(result===true){
      res.send({
        status:1
      })
     }else{
      res.send({
        status:0
      })
     }
  } catch (error) {
    console.log(error)
  }
}
const getPcbDetailsForDashboard=async(req,res)=>{
  let {userId,userType} = req.body
  let data = await Request.getAllRequests(null, userId, userType)
  let clientCount = await Settings.getClientCount()
  let projectCount = await Community.getAllCommunitiesCount(userId, userType)
  let installationCount=await Settings.installationCountDashboard(userId, userType)
  let onboardingCount = await Settings.getOnboardingCount()
  let crmCount = await Settings.getCRMDetailsCount()
  let trafficwiseCount = await Settings.trafficwiseCount()
  res.send({
    status:1,onboardingCount,
    requestCount:data.totalCount,clientCount,projectCount,installationCount:installationCount,
    crmCount,
    trafficwiseCount,
  })
}

const fetchclocksettings = async(req,res) =>{
  try{
    const {projectId=null, taskId=null} = req.body ?? {};
    const clocksettings = await Settings.fetchclocksettings()
    let allServices = []
    let allAddlServices = []
    if(projectId && taskId){
      allServices = await Recipe.fetchAllServicesByProject(projectId, taskId)
    }
    if(projectId){
      allAddlServices = await Recipe.fetchAllAdditionalServicesByProject(projectId)
    }
    if(clocksettings?.length > 0){
      res.send({status:1,clocksettings:clocksettings,allServices, allAddlServices})
    }else{
      res.send({status:0,message:'No clock settings found'})
    }
  }catch(error){
    console.log('Error fetching',error);
    res.send({status:500, message:'Server Error',error:error})
  }
}

const fetchclocksettingsById = async(req,res) =>{
  try{
    const {id} = req.body
    const clocksettings = await Settings.fetchclocksettings(id)
    if(clocksettings?.length > 0){
      res.send({status:1,clocksettings:clocksettings})
    }else{
      res.send({status:0,message:'No clock settings found'})
    }
  }catch(error){
    console.log('Error fetching',error);
    res.send({status:500, message:'Server Error',error:error})
  }
}

const editclocksettings = async(req,res) =>{
  try{
    const {editId,userId,values} = req.body
    const time = values?.time
    let timestamp = Math.round(moment().valueOf() / 1000);
    const updated = await Settings.editclocksettings(editId,time,userId,timestamp)
    if(updated){
      res.send({status:1,message:'Clock settings updated successfully'})
    }else{
      res.send({status:0,message:'Failed to update clock settings'})
    }
  }catch(error){
    console.log('Error fetching',error);
    res.send({status:500, message:'Server Error',error:error})
  }
}
const updateCompanyAddress=async(req,res)=>{
  try {
    let {values,id} = req.body
    if(!empty(values)){
      let data={}
      data['address'] = values?.address
      data['city'] = values?.city
      data['state'] = values?.state
      data['zipcode'] = values?.zipcode
      data['phone'] = typeof values?.phoneNumber !== 'undefined' ? values.phoneNumber : values?.phone
      data['phone_country_code'] = typeof values?.phone_country_code !== 'undefined' ? values.phone_country_code : values?.phone_country_code
      data['company_fax_number'] = values?.company_fax_number
      data['company_mail'] = values?.company_mail
      data['company_website'] = values?.company_website
      data['lat'] = null
      data['lng'] = null
      let result = await Settings.updateCompanyprofile(data,id)
      if(result===true){
        res.send({
          status:1
        })
      }else{
        res.send({
          status:0
        })
      }
    }else{
      res.send({
        status:0
      })
    }
  } catch (error) {
    console.log(error)
  }
}
const fetchRefreshToken=async(req,res)=>{
  try {
    let result = await Quickbook.fetchRefreshTokenForUI();
    let tokenValid = await Quickbook.checkValidRefreshToken();
    if(result){
      res.send({ status:1, message:'Token fetched successfully', refreshToken:result?.refreshToken,company:result?.company, tokenValid:tokenValid })
    }else{
      res.send({ status:0, message:'Failed to fetch token' })
    }
  } catch (error) {
    console.log('Error fetching token : ',error)
    res.send({ status:0, message:'Error fetching token' })
  }
}
const updateRefreshToken=async(req,res)=>{
  try {
    let { newToken } = req.body
    if(!empty(newToken)){
      let result = await Quickbook.updateRefreshToken(newToken);
      // updateQbTokenOnAllInstallations is now in quickbook.js to avoid circular dependency
      let updateOnAllOtherInstallations = await Quickbook.updateQbTokenOnAllInstallations(newToken);
      if(result){
        res.send({ status:1, message:'Token updated successfully' })
      }else{
        res.send({ status:0, message:'Failed to update token' })
      }
    }else{
      res.send({ status:0, message:'Failed to update token' })
    }
  } catch (error) {
    console.log('Error updating token : ',error)
    res.send({ status:0, message:'Error updating token' })
  }
}

const getAllPCBItems = async(req,res)=>{
  try {
    const{userId} =req.body
    const response = await Settings.getAllPcbItems()
    const usersPcbItem = await Settings.getUsersPcbItems(userId)
    const usersPcbItemOrder = await Settings.getUserPcbItemsInOrder(userId)
    const usersPcbPreferences = await Settings.getUserPcbPreferencesByUser(userId)
    if(response){
      res.send({status:1,result:response,usersPcbItem,usersPcbItemOrder,usersPcbPreferences})
    }else{
      res.send({status:0})

    }
  } catch (error) {
    res.send({ status:0, message:'Error getting pcb items' })
  }
}

// const updateUsersPcbItems = async(req,res)=>{
//   try {
//     const{userId, selectedItems}= req.body
//     const result = await Settings.updateUsersPcbItems(userId,selectedItems)
//     if(result){
//          res.send({status:1,result})
//     }else{
//       res.send({status:0})
//     }
//   } catch (error) {
//     res.send({ status:0, message:'Error updating pcb items' })
//   }
// }

const updateUsersPcbItems = async (req, res) => {
  try {
    const { userId, selectedItems } = req.body;
    const now = Math.round(moment().valueOf() / 1000);

    // Validate input data
    if (!userId) {
      return res.send({ status: 0, message: "User ID is required" });
    }
    
    if (!Array.isArray(selectedItems)) {
      return res.send({ status: 0, message: "Selected items must be an array" });
    }

    // Log the incoming data for debugging
    console.log('Updating PCB items for user:', userId);
    console.log('Selected items count:', selectedItems.length);
    console.log('First few items:', selectedItems.slice(0, 3));

    // 1) Extract only enabled items for pcb_item_order (main permission must be ON)
    const enabledItems = selectedItems.filter(item => {
      // Check if main permission is enabled (either pcb_email_enabled or pcb_sms_enabled being 1)
      // return item.pcb_email_enabled === 1 || item.pcb_sms_enabled === 1;
      return true;
    });

    console.log('Total items received:', selectedItems.length);
    console.log('Enabled items for pcb_item_order:', enabledItems.length);
    console.log('Enabled items:', enabledItems.map(item => ({ id: item.pcb_item_id, email: item.pcb_email_enabled, sms: item.pcb_sms_enabled })));

    // 2) Save/update PCB items order with only enabled items
    const result = await Settings.updateUsersPcbItems(userId, enabledItems);
    if (!result) return res.send({ status: 0 });

    // 3) Get existing active preferences for this user
    const existing = await Settings.getUserPcbPreferencesByUser(userId);
    const existingMap = new Map((existing || []).map(r => [Number(r.pcb_item_id), r]));

    // 4) Process ALL items (both enabled and disabled) for preferences
    await Promise.all(
      selectedItems.map(async (item) => {
        const { pcb_item_id, pcb_email_enabled = 0, pcb_sms_enabled = 0 } = item;
        const existingPref = existingMap.get(Number(pcb_item_id));

        if (existingPref) {
          // Update existing preference
          await Settings.updateUserPcbPreference(existingPref.id, {
            pcb_email_enabled: pcb_email_enabled ? 1 : 0,
            pcb_sms_enabled: pcb_sms_enabled ? 1 : 0,
            status: 1,
            updated_on: now,
          });
        } else {
          // Add new preference
          await Settings.addUserPcbPreference({
            user_id: userId,
            pcb_item_id,
            pcb_email_enabled: pcb_email_enabled ? 1 : 0,
            pcb_sms_enabled: pcb_sms_enabled ? 1 : 0,
            timestamp: now,
            updated_on: null,
            status: 1,
          });
        }
      })
    );

    return res.send({ status: 1, result });
  } catch (error) {
    console.log("Error updating pcb items & prefs:", error);
    
    // Provide more specific error messages
    let errorMessage = "Error updating pcb items";
    if (error.message && error.message.includes('Data too long')) {
      errorMessage = "PCB items data is too long. Please contact administrator to increase database column size.";
    } else if (error.message && error.message.includes('selectedPcbIds')) {
      errorMessage = "Invalid PCB items data provided";
    }
    
    return res.send({ status: 0, message: errorMessage, error: error.message });
  }
};

// === Add User PCB Preference ===
const addUserPcbPreferenceController = async (req, res) => {
  try {
    const { userId, pcb_item_id, pcb_email_enabled, pcb_sms_enabled } = req.body;
    if (!userId || !pcb_item_id) {
      return res.send({ status: 0, message: 'Missing required fields: userId, pcb_item_id' });
    }

    const now = Math.round(moment().valueOf() / 1000);
    const data = {
      user_id: userId,
      pcb_item_id,
      pcb_email_enabled: pcb_email_enabled ? 1 : 0,
      pcb_sms_enabled: pcb_sms_enabled ? 1 : 0,
      timestamp: now,
      updated_on: null,
      status: 1,
    };

    const result = await Settings.addUserPcbPreference(data); // uses your model fn
    if (result) {
      return res.send({ status: 1, message: 'Preference added successfully', result });
    }
    return res.send({ status: 0, message: 'Failed to add preference' });
  } catch (error) {
    console.log('Error adding user pcb preference:', error);
    return res.send({ status: 500, message: 'Server Error' });
  }
};

// === Update User PCB Preference ===
const updateUserPcbPreferenceController = async (req, res) => {
  try {
    const { id, pcb_email_enabled, pcb_sms_enabled, status } = req.body;
    if (!id) {
      return res.send({ status: 0, message: 'Missing required field: id' });
    }

    const now = Math.round(moment().valueOf() / 1000);
    const data = {
      updated_on: now,
    };

    if (typeof pcb_email_enabled !== 'undefined') data.pcb_email_enabled = pcb_email_enabled ? 1 : 0;
    if (typeof pcb_sms_enabled !== 'undefined') data.pcb_sms_enabled = pcb_sms_enabled ? 1 : 0;
    if (typeof status !== 'undefined') data.status = Number(status);

    const updated = await Settings.updateUserPcbPreference(id, data); // uses your model fn
    if (updated) {
      return res.send({ status: 1, message: 'Preference updated successfully' });
    }
    return res.send({ status: 0, message: 'Failed to update preference' });
  } catch (error) {
    console.log('Error updating user pcb preference:', error);
    return res.send({ status: 500, message: 'Server Error' });
  }
};

// === Get All Preferences for a User (status != 0) ===
const getUserPcbPreferencesController = async (req, res) => {
  try {
    const { userId } = req.body;
    if (!userId) {
      return res.send({ status: 0, message: 'Missing required field: userId' });
    }

    const rows = await Settings.getUserPcbPreferencesByUser(userId); // uses your model fn
    if (rows && rows.length) {
      return res.send({ status: 1, data: rows });
    }
    return res.send({ status: 0, message: 'No preferences found', data: [] });
  } catch (error) {
    console.log('Error fetching user pcb preferences:', error);
    return res.send({ status: 500, message: 'Server Error' });
  }
};

// === Get Single Preference by ID (status != 0) ===
const getUserPcbPreferenceByIdController = async (req, res) => {
  try {
    const { id } = req.body;
    if (!id) {
      return res.send({ status: 0, message: 'Missing required field: id' });
    }

    const row = await Settings.getUserPcbPreferenceById(id); // uses your model fn
    if (row) {
      return res.send({ status: 1, data: row });
    }
    return res.send({ status: 0, message: 'Preference not found' });
  } catch (error) {
    console.log('Error fetching user pcb preference by id:', error);
    return res.send({ status: 500, message: 'Server Error' });
  }
};

module.exports = {
  getAllSettings,
  addUserRole,
  editUserRole,
  deleteUserRole,
  getUserRoleById,
  addService,
  getServiceById,
  editService,
  deleteService,
  addpartnerTypes,
  editpartnerType,
  deletepartnerType,
  getpartnerTypebyId,
  dashboardCount,projectStatistics,projectStatisticsOptimized,
  updateCompanyprofile,
  getCompanyProfileDetails,
  updateSocialLinks,
  getInstallAddressEmail,
  updateInstallAddressEmail,
  getAllRanks,
  updateRank,
  navigationControlSetting,
  addJobTitle,
  UpcomingprojectStatistics,
  updateSettingsPCB,
  getPcbDetailsForDashboard,
  fetchclocksettings,
  editclocksettings,
  fetchclocksettingsById,
  updateCompanyAddress,
  updateRefreshToken,
  fetchRefreshToken,
  updateCompanyLatLngController,
  getAllPCBItems,
  updateUsersPcbItems,
  updateProjectLatLngController,
  addUserPcbPreferenceController,
  updateUserPcbPreferenceController,
  getUserPcbPreferencesController,
  getUserPcbPreferenceByIdController,
};
