import { Response } from "express";
import CONSTANTS from "../config/constants";
import log from "../config/log";
import {
    redisSubscriber,
    REDIS_CHANNEL
} from "../config/redis/redis";
import clientDB from "../models/client.model";
import complaintDB from "../models/complaint.model";
import occupancyDB from "../models/occupancy.model";
import propertyDB from "../models/property.model";
import staffDB from "../models/staff.model";
import tenantDB from "../models/tenant.model";
import CustomRequest from "../types/requestType";
import sendSMS from "../utils/sendSMS";
import sendNotification from "../utils/sendNotification";
import moment from "moment";
import fsPromises from "fs/promises";
import fs from "fs";
import {
  complaintsForAdmin,
  complaintsForClient,
  complaintsForStaff,
  propComplaintsForClient,
  propComplaintsForAdmin,
  complaintStaffCounts,
  complaintsForProperty,
  complaintsForClientWeb,
  propComplaintsForStaff,
  propComplaintStaffCounts,
  propComplaintsForClientWeb,
} from "../utils/client/complaintsByUserType";
import flatDB from "../models/flat.model";
import notificationPrefDB from "../models/notificationPref.model";
import {
  sendWhatsappGharAssignStaff,
  sendWhatsappGharAssignTenant,
  sendWhatsappGharNewCompOwner,
  sendWhatsappGharNewCompTenant,
  sendWhatsappGharResolvedOwner,
  sendWhatsappGharResolvedTenant,
} from "../utils/sendWhatsappGharMumbai";
import {
  sendWhatsappAssignedNewPropComplaintStaff,
  sendWhatsappAssignedStaff,
  sendWhatsappAssignedStaffNew,
  sendWhatsappAssignedTenant,
  sendWhatsappNewCompOwner,
  sendWhatsappNewCompTenant,
  sendWhatsappResolvedOwner,
  sendWhatsappResolvedTenant,
} from "../utils/sendWhatsappWithConfig";
import settingsDB from "../models/settings.model";
import { cli } from "winston/lib/winston/config";
import { isUserPartner } from "../utils/isUserPartner";
import { logActivity } from "../utils/logActivity";
import { isPrivilegedStaff } from "../utils/isPrivilegedStaff";
import clientConfigDB from "../models/clientConfig.model";
import autoAssignComplaint from "../utils/autoAssignComplaint";
import getComplaintAssignedTo from "../utils/getComplaintAssignedTo";
import notificationDB from "../models/notification.model";
import { clientComplaintGraphX } from "../utils/client/getGraphData";
import propertiesTypes from "../schemas/property.schema";
import { GoogleGenAI } from '@google/genai';
import getReopenReason, { getReopenReasonIdByDescription } from "../utils/getComplaintReopenReasons";
import { getClientWhatsappCredentialsMessageCentral } from "../utils/getClientWhatsappCredentials";
import sendWhatsappMC from "../utils/sendWhatsappMessageCentral";
import whatsappPendingMessagesDB from "../models/whatsappPendingMessages.model";
// import sendWhatsappMC from "../utils/sendWhatsappMessageCentral";

const complaints: any = {};

complaints.Add = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "Add";

  try {
    let { title, description } = req.body;
    const tenantId = req.id;
    const clientId = req.clientId;
    const file = req.file;
    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Title [${title}], Description [${description}] `
    );

    if (!title || title === "undefined") title = null;
    if (!description || description === "undefined") description = null;

    if (!title) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], Empty Title`
      );
      if (file) await fsPromises.unlink(file.path);
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const tenant = await tenantDB.getById({ id: tenantId });

    if (!tenant) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], No Tenant Found`
      );
      if (file) await fsPromises.unlink(file.path);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let occupancy = await occupancyDB.getByClientIdAndTenantId({
      clientId,
      tenantId: tenant?.id,
    });

    if (!occupancy) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], No Occupancy Found`
      );
      if (file) await fsPromises.unlink(file.path);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    occupancy = occupancy[0];

    if (
      occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.OCCUPIED &&
      occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT
    ) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], Tenant is not Occupied`
      );
      if (file) await fsPromises.unlink(file.path);

      return res.status(400).json({
        msg: "You are not allowed to raise complaint",
        isSuccess: false,
      });
    }

    let client = await clientDB.getById({ id: occupancy.clientId });
    const property = await propertyDB.getById({ id: occupancy.propId });

    let notifyToPropNumber = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.NOTIFY_TO_PROP_NUMBER
    });

    if(notifyToPropNumber && Number(notifyToPropNumber?.value) === 1) {
      client.mobile = property?.ownerMobile;
      client.name = property?.ownerName;
    }

    let filePath = null;
    if (file) {
      const folderName = `complaints/${moment().format("DD_MM_YYYY")}`;
      const folderPath = `uploads/documents/client_${occupancy.clientId}/${folderName}`;

      if (!fs.existsSync(folderPath)) {
        await fsPromises.mkdir(folderPath, { recursive: true });
      }

      const oldPath = `uploads/tmp/${file.filename}`;
      const newPath = `${folderPath}/${file.filename}`;
      await fsPromises.copyFile(oldPath, newPath);

      filePath = `${process.env.UPLOAD_PATH}/documents/client_${occupancy.clientId}/${folderName}/${file.filename}`;
    }

    let flatName = "";

    if (property.type === CONSTANTS.PROPERTY_TYPE.FLAT) {
      const { name } = await flatDB.getById({ id: occupancy.flatId });
      flatName = "Flat No " + name;
    } else {
      flatName =
        occupancy.floor === "G" ? "Ground Floor" : "Floor " + occupancy.floor;
    }

    const complaintId = await complaintDB.create({
      clientId: occupancy.clientId,
      tenantId: tenant?.id,
      propId: occupancy.propId,
      roomId: occupancy.roomId,
      raisedBy: CONSTANTS.USER_TYPE.TENANT,
      raisedFor: CONSTANTS.COMPLAIN_FOR.ROOM, //For Tenant
      //floor: occupancy.floor,//Sukhbir on 29th nov 2024 10:00PM
      floor: flatName,
      img: filePath || "",
      title,
      raisedById: tenant?.id,
      description,
    });

    if (file) await fsPromises.unlink(file.path);

    if (client.regId) {
        await sendNotification({
          title: `A new complaint has been received`,
          message: `Please review the details at your earliest convenience to determine the next steps. Kipinn Team`,
          regId: client.regId,
          userId: client.id,
          userType: CONSTANTS.USER_TYPE.CLIENT,
          notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
          clientId: client.id,
        });
    } else {
      await notificationDB.add({
        userId: client.id,
        userType: CONSTANTS.USER_TYPE.CLIENT,
        title: `A new complaint has been received`,
        message: `Please review the details at your earliest convenience to determine the next steps. Kipinn Team`,
        notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
      });
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${client.id}] Title [${title}], Description [${description}], No Client's RegId Found`
      );
    }

    const propSettings = await settingsDB.getByClientIdAndPropId({
      clientId: occupancy.clientId,
      propId: occupancy.propId,
    });

    if (propSettings) {
      if (propSettings.sms === 5) {
        log.info(
          `[${C}], [${F}], Client Id [${occupancy.clientId}], SMS Notification not enabled`
        );
        const msg = CONSTANTS.MSG.COMPLAINT_RECEIVED.replace(
          "{#var#}",
          property.name
        );
        sendSMS(
          client.mobile,
          msg,
          CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RECEIVED
        );
      }
      if (propSettings.whatsApp === 1) {
        log.info(
          `[${C}], [${F}], Client Id [${occupancy.clientId}], WhatsApp Notification enabled`
        );
        let footerText = propSettings.footer || "The Kipinn Team";
        /** Notify Owner**/
        let bodyVal = [client.name, tenant.name, `${flatName + ", " + property.name}`, tenant.mobile, title];
        await whatsappPendingMessagesDB.add ({
          clientId,
          propId: occupancy.propId,
          userType: CONSTANTS.USER_TYPE.CLIENT,
          userId: clientId,
          userName: client.name,
          userMobile: client.mobile,
          templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_REGISTRATION,
          payload : JSON.stringify(bodyVal),
          file: null,
        });

        /** Notify Tenant**/
        bodyVal = [tenant?.name, title, footerText.replace("Team", "").trim()];
        await whatsappPendingMessagesDB.add ({
          clientId,
          propId: occupancy.propId,
          userType: CONSTANTS.USER_TYPE.TENANT,
          userId: clientId,
          userName: tenant.name,
          userMobile: tenant.mobile,
          templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_REGISTRATION,
          payload : JSON.stringify(bodyVal),
          file: null,
        });


        // let whatsappAgreegrator = await clientConfigDB.getClientConfig({
        //   clientId,
        //   provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
        //   type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.WHATSAPP_AGGREGATOR
        // });

        // let noitifyOwnerTemplate = await getClientWhatsappCredentialsMessageCentral(Number(clientId), property?.id, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_REGISTRATION, CONSTANTS.USER_TYPE.CLIENT);

        // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && noitifyOwnerTemplate) {
        //     // log.info(
        //     //   `[${C}], [${F}], Client Id [${clientId}], TenantId [${tenantId}], Sending through Message Central to client`
        //     // );
        //     // const ownerBodyValues: Record<string, string> = {
        //     //   body_1: `${client.name}`,
        //     //   body_2: `${tenant.name}`,
        //     //   body_3: `${flatName + ", " + property.name}`,
        //     //   body_4: `${tenant.mobile}`,
        //     //   body_5: `${title}`
        //     // };

        //     // //Sent To owner
        //     // await sendWhatsappMC(
        //     //   client.mobile,
        //     //   Number(clientId),
        //     //   Number(occupancy.propId),
        //     //   ownerBodyValues,
        //     //   CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_REGISTRATION,
        //     //   CONSTANTS.USER_TYPE.CLIENT,
        //     //   CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
        //     // );
        // } else {
        //   // log.info(
        //   //   `[${C}], [${F}], Client Id [${clientId}], TenantId [${tenantId}], Sending through intrakt to client`
        //   // );
        //   // sendWhatsappNewCompOwner(
        //   //   client.mobile,
        //   //   client.name,
        //   //   tenant.name,
        //   //   flatName + ", " + property.name,
        //   //   tenant.mobile,
        //   //   title,
        //   //   Number(clientId),
        //   // );
        // }

        //let noitifyToTenant = await getClientWhatsappCredentialsMessageCentral(Number(clientId), property?.id, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_REGISTRATION, CONSTANTS.USER_TYPE.TENANT);
        // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && noitifyToTenant) {
        //   // log.info(
        //   //   `[${C}], [${F}], Client Id [${clientId}], TenantId [${tenantId}], Sending through Message Central to tenant`
        //   // );
        //   // const bodyValues: Record<string, string> = {
        //   //   body_1: `${tenant?.name}`,
        //   //   body_2: `${title}`,
        //   //   body_3: `${footerText.replace("Team", "").trim()}`
        //   // };
        //   // //Sent To tenant
        //   // await sendWhatsappMC(
        //   //   tenant?.mobile,
        //   //   Number(clientId),
        //   //   Number(occupancy.propId),
        //   //   bodyValues,
        //   //   CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_REGISTRATION,
        //   //   CONSTANTS.USER_TYPE.TENANT,
        //   //   CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
        //   // );
        // } else {
        //   // log.info(
        //   //   `[${C}], [${F}], Client Id [${clientId}], TenantId [${tenantId}], Sending through intrakt to tenant`
        //   // );
        //   // sendWhatsappNewCompTenant(
        //   //   tenant.mobile,
        //   //   tenant.name,
        //   //   title,
        //   //   property.name,
        //   //   footerText,
        //   //   Number(clientId),
        //   // );
        // }
      }
    }

    const autoAssign = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.AUTO_ASSIGN_COMPLAINT,
    });

    // const helpDesk = await staffDB.getByClientIdAndRole({
    //   clientId,
    //   role: CONSTANTS.STAFF_ROLES.HELPDESK,
    // });

    if (autoAssign && Number(autoAssign?.value) === 1) {
      const assignedTo = await getComplaintAssignedTo(title);
      let assignedToStaff = await staffDB.getByClientIdAndRoleAndProperty({
        clientId,
        role: assignedTo,
        status: CONSTANTS.STAFF_STATUS.ACTIVE,
        propId: Number(occupancy.propId),
      });
      if (!assignedToStaff || assignedToStaff.length === 0) {
        assignedToStaff = await staffDB.getByClientIdAndRoleAndProperty({
          clientId,
          role: CONSTANTS.STAFF_ROLES.HELPDESK,
          status: CONSTANTS.STAFF_STATUS.ACTIVE,
          propId: Number(occupancy.propId),
        });
      }
      if (assignedToStaff && assignedToStaff.length > 0) {
        let autoAssigned = await autoAssignComplaint(
            clientId!,
            complaintId,
            assignedToStaff[0]?.id,
            CONSTANTS.COMPLAIN_FOR.ROOM,
          );
        

        if (autoAssigned) {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Assigned Staff Id [${assignedToStaff[0].id}], Assigned Staff Role [${assignedToStaff[0].role}], Complaint Id [${complaintId}], Complaint Auto Assigned`
          );
        } else {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Assigned Staff Id [${assignedToStaff[0].id}], Assigned Staff Role [${assignedToStaff[0].role}], Complaint Id [${complaintId}], Complaint Not Auto Assigned`
          );
        }
      }
    }

    log.info(
      `[${C}], [${F}], Tenant Id [${tenant?.id}], Title [${title}], Description [${description}], Complaint Added Successfully`
    );
    return res.status(200).json({
      msg: "Complaint added successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.Reopen = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "Reopen";

  try {
    let { description, complaintId, reopenReason=null, } = req.body;
    const tenantId = req.id;
    const clientId = req.clientId;
    const file = req.file;
    const status = CONSTANTS.COMPLAINT_STATUS.REOPENED;

    if (typeof reopenReason !== "number" && isNaN(Number(reopenReason))) {
      const reopenReasonId = await getReopenReasonIdByDescription(reopenReason);
      if (reopenReasonId) {
        reopenReason = reopenReasonId;
      } else {
        reopenReason = 1;
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Re-open Reason [${reopenReason}], Description [${description}], Is File Uploaded [${file ? `Yes, File [${JSON.stringify(file)}]` : "No"}] `
    );

    if (!description || description === "undefined") description = null;

    const tenant = await tenantDB.getById({ id: tenantId });

    if (!tenant) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}],Complaint Id [${complaintId}], Re-open Reason [${reopenReason}], Description [${description}], No Tenant Found`
      );
      if (file) await fsPromises.unlink(file.path);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let filePath = null;
    if (file) {
      const folderName = `complaints/${moment().format("DD_MM_YYYY")}`;
      const folderPath = `uploads/documents/client_${clientId}/${folderName}`;

      if (!fs.existsSync(folderPath)) {
        await fsPromises.mkdir(folderPath, { recursive: true });
      }

      const oldPath = `uploads/tmp/${file.filename}`;
      const newPath = `${folderPath}/${file.filename}`;
      await fsPromises.copyFile(oldPath, newPath);

      filePath = `${process.env.UPLOAD_PATH}/documents/client_${clientId}/${folderName}/${file.filename}`;
    }

    const client = await clientDB.getById({ id: clientId });

    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Re-open Reason [${reopenReason}], Description [${description}], No Client Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let complaint = await complaintDB.getById({ id: complaintId });
    if (!complaint) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], No Complaint Found With Id`
      );

      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    await complaintDB.updateStatus({
      id: complaintId,
      status,
    });

    await complaintDB.updateDescription({
      id: complaintId,
      description: description || null,
    });

    await complaintDB.updateImg({
      id: complaintId,
      img: filePath || null,
    });

    await complaintDB.updateReopenReason({
      id: complaintId,
      reopenReason,
    });

    let msg = "Complaint Reopened Successfully";

    let isNotiSent = false;
    let isSent = false;

    // if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
    //   if (tenant.regId) {
    //     isNotiSent = await sendNotification({
    //       title: `Your Complaint has been Reopened`,
    //       message: `We've reopened this to ensure your concerns are fully addressed. Thanks for your feedback.`,
    //       regId: tenant.regId,
    //       userId: tenant.id,
    //       userType: CONSTANTS.USER_TYPE.TENANT,
    //       notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
    //       clientId: client.id,
    //     });
    //   } else {
    //     log.info(
    //       `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Tenant Id [${tenant.id}], No Tenant's RegId Found`
    //     );
    //   }
    // }

    // const propSettings = await settingsDB.getByClientIdAndPropId({
    //   clientId,
    //   propId: complaint.propId,
    // });

    // if (propSettings) {
    //   // if (propSettings.sms === 5) {
    //   //   log.info(
    //   //     `[${C}], [${F}], Client Id [${clientId}], SMS Notification not enabled`
    //   //   );
    //   //   const msg = CONSTANTS.MSG.COMPLAINT_REOPENED;
    //   //   if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
    //   //   isSent = await sendSMS(
    //   //     tenant.mobile,
    //   //     msg,
    //   //     CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RESOLVED
    //   //   );
    //   //   } else {
    //   //     if(Number(req.id) != Number(clientId)) {
    //   //       isSent = await sendSMS(
    //   //         client.mobile,
    //   //         msg,
    //   //         CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RESOLVED
    //   //       );
    //   //     }
    //   //   }
    //   // }
    //   if (propSettings.whatsApp === 1) {
    //     log.info(
    //       `[${C}], [${F}], Client Id [${clientId}], WhatsApp Notification not enabled`
    //     );
    //     //let footerText = propSettings.footer || "The Kipinn Team";
    //     if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
    //       sendWhatsappResolvedTenant(
    //         tenant.mobile,
    //         tenant.name,
    //         complaint.title,
    //         Number(clientId)
    //       );
    //       sendWhatsappResolvedOwner(
    //         client.mobile,
    //         client.name,
    //         complaint.title,
    //         tenant.name,
    //         Number(clientId)
    //       );
    //     } else {
    //       if(Number(req.id) != Number(clientId)) {
    //         sendWhatsappResolvedOwner(
    //           client.mobile,
    //           client.name,
    //           complaint.title,
    //           client.name,
    //           Number(clientId)
    //         );
    //       }
    //     }
    //   }
    // }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Is SMS Sent [${isSent}], Is Noti Sent [${isNotiSent}] ${msg}`
    );
      
    if (file) await fsPromises.unlink(file.path);

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenant?.id}],Complaint Id [${complaintId}], Re-open Reason [${reopenReason}], Description [${description}], Complaint Re-opened Successfully`
    );

    return res.status(200).json({
      msg: "Complaint re-opened successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.AddFeedback = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "AddFeedback";

  try {
    const { rating, feedback, complaintId } = req.body;
    const tenantId = req.id;
    log.info(
      `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}]`
    );

    const tenant = await tenantDB.getById({ id: tenantId });

    if (!tenant) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], No Tenant Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const occupancy = await occupancyDB.getByTenantId({
      tenantId: tenant?.id,
    });

    if (!occupancy) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], No Occupancy Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    if (
      occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.OCCUPIED &&
      occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT
    ) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], Tenant is not Occupied`
      );

      return res.status(400).json({
        msg: "You are not allowed to raise complaint",
        isSuccess: false,
      });
    }

    // const client = await clientDB.getById({ id: occupancy.clientId });
    // const property = await propertyDB.getById({ id: occupancy.propId });

    await complaintDB.updateFeedback({
      id: complaintId,
      feedback,
      rating,
    });

    let isNotiSent = false;

    // if (tenant.regId) {
    //   isNotiSent = await sendNotification({
    //     title: `Your complaint submitted successfully`,
    //     message: `Your complaint has been successfully forwarded to the owner for review. We will keep you updated on the progress.`,
    //     regId: tenant.regId,
    //     userId: tenant.id,
    //     userType: CONSTANTS.USER_TYPE.TENANT,
    //   });
    // } else {
    //   log.info(
    //     `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], No Tenant's RegId Found`
    //   );
    // }

    // const msg = CONSTANTS.MSG.COMPLAINT_SUBMITTED;

    // const isSent = await sendSMS(
    //   tenant.mobile,
    //   msg,
    //   CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_SUBMITTED
    // );

    // let isNotiSent2 = false;
    // if (client.regId) {
    //   isNotiSent2 = await sendNotification({
    //     title: `A new complaint has been received`,
    //     message: `Please review the details at your earliest convenience to determine the next steps. Kipinn Team`,
    //     regId: client.regId,
    //     userId: client.id,
    //     userType: CONSTANTS.USER_TYPE.CLIENT,
    //   });
    // } else {
    //   log.info(
    //     `[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${client.id}] Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], No Client's RegId Found`
    //   );
    // }

    // const msg2 = CONSTANTS.MSG.COMPLAINT_RECEIVED.replace(
    //   "{#var#}",
    //   property.name
    // );

    // const isSent2 = await sendSMS(
    //   client.mobile,
    //   msg2,
    //   CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RECEIVED
    // );

    log.info(
      `[${C}], [${F}], Tenant Id [${tenant?.id}], Complaint Id [${complaintId}], Rating [${rating}], Feedback [${feedback}], Feedback and Rating Added Successfully`
    );
    return res.status(200).json({
      msg: "Feedback Submitted Successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForTenant = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForTenant";

  try {
    const tenantId = req.id;
    const clientId = req.clientId;
    log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}]`);

    const tenant = await tenantDB.getById({ id: tenantId });
    const client = await clientDB.getById({ id: clientId });

    if (!tenant) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Tenant Found`);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    // const complaints = await complaintDB.getByTenantId({
    //   tenantId: tenant?.id,
    // });

    const complaints = await complaintDB.getByTenantIdAndClientId({
      tenantId: tenant?.id,
      clientId,
    });

    if(complaints && complaints.length > 0){
      for(let complaint of complaints){
        if(complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName){
          complaint.staffName = client.name;
        }
      }
    }

    const reopenReasons = await getReopenReason(0);

    return res.status(200).json({
      msg: "Complaint list sent successfully",
      data: complaints,
      reopenReasons,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForClient = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForClient";

  try {
    // let clientId = req.id;
    let staff = null;
    const userType = req.userType;

    let { pageNum, filter, status, filterVal, tenantId } = req.query;

    if (typeof filterVal === "string") {
      filterVal = filterVal.split(",").map(v => v.trim());
    }

    let complaints: any = [];
    let complaintCounts = {
      new: 0,
      assigned: 0,
      closed: 0,
    };

    let properties = [];
    let staffs = [];

    const limit = 10;

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    const client = await clientDB.getById({ id: clientId });

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      // const client = await clientDB.getById({ id: clientId });
      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], ${
          isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`
        }, Page Num [${pageNum}], Status [${status}], Filter [${filter}], Filter Val [${filterVal}], Type of Filter Val [${typeof filterVal}], Tenant Id [${tenantId}], ${
          isPartner ? "Partner Requesting" : "Client Requesting"
        }....`
      );

      if (Number(tenantId)) {
        complaints = await complaintDB.getByTenantIdAndClientId({
          tenantId,
          clientId,
        });
        complaintCounts = await complaintDB.getComplaintCountsForTenant({
          tenantId,
          clientId,
        });
      } else {
        complaints = await complaintsForClient(
          filter?.toString() || "",
          status?.toString() || "",
          Number(pageNum),
          limit,
          Number(clientId),
          // String(filterVal),
          filterVal,
        );

        if (filter === "PR") {
          complaintCounts = await complaintDB.getComplaintCountsByPropForClient({
            clientId,
            propIds: filterVal,
          });
        } else if (filter === "S") {
          complaintCounts = await complaintDB.getComplaintCountsByStaffForClient({
            clientId,
            staffs: filterVal,
          });
        } else if (filter === "C") {
          complaintCounts = await complaintDB.getComplaintCountsByCategoryForClient({
            clientId,
            titles: filterVal,
          });
        } else {
          complaintCounts = await complaintDB.getComplaintCountsForClient({
            clientId,
          });
        }
      }

      properties = await propertyDB.getPropIdsByClientId({
        clientId: clientId,
        status: CONSTANTS.PROPERTY_STATUS.ACTIVE,
      });

      staffs = await staffDB.getByClientId({
        clientId,
      });

    } else {
      const staffId = req.id;

      staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Page Num [${pageNum}], Filter [${filter}], Staff Id [${staffId}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Status [${status}], Filter [${filter}], Filter Val [${filterVal}], Type of Filter Val [${typeof filterVal}], Tenant Id [${tenantId}], Staff Id [${staffId}], Staff Requested....`
      );

      if (Number(tenantId)) {
        complaints = await complaintDB.getByTenantIdAndClientId({
          tenantId,
          clientId,
        });
        complaintCounts = await complaintDB.getComplaintCountsForTenant({
          tenantId,
          clientId,
        });
      } else {
        if (
          staff.role === CONSTANTS.STAFF_ROLES.ADMIN ||
          staff.role === CONSTANTS.STAFF_ROLES.WARDEN ||
          staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE
        ) {
          complaints = await complaintsForAdmin(
            filter?.toString() || "",
            status?.toString() || "",
            Number(pageNum),
            limit,
            Number(clientId),
            Number(staffId),
            filterVal,
          );
          complaintCounts = await complaintStaffCounts(
            Number(clientId),
            Number(staffId),
            String(filter),
            filterVal,
          );
        } else {
          complaints = await complaintsForStaff(
            filter?.toString() || "",
            status?.toString() || "",
            Number(pageNum),
            limit,
            Number(staffId),
            filterVal,
          );
          complaintCounts = await complaintStaffCounts(
            Number(clientId),
            Number(staffId),
            String(filter),
            filterVal,
          );
        }
      }
      const staffLinkedProps = await propertyDB.getPropsByStaffId({
        staffId: staff.id,
      });

      properties = staffLinkedProps;
    }

    if (complaints && complaints.length > 0) {
      for (let complaint of complaints) {
        if (complaint.status >= CONSTANTS.COMPLAINT_STATUS.ASSIGNED) {
          // complaint.resolveTime = moment(complaint.resolvedAt).diff(moment(complaint.createdAt), "hours");
          const {name} = await staffDB.getById ({
              id: complaint.assignedTo,
            });
          complaint.staffName = name;
        }

        if (complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName) {
          complaint.staffName = client.name;
        }
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Filter [${filter}], Complaint list sent successfully`
    );

    return res.status(200).json({
      msg: "Complaint list sent successfully",
      stats: complaintCounts,
      data: complaints || [],
      propList: properties,
      staffs: staffs,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForClientX = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForClientX";

  try {
    const userType = req.userType;

    let { pageNum, status, staffFilter, titleFilter, propFilter, tenantId } = req.query;

    log.info(
      `[${C}], [${F}], Status [${status}], Staff Filters [${staffFilter}], Title Filter [${titleFilter}], Property Filter [${propFilter}], Tenant Id [${tenantId}]`
    );

    if (titleFilter && titleFilter !== "null" && titleFilter !== "undefined" && String(titleFilter).trim() !== "" && typeof titleFilter === 'string') {
      titleFilter = titleFilter.split(',').map(v => v.trim()).filter(Boolean);
    }

    if (staffFilter && staffFilter !== "null" && staffFilter !== "undefined" && String(staffFilter).trim() !== "" && typeof staffFilter === 'string') {
      staffFilter = staffFilter.split(',').map(v => v.trim()).filter(Boolean);
    }

    if (propFilter && propFilter !== "null" && propFilter !== "undefined" && String(propFilter).trim() !== "" && typeof propFilter === 'string') {
      propFilter = propFilter.split(',').map(v => v.trim()).filter(Boolean);
    }

    let complaints: any = [];
    let complaintCounts = {
      new: 0,
      assigned: 0,
      closed: 0,
    };

    let properties = [];
    let staffs = [];

    const limit = 10;

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    const client = await clientDB.getById({ id: clientId });

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], ${isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`},  ${isPartner ? "Partner Requesting" : "Client Requesting"}....`
      );

      if (Number(tenantId)) {
        complaints = await complaintDB.getByTenantIdAndClientId({
          tenantId,
          clientId,
        });
        complaintCounts = await complaintDB.getComplaintCountsForTenant({
          tenantId,
          clientId,
        });
      } else {
        complaints = await complaintDB.getByClientIdAndFilters({
          clientId,
          title: titleFilter ? titleFilter : [],
          assignedTo: staffFilter ? staffFilter : [],
          status,
          propId: propFilter ? propFilter : [],
          pageNum,
          limit,
        });

        complaintCounts = await complaintDB.getCountByClientIdFilters({
          clientId,
          title: titleFilter ? titleFilter : [],
          assignedTo: staffFilter ? staffFilter : [],
          propId: propFilter ? propFilter : [],
        });
      }

      properties = await propertyDB.getPropIdsByClientId({
        clientId: clientId,
        status: CONSTANTS.PROPERTY_STATUS.ACTIVE,
      });

      staffs = await staffDB.getByClientId({
        clientId,
      });

    } else {
      const staffId = req.id;

      const staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Staff Requested....`
      );

      if (Number(tenantId)) {
        complaints = await complaintDB.getByTenantIdAndClientId({
          tenantId,
          clientId,
        });
        complaintCounts = await complaintDB.getComplaintCountsForTenant({
          tenantId,
          clientId,
        });
      } else {
        const staffLinkedProps = await propertyDB.getPropsByStaffId({
          staffId,
        });

        if (staffLinkedProps) {

          if (!Array.isArray(staffFilter)) {
            staffFilter = [];
          }

          staffFilter = staffFilter as string[];

          const propertiesIds = staffLinkedProps
            .map((prop: propertiesTypes) => prop.id)
            .join(",");

          if (
            Number(staff.role) === CONSTANTS.STAFF_ROLES.ADMIN || Number(staff.role) === CONSTANTS.STAFF_ROLES.BACK_OFFICE || Number(staff.role) === CONSTANTS.STAFF_ROLES.FINANCE_ADMIN || Number(staff.role) === CONSTANTS.STAFF_ROLES.HELPDESK
          ) {
            log.info(
              `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staff.id}], Staff Role [${staff.role}], Admin Staff Requesting, Fetching All Complaints Based On Property Access`
            );

            complaints = await complaintDB.getByClientIdAndFilters({
              clientId,
              title: titleFilter ? titleFilter : [],
              assignedTo: staffFilter ? staffFilter : [],
              status,
              propId: propFilter ? propFilter : propertiesIds,
              pageNum,
              limit,
            });
    
            complaintCounts = await complaintDB.getCountByClientIdFilters({
              clientId,
              title: titleFilter ? titleFilter : [],
              assignedTo: staffFilter ? staffFilter : [],
              propId: propFilter ? propFilter : propertiesIds,
            });
          } else if(Number(staff.role) === CONSTANTS.STAFF_ROLES.MAINTENANCE_SUPERVISOR) {
              log.info(
                `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staff.id}], Staff Role [${staff.role}], Non-Admin Staff Requesting, Fetching for Maintenance superviser`
              );
              titleFilter = "Electronics/Appliance Issue,Maintenance and Infrastructure,Plumbing Issues";
              if (titleFilter && titleFilter !== "null" && titleFilter !== "undefined" && String(titleFilter).trim() !== "" && typeof titleFilter === 'string') {
                titleFilter = titleFilter.split(',').map(v => v.trim()).filter(Boolean);
              }
              complaints = await complaintDB.getByClientIdAndFilters({
                clientId,
                title: titleFilter ? titleFilter : [],
                assignedTo: staffFilter ? staffFilter : [],
                status,
                propId: propFilter ? propFilter : propertiesIds,
                pageNum,
                limit,
              });
      
              complaintCounts = await complaintDB.getCountByClientIdFilters({
                clientId,
                title: titleFilter ? titleFilter : [],
                assignedTo: staffFilter ? staffFilter : [],
                propId: propFilter ? propFilter : propertiesIds,
              });
          } else {
            log.info(
              `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staff.id}], Staff Role [${staff.role}], Non-Admin Staff Requesting, Fetching Only Assigned Complaints`
            );

            if (!staffFilter.includes(String(staffId))) {
              staffFilter.push(String(staffId));
            }

            complaints = await complaintDB.getByClientIdAndFilters({
              clientId,
              title: titleFilter ? titleFilter : [],
              assignedTo: [staff.id],
              status,
              propId: propFilter ? propFilter : propertiesIds,
              pageNum,
              limit,
            });
    
            complaintCounts = await complaintDB.getCountByClientIdFilters({
              clientId,
              title: titleFilter ? titleFilter : [],
              assignedTo: [staff.id],
              propId: propFilter ? propFilter : propertiesIds,
            });

          }

        }

      }
      const staffLinkedProps = await propertyDB.getPropsByStaffId({
        staffId: staff.id,
      });

      properties = staffLinkedProps;
    }

    if (complaints && complaints.length > 0) {
      for (let complaint of complaints) {
        if (complaint.status >= CONSTANTS.COMPLAINT_STATUS.ASSIGNED) {
          const {name} = await staffDB.getById ({
              id: complaint.assignedTo,
            });
          complaint.staffName = name;
        }

        if (complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName) {
          complaint.staffName = client.name;
        }
      }
    }

    const reopenReasons = await getReopenReason(0);

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Staff Filters [${staffFilter}], Title Filter [${titleFilter}], Property Filter [${propFilter}], Tenant Id [${tenantId}], Complaint list sent successfully`
    );

    return res.status(200).json({
      msg: "Complaint list sent successfully",
      stats: complaintCounts,
      data: complaints || [],
      propList: properties,
      staffs: staffs,
      reopenReasons,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.GetComplaintDetails = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "GetComplaintDetails";

  try {
    const { complaintId, complaintFor } = req.params;

    const userType = req.userType;

    let clientId = req.id;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint For [${complaintFor}]`
    );

    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Complaint Id [${complaintId}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint For [${complaintFor}], Staff Id [${req.id}], Staff Requested....`
      );
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Client Requested....`
      );
    }

    const client = await clientDB.getById({ id: clientId });

    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], No Client Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let complaint;
    if (Number(complaintFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
      complaint = await complaintDB.getById({ id: complaintId });
    } else {
      complaint = await complaintDB.getByIdForProp({ id: complaintId });
    }

    if (!complaint) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], No Complaint Found`
      );
      return res
        .status(400)
        .json({ msg: "No Complaint Found", isSuccess: false });
    }

    const reopenReasons = await getReopenReason(0);

    if (complaint.reopenReason) {
      complaint.reopenReasonTitle = reopenReasons.find( (item: { id: number; }) => item.id === complaint.reopenReason)?.title;
      complaint.reopenReasonDescription = reopenReasons.find( (item: { id: number; }) => item.id === complaint.reopenReason)?.description;
    } else {
      complaint.reopenReasonTitle = null;
      complaint.reopenReasonDescription = null;
    }

    //log.info(`Complaint [${JSON.stringify(complaint)}]`);

    let staffs = [];

    if (complaint.status === CONSTANTS.COMPLAINT_STATUS.PENDING || complaint.status === CONSTANTS.COMPLAINT_STATUS.ASSIGNED) {
      const property = await propertyDB.getById({ id: complaint.propId });
      if (!property) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], No Property Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      staffs = await staffDB.getByPropIdForComplaints({ propId: property.id });
      if (!staffs) staffs = [];
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint details & staff list sent successfully`
    );

    return res.status(200).json({
      msg: "Complaint details sent successfully",
      data: { complaint, staffs, ownerName: client.name },
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.GetComplaintDetailsByTenant = async (
  req: CustomRequest,
  res: Response
) => {
  const C = "Complaint Controller";
  const F = "GetComplaintDetailsByTenant";

  try {
    const tenantId = req.id;
    const { complaintId } = req.params;
    log.info(
      `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}]`
    );

    const tenant = await tenantDB.getById({ id: tenantId });

    if (!tenant) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], No Tenant Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const complaint = await complaintDB.getById({ id: complaintId });
    if (!complaint) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], No Complaint Found`
      );
      return res
        .status(400)
        .json({ msg: "No Complaint Found", isSuccess: false });
    }

    const property = await propertyDB.getById({ id: complaint.propId });
    if (!property) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], No Property Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let staff = null;
    if (complaint.assignedTo)
      staff = await staffDB.getById({ id: complaint.assignedTo });

    log.info(
      `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Complaint details & staff list sent successfully`
    );

    return res.status(200).json({
      msg: "Complaint details sent successfully",
      data: { complaint, staff },
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.AssignComplaint = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "AssignComplaint";

  try {
    const { staffId, secondStaffId = null, complaintId, complaintFor, closingRemarks = null } = req.body;

    const userType = req.userType;

    let clientId = req.id;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Second Staff Id [${secondStaffId}], Complaint Id [${complaintId}], Complaint For [${complaintFor}], Remarks [${closingRemarks}]`
    );

    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Staff Id [${staffId}], Complaint Id [${complaintId}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Requesting Staff Id [${req.id}], Staff Requested....`
      );
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Client Requested....`
      );
    }

    const client = await clientDB.getById({ id: clientId });

    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], No Client Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const staff = await staffDB.getById({ id: staffId });
    if (!staff) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], No Staff Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let complaint;
    if (complaintFor === CONSTANTS.COMPLAIN_FOR.ROOM) {
      complaint = await complaintDB.getById({ id: complaintId });
    } else {
      complaint = await complaintDB.getByIdForProp({ id: complaintId });
    }

    if (!complaint) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], No Complaint Found`
      );
      return res
        .status(400)
        .json({ msg: "No Complaint Found", isSuccess: false });
    }

    await complaintDB.assignStaffDB({
      id: complaintId,
      assignedTo: staffId,
      status: CONSTANTS.COMPLAINT_STATUS.ASSIGNED
    });
    let coStaff = null;
    if(secondStaffId) {
      coStaff = await staffDB.getById({ id: secondStaffId });
      await complaintDB.secondAssignStaffDB ({
        id: complaintId,
        coAssignedTo: secondStaffId,
        status: CONSTANTS.COMPLAINT_STATUS.ASSIGNED
      });
    } else {
      await complaintDB.removeSecondAssignStaffDB ({
        id: complaintId,
      }); 
    }

    if(closingRemarks) {
      await complaintDB.updateClosingRemarks ({
        id: complaintId,
        closingRemarks,
      });
    }

    const property = await propertyDB.getById({ id: complaint.propId });
    let tenant;
    if (complaintFor === CONSTANTS.COMPLAIN_FOR.ROOM) {
      tenant = await tenantDB.getById({ id: complaint.tenantId });
      let isNotiSent = false;
      if (tenant.regId) {
        isNotiSent = await sendNotification({
          title: `Your complaint assigned to ${staff.name}`,
          message: `Your complaint has been acknowledged and assigned. They will be working to resolve it as quickly as possible. We appreciate your patience.`,
          regId: tenant.regId,
          userId: tenant.id,
          userType: CONSTANTS.USER_TYPE.TENANT,
          notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
          clientId: client.id,
        });
      } else {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Tenant Id [${tenant.id}], No Tenant's RegId Found`
        );
      }

      const msg = CONSTANTS.MSG.COMPLAINT_ASSIGNED.replace(
        "{#var#}",
        staff.name
      );

      // const isSent = await sendSMS(
      //   tenant.mobile,
      //   msg,
      //   CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_ASSIGNED
      // );

      // log.info(
      //   `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Is SMS Sent [${isSent}], Is Noti Sent [${isNotiSent}], Is SMS Sent2 [${isSent2}], Is Noti Sent2 [${isNotiSent2}], Notification Sent`
      // );
    }

    let isNotiSent2 = false;
    let isNotiSent3 = false;
    if (staff.regId) {
      isNotiSent2 = await sendNotification({
        title: `A new complaint assigned to you`,
        message: `${client.name} has assigned you a new complaint for property ${property.name}. Kindly look at it and do needful.`,
        regId: staff.regId,
        userId: staff.id,
        userType: CONSTANTS.USER_TYPE.STAFF,
        notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
        clientId: client.id,
      });
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], No Staff's RegId Found`
      );
    }

    if (coStaff && coStaff.regId) {
      isNotiSent3 = await sendNotification({
        title: `A new complaint assigned to you`,
        message: `${client.name} has assigned you a new complaint for property ${property.name}. Kindly look at it and do needful.`,
        regId: coStaff?.regId,
        userId: coStaff?.id,
        userType: CONSTANTS.USER_TYPE.STAFF,
        notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
        clientId: client.id,
      });
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], No Staff's RegId Found`
      );
    }

    const propSettings = await settingsDB.getByClientIdAndPropId({
      clientId,
      propId: complaint.propId,
    });

    if (propSettings) {
      if (propSettings.sms === 5) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], SMS Notification not enabled`
        );
        const msg2 = CONSTANTS.MSG.COMPLAINT_ASSIGNED_STAFF.replace(
          "{#var#}",
          client.name
        ).replace("{#var2#}", property.name);

        const isSent2 = await sendSMS(
          staff.mobile,
          msg2,
          CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_ASSIGNED_STAFF
        );
      }
      if (propSettings.whatsApp === 1) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], WhatsApp Notification enabled`
        );
        let footerText = propSettings.footer || "The Kipinn Team";
        if (complaintFor === CONSTANTS.COMPLAIN_FOR.ROOM) {

          /** Notify Staff **/
          const staffBodyVal = [staff.name, property.name, tenant.name, tenant.mobile, complaint.title,footerText.replace("Team", "").trim()];
          await whatsappPendingMessagesDB.add ({
            clientId,
            propId: complaint.propId,
            userType: CONSTANTS.USER_TYPE.STAFF,
            userId: staffId,
            userName: staff?.name,
            userMobile: staff?.mobile,
            templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.STAFF.COMPLAINT_ASSIGNED,
            payload : JSON.stringify(staffBodyVal),
            file: null,
          });

          /** Notify Tenant **/
          const tenantBodyVal = [tenant?.name, complaint.title, staff.name, footerText.replace("Team", "").trim()];
          await whatsappPendingMessagesDB.add ({
            clientId,
            propId: complaint.propId,
            userType: CONSTANTS.USER_TYPE.TENANT,
            userId: complaint.tenantId,
            userName: tenant?.name,
            userMobile: tenant?.mobile,
            templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_ASSIGNED,
            payload : JSON.stringify(tenantBodyVal),
            file: null,
          });




          // let whatsappAgreegrator = await clientConfigDB.getClientConfig({
          //   clientId,
          //   provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
          //   type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.WHATSAPP_AGGREGATOR
          // });

          // let complaintAssignedStaff = await getClientWhatsappCredentialsMessageCentral(Number(clientId), property?.id, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.STAFF.COMPLAINT_ASSIGNED, CONSTANTS.USER_TYPE.STAFF); 

          // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && complaintAssignedStaff) {
          //     log.info(
          //       `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Sending through message central to staff`
          //     );
          //     let flatName = "";
          //     let occupancy = await occupancyDB.getByTenantIdAndClientId({
          //       clientId: clientId,
          //       tenantId: complaint?.tenantId,
          //     });
          //     if (property.type === CONSTANTS.PROPERTY_TYPE.FLAT) {
          //       const { name } = await flatDB.getById({ id: occupancy.flatId });
          //       flatName = name;
          //     } else {
          //       flatName =
          //         occupancy.floor === "G" ? "Ground Floor" : "Floor " + occupancy.floor;
          //     }
          //     const bodyValues: Record<string, string> = {
          //       body_1: `${staff.name}`,
          //       body_2: `${property.name}`,
          //       body_3: `${flatName} (${complaint?.roomNum})`,
          //       body_4: `${tenant.name}`,
          //       body_5: `${tenant.mobile}`,
          //       body_6: `${complaint.title}`,
          //       body_7: `${footerText.replace("Team", "").trim()}`
          //     };
          //     sendWhatsappMC(
          //       staff.mobile,
          //       Number(clientId),
          //       Number(property.id),
          //       bodyValues,
          //       CONSTANTS.WHATSAPP_TEMPLATE_TYPES.STAFF.COMPLAINT_ASSIGNED,
          //       CONSTANTS.USER_TYPE.STAFF,
          //       CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
          //     );
          //     if(coStaff) {
          //       let bodyValuesCoStaff: Record<string, string> = {
          //         body_1: `${coStaff.name}`,
          //         body_2: `${property.name}`,
          //         body_3: `${flatName} (${complaint?.roomNum})`,
          //         body_4: `${tenant.name}`,
          //         body_5: `${tenant.mobile}`,
          //         body_6: `${complaint.title}`,
          //         body_7: `${footerText.replace("Team", "").trim()}`
          //       };
          //       sendWhatsappMC(
          //         coStaff?.mobile,
          //         Number(clientId),
          //         Number(property.id),
          //         bodyValuesCoStaff,
          //         CONSTANTS.WHATSAPP_TEMPLATE_TYPES.STAFF.COMPLAINT_ASSIGNED,
          //         CONSTANTS.USER_TYPE.STAFF,
          //         CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
          //       );
          //     }
          // } else {
          //     log.info(
          //       `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Sending through intrakt to staff`
          //     );
          //     if(519 === Number(clientId)) {
          //     sendWhatsappAssignedStaff(
          //       staff.mobile,
          //       staff.name,
          //       property.name,
          //       tenant.name,
          //       tenant.mobile,
          //       complaint.title,
          //       footerText,
          //       Number(clientId),
          //     );
          //     if(coStaff) {
          //       sendWhatsappAssignedStaff(
          //         coStaff?.mobile,
          //         coStaff?.name,
          //         property.name,
          //         tenant.name,
          //         tenant.mobile,
          //         complaint.title,
          //         footerText,
          //         Number(clientId),
          //       );
          //     }
          //   } else {
          //     let flatName = "";
          //     let occupancy = await occupancyDB.getByTenantIdAndClientId({
          //       clientId: clientId,
          //       tenantId: complaint?.tenantId,
          //     });
          //     if (property.type === CONSTANTS.PROPERTY_TYPE.FLAT) {
          //       const { name } = await flatDB.getById({ id: occupancy.flatId });
          //       flatName = name;
          //     } else {
          //       flatName =
          //         occupancy.floor === "G" ? "Ground Floor" : "Floor " + occupancy.floor;
          //     }
          //     sendWhatsappAssignedStaffNew(
          //       staff.mobile,
          //       staff.name,
          //       property.name,
          //       `${flatName} (${complaint?.roomNum})`,
          //       tenant.name,
          //       tenant.mobile,
          //       complaint.title,
          //       footerText,
          //       Number(clientId)
          //     );
          //     if(coStaff) {
          //       sendWhatsappAssignedStaffNew(
          //         coStaff?.mobile,
          //         coStaff?.name,
          //         property.name,
          //         `${flatName} (${complaint?.roomNum})`,
          //         tenant.name,
          //         tenant.mobile,
          //         complaint.title,
          //         footerText,
          //         Number(clientId)
          //       );
          //     }
          //   }
          // }
        
        // let complaintAssignedTenant = await getClientWhatsappCredentialsMessageCentral(Number(clientId), property?.id, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_ASSIGNED, CONSTANTS.USER_TYPE.TENANT); 
        // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && complaintAssignedTenant) {
        //   log.info(
        //     `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Sending through message central to tenant`
        //   );
        //   const bodyValues: Record<string, string> = {
        //     body_1: `${tenant?.name}`,
        //     body_2: `${complaint.title}`,
        //     body_3: `${staff.name}`,
        //     body_4: `${footerText.replace("Team", "").trim()}`
        //   };
        //   sendWhatsappMC(
        //     tenant?.mobile,
        //     Number(clientId),
        //     Number(property.id),
        //     bodyValues,
        //     CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_ASSIGNED,
        //     CONSTANTS.USER_TYPE.TENANT,
        //     CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
        //   );
        // } else {
        //   log.info(
        //     `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Sending through intrakt to tenant`
        //   );
        //   sendWhatsappAssignedTenant(
        //     tenant.mobile,
        //     tenant.name,
        //     complaint.title,
        //     staff.name,
        //     footerText,
        //     Number(clientId),
        //   );
        // }
      } else {
        // sendWhatsappAssignedStaff(
        //   staff.mobile,
        //   staff.name,
        //   property.name,
        //   client.name,
        //   client.mobile,
        //   complaint.title,
        //   footerText, 
        //   Number(clientId),
        // );
        sendWhatsappAssignedNewPropComplaintStaff(
          staff.mobile,
          staff.name,
          property.name,
          complaint.title,
          footerText, 
          Number(clientId),
        );
      }
      }
    }

    if (complaintFor === CONSTANTS.COMPLAIN_FOR.ROOM) {
      await logActivity(
        req.userType!,
        Number(req.id!),
        Number(req.parentClientId!),
        Number(req.platform),
        tenant.id,
        CONSTANTS.ACTIVITY_TYPES.ASSIGN_TENANT_COMPLAINT,
        complaint.title,
        staff.name,
        null,
        null,
        null
      );
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Complaint Id [${complaintId}], Assigned Staff Successfully`
    );

    return res.status(200).json({
      msg: "Assigned staff successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.UpdateStatus = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "UpdateStatus";

  try {
    const { status, complaintId, complaintFor, closingRemarks=null, } = req.body;

    const userType = req.userType;

    let clientId = req.id;

    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Status [${status}], Complaint Id [${complaintId}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Complaint For [${complaintFor}], Closing Remarks [${closingRemarks}], Staff Id [${req.id}], Staff Requested....`
      );
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Complaint For [${complaintFor}], Closing Remarks [${closingRemarks}], Client Requested....`
      );
    }

    let client = await clientDB.getById({ id: clientId });

    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], No Client Found`
      );

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let complaint;
    if (CONSTANTS.COMPLAIN_FOR.ROOM == complaintFor) {
      complaint = await complaintDB.getById({ id: complaintId });
    } else {
      complaint = await complaintDB.getByIdForProp({ id: complaintId });
    }
    if (!complaint) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], No Complaint Found`
      );
      return res
        .status(400)
        .json({ msg: "No Complaint Found", isSuccess: false });
    }

    const property = await propertyDB.getById({ id: complaint.propId });
    let notifyToPropNumber = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.NOTIFY_TO_PROP_NUMBER
    });

    if(notifyToPropNumber && Number(notifyToPropNumber?.value) === 1) {
      client.mobile = property?.ownerMobile;
      client.name = property?.ownerName;
    }

    let tenant;
    if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
      tenant = await tenantDB.getById({ id: complaint.tenantId });
    }

    let msg = "";
    if (status === CONSTANTS.COMPLAINT_STATUS.RESOLVED) {
      await complaintDB.updateResolvedAt({
        id: complaintId,
        resolvedAt: moment().format("YYYY-MM-DD HH:mm:ss"),
      });

      await complaintDB.updateClosingRemarks({
        id: complaintId,
        closingRemarks,
      });

      if (!complaint.assignedTo && userType === CONSTANTS.USER_TYPE.STAFF) {
        await complaintDB.assignStaffDB({
          id: complaintId,
          assignedTo: req.id,
          status: CONSTANTS.COMPLAINT_STATUS.RESOLVED,
        });
      }

      msg = "Complaint Resolved Successfully";
    } else if(status === CONSTANTS.COMPLAINT_STATUS.PENDING || status === CONSTANTS.COMPLAINT_STATUS.REOPENED) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Updating Remark`
      );
      await complaintDB.updateClosingRemarks({
        id: complaintId,
        closingRemarks,
      });
      msg = "Complaint note updated Successfully";
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Invalid Status`
      );
      return res.status(400).json({ msg: "Invalid Status", isSuccess: false });
    }

    await complaintDB.updateStatus({
      id: complaintId,
      status,
    });

    let isNotiSent = false;
    let isSent = false;

    if (status === CONSTANTS.COMPLAINT_STATUS.RESOLVED) {
      if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
        if (tenant.regId) {
          isNotiSent = await sendNotification({
            title: `Good news! Your complaint has been resolved`,
            message: `We appreciate your patience and understanding.`,
            regId: tenant.regId,
            userId: tenant.id,
            userType: CONSTANTS.USER_TYPE.TENANT,
            notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMPLAIN,
            clientId: client.id,
          });
        } else {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Tenant Id [${tenant.id}], No Tenant's RegId Found`
          );
        }
      }

      const propSettings = await settingsDB.getByClientIdAndPropId({
        clientId,
        propId: complaint.propId,
      });

      if (propSettings) {
        if (propSettings.sms === 5) {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], SMS Notification not enabled`
          );
          const msg = CONSTANTS.MSG.COMPLAINT_RESOLVED;
          if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {
          isSent = await sendSMS(
            tenant.mobile,
            msg,
            CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RESOLVED
          );
          } else {
            if(Number(req.id) != Number(clientId)) {
              isSent = await sendSMS(
                client.mobile,
                msg,
                CONSTANTS.SMS_TEMPLATE_IDS.COMPLAINT_RESOLVED
              );
            }
          }
        }
        if (propSettings.whatsApp === 1) {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], WhatsApp Notification not enabled`
          );
          //let footerText = propSettings.footer || "The Kipinn Team";
          if (Number(complaint.raisedFor) === CONSTANTS.COMPLAIN_FOR.ROOM) {

            /** Notify Tenant **/
            let bodyVal = [tenant?.name, complaint.title];
            await whatsappPendingMessagesDB.add ({
              clientId,
              propId: complaint.propId,
              userType: CONSTANTS.USER_TYPE.TENANT,
              userId: tenant?.id,
              userName: tenant?.name,
              userMobile: tenant?.mobile,
              templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_RESOLVED,
              payload : JSON.stringify(bodyVal),
              file: null,
            });
            
            /** Notify Owner **/
            bodyVal = [client?.name, complaint.title, tenant?.name];
            await whatsappPendingMessagesDB.add ({
              clientId,
              propId: complaint.propId,
              userType: CONSTANTS.USER_TYPE.CLIENT,
              userId: client?.id,
              userName: client?.name,
              userMobile: client?.mobile,
              templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_RESOLVED,
              payload : JSON.stringify(bodyVal),
              file: null,
            });

            // let whatsappAgreegrator = await clientConfigDB.getClientConfig({
            //   clientId,
            //   provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
            //   type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.WHATSAPP_AGGREGATOR
            // });

            // let complaintResolvedTenant = await getClientWhatsappCredentialsMessageCentral(Number(clientId), complaint.propId, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_RESOLVED, CONSTANTS.USER_TYPE.TENANT);
            // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && complaintResolvedTenant) {
            //   log.info(
            //     `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint Id [${complaintId}], Sending through message central to tenant`
            //   );
            //   const bodyValues: Record<string, string> = {
            //     body_1: `${tenant?.name}`,
            //     body_2: `${complaint.title}`
            //   };
            //   sendWhatsappMC(
            //     tenant?.mobile,
            //     Number(clientId),
            //     Number(complaint.propId),
            //     bodyValues,
            //     CONSTANTS.WHATSAPP_TEMPLATE_TYPES.TENANT.COMPLAINT_RESOLVED,
            //     CONSTANTS.USER_TYPE.TENANT,
            //     CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
            //   );
            //   } else {
            //     log.info(
            //       `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint Id [${complaintId}], Sending through intrakt to tenant`
            //     );
            //     sendWhatsappResolvedTenant(
            //       tenant.mobile,
            //       tenant.name,
            //       complaint.title,
            //       Number(clientId)
            //     );
            //   }
              // let complaintResolvedOwner = await getClientWhatsappCredentialsMessageCentral(Number(clientId), complaint.propId, CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_RESOLVED, CONSTANTS.USER_TYPE.CLIENT);
              // if(whatsappAgreegrator && Number(whatsappAgreegrator?.value)  === CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL && complaintResolvedOwner) {
              //   log.info(
              //     `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint Id [${complaintId}], Sending through message central to client`
              //   );
              //   const bodyValues: Record<string, string> = {
              //     body_1: `${client?.name}`,
              //     body_2: `${complaint.title}`,
              //     body_3: `${tenant?.name}`
              //   };
              //   sendWhatsappMC(
              //     client.mobile,
              //     Number(clientId),
              //     Number(complaint.propId),
              //     bodyValues,
              //     CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_RESOLVED,
              //     CONSTANTS.USER_TYPE.CLIENT,
              //     CONSTANTS.CLIENT_CONFIG_PROVIDER.MESSAGE_CENTRAL
              //   );
              // } else {
              //   log.info(
              //     `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${complaintId}], Complaint Id [${complaintId}], Sending through intrakt to client`
              //   );
              //   sendWhatsappResolvedOwner(
              //     client.mobile,
              //     client.name,
              //     complaint.title,
              //     tenant.name,
              //     Number(clientId)
              //   );
              // }
          } else {
            if(Number(req.id) != Number(clientId)) {
              //To owner
              let bodyVal = [client?.name, complaint.title, tenant?.name];
              await whatsappPendingMessagesDB.add ({
                clientId,
                propId: complaint.propId,
                userType: CONSTANTS.USER_TYPE.CLIENT,
                userId: client?.id,
                userName: client?.name,
                userMobile: client?.mobile,
                templateType: CONSTANTS.WHATSAPP_TEMPLATE_TYPES.CLIENT.COMPLAINT_RESOLVED,
                payload : JSON.stringify(bodyVal),
                file: null,
              });
              // sendWhatsappResolvedOwner(
              //   client.mobile,
              //   client.name,
              //   complaint.title,
              //   client.name,
              //   Number(clientId)
              // );
            }
          }
        }
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Status [${status}], Complaint Id [${complaintId}], Is SMS Sent [${isSent}], Is Noti Sent [${isNotiSent}] ${msg}`
    );

    return res.status(200).json({
      msg: msg,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.AddByAdmin = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "AddByAdmin";

  try {
    let { title, description, id, type } = req.body;
    //const clientId = req.id;
    const userType = req.userType;
    const file = req.file;
    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    let complaintId;
    let propId;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Id [${id}], Title [${title}], Type [${type}], Description [${description}] `
    );

    if (!title || title === "undefined") title = null;
    if (!description || description === "undefined") description = null;
    if (!id || id === "undefined") id = null;

    if (!title) {
      log.info(
        `[${C}], [${F}], Id [${id}], Title [${title}], Description [${description}], Empty Title`
      );
      if (file) await fsPromises.unlink(file.path);
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    if (Number(type) === CONSTANTS.COMPLAIN_FOR.ROOM) {
      //Complain for Tenant Room
      let tenantId = id;
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Complain for Tenant`);
      const tenant = await tenantDB.getById({ id: tenantId });

      if (!tenant) {
        log.info(
          `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], No Tenant Found`
        );
        if (file) await fsPromises.unlink(file.path);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      const occupancy = await occupancyDB.getByTenantId({
        tenantId: tenant?.id,
      });

      if (!occupancy) {
        log.info(
          `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], No Occupancy Found`
        );
        if (file) await fsPromises.unlink(file.path);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      if (
        occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.OCCUPIED &&
        occupancy.status !== CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT
      ) {
        log.info(
          `[${C}], [${F}], Tenant Id [${tenantId}], Title [${title}], Description [${description}], Tenant is not Occupied`
        );
        if (file) await fsPromises.unlink(file.path);

        return res.status(400).json({
          msg: "You are not allowed to raise complaint",
          isSuccess: false,
        });
      }
      //const client = await clientDB.getById({ id: occupancy.clientId });
      propId = occupancy.propId;
      const property = await propertyDB.getById({ id: occupancy.propId });

      let filePath = null;
      if (file) {
        log.info(
        `[${C}], [${F}], Tenant Id [${tenant?.id}], Complaint with image`
        );
        const folderName = `complaints/${moment().format("DD_MM_YYYY")}`;
        const folderPath = `uploads/documents/client_${occupancy.clientId}/${folderName}`;

        if (!fs.existsSync(folderPath)) {
          await fsPromises.mkdir(folderPath, { recursive: true });
        }

        const oldPath = `uploads/tmp/${file.filename}`;
        const newPath = `${folderPath}/${file.filename}`;
        await fsPromises.copyFile(oldPath, newPath);

        filePath = `${process.env.UPLOAD_PATH}/documents/client_${occupancy.clientId}/${folderName}/${file.filename}`;
      }
      let flatName = "";

      if (property.type === CONSTANTS.PROPERTY_TYPE.FLAT) {
        const { name } = await flatDB.getById({ id: occupancy.flatId });
        flatName = "Flat No " + name;
      } else {
        flatName =
          occupancy.floor === "G" ? "Ground Floor" : "Floor " + occupancy.floor;
      }
      complaintId = await complaintDB.create({
        clientId: occupancy.clientId,
        tenantId: tenant?.id,
        propId: occupancy.propId,
        roomId: occupancy.roomId,
        raisedBy: CONSTANTS.USER_TYPE.CLIENT,
        raisedFor: CONSTANTS.COMPLAIN_FOR.ROOM, //For Tenant
        floor: flatName,
        img: filePath || "",
        title,
        raisedById: occupancy.clientId,
        description,
      });
      if (file) await fsPromises.unlink(file.path);
      log.info(
        `[${C}], [${F}], Tenant Id [${tenant?.id}], Title [${title}], Description [${description}], Complaint Added Successfully`
      );
    } else {
      //Complain for Property
      propId = id;
      log.info(
        `[${C}], [${F}], Property Id [${propId}], Complain for Property`
      );
      const property = await propertyDB.getById({ id: propId });
      if (!property) {
        log.info(
          `[${C}], [${F}], Property Id [${propId}], Title [${title}], Description [${description}], No Property Found`
        );
        if (file) await fsPromises.unlink(file.path);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      let filePath = null;
      if (file) {
        const folderName = `complaints/${moment().format("DD_MM_YYYY")}`;
        const folderPath = `uploads/documents/client_${clientId}/${folderName}`;

        if (!fs.existsSync(folderPath)) {
          await fsPromises.mkdir(folderPath, { recursive: true });
        }

        const oldPath = `uploads/tmp/${file.filename}`;
        const newPath = `${folderPath}/${file.filename}`;
        await fsPromises.copyFile(oldPath, newPath);

        filePath = `${process.env.UPLOAD_PATH}/documents/client_${clientId}/${folderName}/${file.filename}`;
      }
      let flatName = property.name;

      complaintId = await complaintDB.create({
        clientId: clientId,
        tenantId: null,
        propId: propId,
        roomId: null,
        raisedBy: CONSTANTS.USER_TYPE.CLIENT,
        raisedFor: CONSTANTS.COMPLAIN_FOR.PROPERTY,
        floor: flatName,
        img: filePath || "",
        title,
        raisedById: clientId,
        description,
      });
      if (file) await fsPromises.unlink(file.path);
      log.info(
        `[${C}], [${F}], Property Id [${propId}], Title [${title}], Description [${description}], Complaint Added Successfully`
      );
    }

    const autoAssign = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.INTERNAL,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.INTERNAL.AUTO_ASSIGN_COMPLAINT,
    });

    // const helpDesk = await staffDB.getByClientIdAndRole({
    //   clientId,
    //   role: CONSTANTS.STAFF_ROLES.HELPDESK,
    // });

    if (autoAssign && Number(autoAssign?.value) === 1) {
      const assignedTo = await getComplaintAssignedTo(title);
      let assignedToStaff = await staffDB.getByClientIdAndRoleAndProperty({
        clientId,
        role: assignedTo,
        status: CONSTANTS.STAFF_STATUS.ACTIVE,
        propId: Number(propId)
      });
      if (!assignedToStaff || assignedToStaff.length === 0) {
        assignedToStaff = await staffDB.getByClientIdAndRoleAndProperty({
          clientId,
          role: CONSTANTS.STAFF_ROLES.HELPDESK,
          status: CONSTANTS.STAFF_STATUS.ACTIVE,
          propId: Number(propId)
        });
      }
      if (assignedToStaff && assignedToStaff.length > 0) {
        let autoAssigned = await autoAssignComplaint(
          clientId!,
          complaintId,
          assignedToStaff[0]?.id,
          type,
        );

        if (autoAssigned) {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Assigned Staff Id [${assignedToStaff[0].id}], Assigned Staff Role [${assignedToStaff[0].role}], Complaint Id [${complaintId}], Complaint Auto Assigned`
          );
        } else {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Assigned Staff Id [${assignedToStaff[0].id}], Assigned Staff Role [${assignedToStaff[0].role}], Complaint Id [${complaintId}], Complaint Not Auto Assigned`
          );
        }
      }
    }

    return res.status(200).json({
      msg: "Complaint added successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForClientForProp = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForClientForProp";

  try {
    //let clientId = req.id;
    let staff = null;
    const userType = req.userType;

    let { pageNum, status, filter, filterVal = null } = req.query;

    log.info(`[${C}], [${F}], Page Num [${pageNum}], Status [${status}], Filter [${filter}], FilterVal [${filterVal}]`);

    let complaints: any = [];

    const limit = 10;
    let complaintCounts = {
      new: 0,
      assigned: 0,
      closed: 0,
    };

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    const client = await clientDB.getById({ id: clientId });

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      // const client = await clientDB.getById({ id: clientId });
      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Filter [${filter}], FilterVal [${filterVal}], ${
          isPartner ? "Partner Requesting" : "Client Requesting"
        }....`
      );

      complaints = await propComplaintsForClient(
        // filter?.toString() || "",
        status?.toString() || "",
        Number(pageNum),
        limit,
        Number(clientId)
      );
      complaintCounts = await complaintDB.getPropComplaintCountsForClient({ clientId });
    } else {
      const staffId = req.id;

      staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Page Num [${pageNum}], Filter [${filter}], Staff Id [${staffId}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Filter [${filter}], FilterVal [${filterVal}], Staff Id [${staffId}], Staff Requested....`
      );

      if (
        staff.role === CONSTANTS.STAFF_ROLES.ADMIN ||
        // staff.role === CONSTANTS.STAFF_ROLES.WARDEN || 
        staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE ||
        staff.role === CONSTANTS.STAFF_ROLES.FINANCE_ADMIN ||
        staff.role === CONSTANTS.STAFF_ROLES.HELPDESK
      ) {
        complaints = await propComplaintsForAdmin(
          // filter?.toString() || "",
          status?.toString() || "",
          Number(pageNum),
          limit,
          Number(clientId),
          Number(staffId)
        );
        complaintCounts = await propComplaintStaffCounts(
          Number(clientId),
          Number(staffId),
          // String(filter),
          String(status),
          filterVal,
        );
      } else {
        complaints = await propComplaintsForStaff(
          // filter?.toString() || "",
          status?.toString() || "",
          Number(pageNum),
          limit,
          Number(staffId)
        );
        complaintCounts = await propComplaintStaffCounts(
          Number(clientId),
          Number(staffId),
          // String(filter),
          String(status),
          filterVal,
        );
      }
    }

    if(complaints && complaints.length > 0){
      for(let complaint of complaints){
        if(complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName){
          complaint.staffName = client?.name;
        }
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Filter [${filter}], Complaint list sent successfully`
    );

    return res.status(200).json({
      msg: "Complaint list sent successfully",
      stats: complaintCounts,
      data: complaints || [],
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.Delete = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "Delete";

  try {
    const { complaintId } = req.body;

    let tenantId = req.id;

    log.info(
      `[${C}], [${F}], Tenant Id [${tenantId}], Complaint Id [${complaintId}], Deleting Complaint....`
    );

    const tenant = await tenantDB.getById({ id: tenantId });

    if (!tenant) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], , No Tenant Found`);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const occupancy = await occupancyDB.getByTenantId({
      tenantId: tenant?.id,
    });

    if (!occupancy) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], , No Occupancy Found`);

      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const complaint = await complaintDB.getById({ id: complaintId });

    if (!complaint) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Status [${complaint.status}], Complaint Id [${complaintId}], No Complaint Found`
      );
      return res
        .status(400)
        .json({ msg: "No Complaint Found", isSuccess: false });
    }

    let msg = "Complain Deleted Successsfully";

    await complaintDB.removeByComplainId({ id: complaintId });

    log.info(
      `[${C}], [${F}], Tenant Id [${tenantId}], Status [${complaint.status}], Complaint Id [${complaintId}], Complain Deleted Successsfully}`
    );

    return res.status(200).json({
      msg: msg,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForWeb = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForWeb";

  try {
    // let clientId = req.id;
    let staff = null;
    const userType = req.userType;

    let { startDate, endDate, filter, status, typeFilter, titleFilter, propId, s, t } = req.query;
    let pageNum = 1;
    let complaints: any = [];
    let complaintCounts = {
      new: 0,
      assigned: 0,
      closed: 0,
      reopened: 0,
    };

    if (titleFilter && titleFilter !== "null" && titleFilter !== "undefined" && String(titleFilter).trim() !== "" && typeof titleFilter === 'string') {
      titleFilter = titleFilter.split(',').map(v => v.trim()).filter(Boolean);
    }

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    const client = await clientDB.getById({ id: clientId });

    let isStaffAllowed = false;
    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staffId = req.id;

      staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Page Num [${pageNum}], Filter [${filter}], Type Filter [${typeFilter}], Staff Id [${staffId}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (!isStaffAllowed) {
        log.info(
          `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Only Admin or Warden Authorized`
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner || isStaffAllowed) {
      // const client = await clientDB.getById({ id: clientId });
      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], ${
          isStaffAllowed ? `Staff Id [${req.id}]` : isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`
        }, Filter [${filter}], Type Filter [${typeFilter}], Title Filter [${titleFilter}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Search Val [${s}], Search Type [${t}], ${
          isStaffAllowed ? "Staff Requesting" : isPartner ? "Partner Requesting" : "Client Requesting"
        }....`
      );
      if (s && s !== "undefined" && s !== "null" && s !== " ") {
        if (Number(t) === 1) {
          complaints = await complaintDB.getByRaisedByMobile({
            clientId: clientId,
            searchVal: s,
          });
          complaintCounts = await complaintDB.getComplaintCountForMobileSearch({
            clientId: clientId,
            searchVal: s,
          });
        } else if (Number(t) === 2) {
          complaints = await complaintDB.getByRaisedByName({
            clientId: clientId,
            searchVal: s,
          });
          complaintCounts = await complaintDB.getComplaintCountForNameSearch({
            clientId: clientId,
            searchVal: s,
          });
        } else {
          log.info(
            `[${C}], [${F}], ${
              isStaffAllowed ? `Staff Id [${req.id}]` : isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`
            }, Filter [${filter}], Type Filter [${typeFilter}], Title Filter [${titleFilter}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Search Val [${s}], Search Type [${t}], Invalid Search Type`
          );
          return res.status(400).json({
            msg: "Invalid Search Type",
            isSuccess: false,
          });
        }
      } else if (Number(propId) === 0) {
        complaints = await complaintsForClientWeb(
          Number(clientId),
          filter?.toString() || "",
          String(startDate),
          String(endDate),
          Number(typeFilter),
          titleFilter || [],
        );

        // if (Number(typeFilter) && Number(typeFilter) !== 0) {
        //   complaintCounts = await complaintDB.getCountByClientIdandDateRangeAndAssigned({
        //     clientId,
        //     startDate: String(startDate),
        //     endDate: String(endDate),
        //     assignedTo: typeFilter,
        //   });
        // } else {
        //   complaintCounts = await complaintDB.getCountByClientIdandDateRange({
        //     clientId,
        //     startDate: String(startDate),
        //     endDate: String(endDate),
        //   });
        // }

        complaintCounts = await complaintDB.getCountByClientIdandDateRangeAndFilters({
          clientId: clientId,
          startDate: String(startDate),
          endDate: String(endDate),
          title: titleFilter || [],
          assignedTo: typeFilter,
        });
      } else {
        complaints = await complaintsForProperty(
          Number(propId),
          filter?.toString() || "",
          String(startDate),
          String(endDate),
          Number(typeFilter),
          titleFilter || [],
        );
        // if (Number(typeFilter) && Number(typeFilter) !== 0) {
        //   complaintCounts = await complaintDB.getCountByPropIdandDateRangeAndAssigned({
        //     propId,
        //     startDate: String(startDate),
        //     endDate: String(endDate),
        //     assignedTo: typeFilter,
        //   });
        // } else {
        //   complaintCounts = await complaintDB.getCountByPropIdandDateRange({
        //     propId,
        //     startDate: String(startDate),
        //     endDate: String(endDate),
        //   });
        // }
        complaintCounts = await complaintDB.getCountByPropIdandDateRangeAndFilters({
          propId,
          startDate: String(startDate),
          endDate: String(endDate),
          assignedTo: Number(typeFilter) ? Number(typeFilter) : null,
          title: titleFilter || [],
        });
      }
    } else {
      // const staffId = req.id;

      // staff = await staffDB.getById({ id: staffId });
      // if (!staff) {
      //   log.info(
      //     `[${C}], [${F}], Page Num [${pageNum}], Filter [${filter}], Type Filter [${typeFilter}], Staff Id [${staffId}], No Staff Found`
      //   );
      //   return res
      //     .status(400)
      //     .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      // }
      // let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      // if (!isStaffAllowed) {
      //   log.info(
      //     `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Only Admin or Warden Authorized`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }

      // clientId = staff.clientId;

      // log.info(
      //   `[${C}], [${F}], Client Id [${clientId}], Filter [${filter}], Type Filter [${typeFilter}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Staff Id [${staffId}], Search Val [${s}], Search Type [${t}], Staff Requested....`
      // );
      // if (s && s !== "undefined" && s !== "null" && s !== " ") {
      //   if (Number(t) === 1) {
      //     complaints = await complaintDB.getByRaisedByMobile({
      //       clientId: clientId,
      //       searchVal: s,
      //     });
      //     complaintCounts = await complaintDB.getComplaintCountForMobileSearch({
      //       clientId: clientId,
      //       searchVal: s,
      //     });
      //   } else if (Number(t) === 2) {
      //     complaints = await complaintDB.getByRaisedByName({
      //       clientId: clientId,
      //       searchVal: s,
      //     });
      //     complaintCounts = await complaintDB.getComplaintCountForNameSearch({
      //       clientId: clientId,
      //       searchVal: s,
      //     });
      //   } else {
      //     log.info(
      //       `[${C}], [${F}], ${
      //         isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`
      //       }, Filter [${filter}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Search Val [${s}], Search Type [${t}], Invalid Search Type`
      //     );
      //     return res.status(400).json({
      //       msg: "Invalid Search Type",
      //       isSuccess: false,
      //     });
      //   }
      // } else if (Number(propId) === 0) {
      //   complaints = await complaintsForClientWeb(
      //     Number(clientId),
      //     filter?.toString() || "",
      //     String(startDate),
      //     String(endDate),
      //     Number(typeFilter),
      //     String(titleFilter) || null,
      //   );
      //   if (Number(typeFilter) && Number(typeFilter) !== 0) {
      //     complaintCounts = await complaintDB.getCountByClientIdandDateRangeAndAssigned({
      //       clientId,
      //       startDate: String(startDate),
      //       endDate: String(endDate),
      //       assignedTo: typeFilter,
      //     });
      //   } else {
      //     complaintCounts = await complaintDB.getCountByClientIdandDateRange({
      //       clientId,
      //       startDate: String(startDate),
      //       endDate: String(endDate),
      //     });
      //   }
      // } else {
      //   complaints = await complaintsForProperty(
      //     Number(propId),
      //     filter?.toString() || "",
      //     String(startDate),
      //     String(endDate),
      //     Number(typeFilter),
      //   );
      //   if (Number(typeFilter) && Number(typeFilter) !== 0) {
      //     complaintCounts = await complaintDB.getCountByPropIdandDateRangeAndAssigned({
      //       propId,
      //       startDate: String(startDate),
      //       endDate: String(endDate),
      //       assignedTo: typeFilter,
      //     });
      //   } else {
      //     complaintCounts = await complaintDB.getCountByPropIdandDateRange({
      //       propId,
      //       startDate: String(startDate),
      //       endDate: String(endDate),
      //     });
      //   }
      // }
    }

    const staffList = await staffDB.getActiveByClientId({
      clientId,
    });

    if(complaints && complaints.length > 0){
      for(let complaint of complaints){
        if(complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName){
          complaint.staffName = client?.name;
        }
      }
    }

    const reopenReasons = await getReopenReason(0);

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Filter [${filter}], Complaint list sent successfully`
    );

    complaintCounts.assigned = Number(complaintCounts?.assigned) || 0;
    complaintCounts.closed = Number(complaintCounts?.closed) || 0;
    complaintCounts.new = Number(complaintCounts?.new) || 0;
    complaintCounts.reopened = Number(complaintCounts?.reopened) || 0;

    return res.status(200).json({
      msg: "Complaint list sent successfully",
      stats: complaintCounts,
      data: complaints || [],
      staffs: staffList || [],
      reopenReasons,
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ListForWebForProp = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "ListForWebForProp";

  try {
    //let clientId = req.id;
    let staff = null;
    const userType = req.userType;

    let { startDate, endDate, s, t, propId, typeFilter, titleFilter=null } = req.query;

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Search Value [${s}], Search Type [${t}], Filter [${typeFilter}], Title Filter [${titleFilter}]`
    );

    if (titleFilter && titleFilter !== "null" && titleFilter !== "undefined" && String(titleFilter).trim() !== "" && typeof titleFilter === 'string') {
      titleFilter = titleFilter.split(',').map(v => v.trim()).filter(Boolean);
    }

    let complaintList: any = [];

    const limit = 10e9;
    let complaintCounts = {
      new: 0,
      assigned: 0,
      closed: 0,
      reopened: 0
    };

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    const client = await clientDB.getById({ id: clientId });

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      // const client = await clientDB.getById({ id: clientId });
      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);

        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], ${
          isPartner ? "Partner Requesting" : "Client Requesting"
        }....`
      );

      const {complaints, complaintCount} = await propComplaintsForClientWeb(
        clientId,
        Number(propId),
        String(startDate),
        String(endDate),
        Number(typeFilter),
        titleFilter || [],
      );
      complaintList = complaints;
      complaintCounts = complaintCount;
    } else {
      const staffId = req.id;

      staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Staff Id [${staffId}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${staffId}], Staff Role [${staff?.role}], Staff Requested....`
      );

      if (
        staff.role === CONSTANTS.STAFF_ROLES.ADMIN ||
        staff.role === CONSTANTS.STAFF_ROLES.WARDEN || 
        staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE
      ) {
        const {complaints, complaintCount} = await propComplaintsForClientWeb(
          clientId,
          Number(propId),
          String(startDate),
          String(endDate),
          Number(typeFilter),
          titleFilter || [],
        );
        complaintList = complaints;
        complaintCounts = complaintCount;
      } else {
        const {complaints, complaintCount} = await propComplaintsForClientWeb(
          clientId,
          Number(propId),
          String(startDate),
          String(endDate),
          Number(typeFilter),
          titleFilter || [],
        );
        complaintList = complaints;
        complaintCounts = complaintCount;
      }
    }

    const staffList = await staffDB.getActiveByClientId({
      clientId,
    });

    if(complaintList && complaintList.length > 0){
      for(let complaint of complaintList){
        if(complaint.status === CONSTANTS.COMPLAINT_STATUS.RESOLVED && !complaint.staffName){
          complaint.staffName = client?.name;
        }
      }
    }

    complaintCounts.assigned = Number(complaintCounts?.assigned) || 0;
    complaintCounts.closed = Number(complaintCounts?.closed) || 0;
    complaintCounts.new = Number(complaintCounts?.new) || 0;
    complaintCounts.reopened = Number(complaintCounts?.reopened) || 0;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Start Date [${startDate}], End Date [${endDate}], Search Val [${s}], Search Type [${t}], Property Complaint list sent successfully`
    );

    return res.status(200).json({
      msg: "Property complaint list sent successfully",
      stats: complaintCounts,
      data: complaintList || [],
      staffs: staffList || [],
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.EditStaffNote = async (req:CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "EditStaffNote";

  try {
    let { id, remarks } = req.body;
    const staffNote = remarks;
    log.info(`[${C}], [${F}], Complaint Id [${id}], Staff Note [${staffNote}]`);

    const userType = req.userType;

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`}, Complaint Id [${id}], Staff Note [${staffNote}] ${isPartner ? "Partner Requesting" : "Client Requesting"}....`
      );
    } else {
      const staff = await staffDB.getById({
        id: req.id,
      });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      // if (staff.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.WARDEN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE) {
      //   log.info(
      //     `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Only Admin or Warden Authorized`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }

      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Complaint Id [${id}], Staff Note [${staffNote}], Staff Requesting....`
      );
    }

    await complaintDB.updateStaffNote({
      id,
      staffNote,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Complaint Id [${id}], Staff Note [${staffNote}], Staff Complaint Note Updated Successfully`
    );

    return res.status(200).json({
      msg: "Complaint note updated successfully.",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.ComplaintAnalytics = async (req: CustomRequest, res: Response) => {
  const C = "Client Controller";
  const F = "ComplaintAnalytics";

  try {
    const userType = req.userType;
    const {
      startDate = moment().startOf('month').format("YYYY-MM-DD"), 
      endDate = moment().endOf('month').format("YYYY-MM-DD")
    } = req.query;
    let data = {};
    log.info(`[${C}], [${F}], Start Date [${startDate}], EndDate [${endDate}]`);

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    let isFinanceAdmin = false;

    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staff = await staffDB.getById({
        id: req.id,
      });
      if (staff && staff.role === CONSTANTS.STAFF_ROLES.FINANCE_ADMIN) isFinanceAdmin = true;
    }
      log.info(
        `[${C}], [${F}], ${
          isPartner ? `Partner Id [${req.id}], Partner Requesting` : isFinanceAdmin ? `Finance Admin Id [${req.id}], Finance Admin Requesting` : `Client Id [${clientId}], Client Requesting`
        }....`
      );

      const client = await clientDB.getById({ id: clientId });

      if (!client) {
        log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      data = await clientComplaintGraphX(client, startDate.toString(), endDate.toString());
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], EndDate [${endDate}],  Complaints data sent successfully`
      );
      

    return res.status(200).json({
      isSuccess: true,
      data,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

complaints.Translate = async (req: CustomRequest, res: Response) => {
  const C = "Complaint Controller";
  const F = "Translate";

  try {
    const { description, translateToLang } = req.body;

    const userType = req.userType;
    
    log.info(`[${C}], [${F}], Complaint Description [${description}], Translate To Language [${translateToLang}]`);

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`}, ${isPartner ? "Partner Requesting" : "Client Requesting"}....`
      );
    } else {
      const staff = await staffDB.getById({
        id: req.id,
      });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const ai = new GoogleGenAI({apiKey: process.env.GEMINI_API_KEY});

    const response = await ai.models.generateContent({
      // gemini-3.5-flash is the recommended, highly intelligent free-tier model
      model: 'gemini-3.5-flash', 
      contents: description,
      config: {
        // System instructions force the model to behave like a strict translator
        systemInstruction: `You are a professional, highly precise translator working for a property management system.
        ### TASK 
        Translate the following tenant complaint into clear, easy-to-understand ${translateToLang} 
        so ground maintenance staff can act on it. 
        
        ### CRITICAL RULES:
        1. Return ONLY the raw, direct translation text. 
        2. Absolutely no conversational filler, introductions, explanations, or markdown commentary.
        3. Preserve technical or appliance keywords if a pure ${translateToLang} translation would be obscure to a maintenance worker. Keep terms like "Geyser", "Lift", "MCB", or "AC" in the standard script/terminology most commonly understood by local technicians.
        
        ### Execution
        Translate the input now following the rules above.`,
        // Lower temperature (0.1 - 0.3) makes the translation deterministic and literal
        temperature: 0.2, 
      },
    });

    log.info(`[${C}], [${F}], Response [${JSON.stringify(response)}]`);

    const translatedText = response.candidates?.[0]?.content?.parts?.[0]?.text;

    log.info(
      `[${C}], [${F}], Description [${description}], Translate To Language [${translateToLang}], Translated Text [${translatedText}], Description Transalted Successfully`
    );

    return res.status(200).json({
      msg: "Translation sent successfully",
      isSuccess: true,
      data: translatedText,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

export default complaints;
