import mysql, { ResultSetHeader, RowDataPacket } from "mysql2";
import DB from "../config/database/db";
import occupancyTypes from "../schemas/occupancy.schema";
import CONSTANTS from "../config/constants";
import log from "../config/log";
import moment from "moment";

const occupancyDB: any = {};

occupancyDB.getById = async ({ id }: occupancyTypes) => {
  const query = "select * from Occupancies where id = ?";
  const data = [id];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getDetailByTenantIdAndClientId = async ({ tenantId, clientId }: occupancyTypes) => {
  const query = "select * from Occupancies where tenantId = ? and clientId=? order by id desc limit 1";
  const data = [tenantId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiring = async ({
  clientId,
  days,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; days: number }) => {
  // const query =
  //   "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL 90 DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?";
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL ? DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    days,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiringBySearch = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: any; }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? OR T.mobile like ?) and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL 90 DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?";

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiringCount = async ({
  clientId,
  days = 90,
}: occupancyTypes & { days: number; }) => {
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL 90 DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId)) as o";
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL ? DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
    days,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getTenantWhoseAgrementExpiringCountCurMonth = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL 90 DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId)) as o";
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getTenantWhoseAgrementExpired = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) Desc LIMIT ?, ?";
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) Desc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiredBySearch = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: any; }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? OR T.mobile like ?) and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) Desc LIMIT ?, ?";

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiredCount = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId)) as o";
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getTenantWhoseAgrementExpiringForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
  days,
}: occupancyTypes & {
  propertiesIds: string;
  pageNum: number;
  limit: number;
  days: number;
}) => {
  // const query =
  //   "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE())  and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL ? DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //propertiesIds,
    days,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiringBySearchForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & {
  propertiesIds: string;
  pageNum: number;
  limit: number;
  searchVal: any;
}) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? OR T.mobile like ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL 90 DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiringCountForStaff = async ({
  clientId,
  propertiesIds,
  days = 90,
}: occupancyTypes & {
  propertiesIds: string;
  days: number;
}) => {
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE())  and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId)) as o";
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE())  and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE(CURDATE()) AND DATE(DATE_ADD(CURDATE(), INTERVAL ? DAY))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
    days,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getTenantWhoseAgrementExpiringCountForStaffCurMonth = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and (DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getTenantWhoseAgrementExpiredForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & {
  propertiesIds: string;
  pageNum: number;
  limit: number;
}) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId AND innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) Desc LIMIT ?, ?"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiredBySearchForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & {
  propertiesIds: string;
  pageNum: number;
  limit: number;
  searchVal: any;
}) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, R.roomNum, T.name as tenantName, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? OR T.mobile like ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId AND innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) Desc LIMIT ?, ?";

  const offset = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantWhoseAgrementExpiredCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  // const query =
  //   "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId)) as o";
  const query =
    "select count(id) as totalCount from (select O.id as id from Occupancies as O where O.clientId = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) as o"; //Pallav - innerO.clientId = O.clientId added to handle multi tenant senario
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalCount;
  else return 0;
};

occupancyDB.getByBedId = async ({ bedId, status }: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.isGstEnabled, O.bookingAmt, O.notes, O.stayType, O.gId, O.discount, O.discountType, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.moveOutReason, O.clientId, O.electricityReading, O.isOnlinePaymentEnabled, O.rentalBond, O.isFineEnabled, O.fine, O.fineType, O.gracePeriod, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.kycStatus, O.rentalType, O.createdAt, O.updatedAt, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, P.type as propertyType, P.name as propName, R.roomNum, R.flatId, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.bedId = ? and O.status = ?";
  const data = [bedId, status];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getAllByBedId = async ({ bedId }: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.bookingAmt, O.notes, O.stayType, O.gId, O.discount, O.discountType, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.moveOutReason, O.clientId, O.electricityReading, O.isOnlinePaymentEnabled, O.rentalBond, O.isFineEnabled, O.fine, O.fineType, O.gracePeriod, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.kycStatus, O.rentalType, O.createdAt, O.updatedAt, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, P.type as propertyType, P.name as propName, R.roomNum, R.flatId, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.bedId = ? and O.status not in (?, ?)";
  const data = [
    bedId,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getLastTenantToMoveInByBedId = async ({ bedId }: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.bookingAmt, O.notes, O.stayType, O.gId, O.discount, O.discountType, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.moveOutReason, O.clientId, O.electricityReading, O.isOnlinePaymentEnabled, O.rentalBond, O.isFineEnabled, O.fine, O.fineType, O.gracePeriod, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.kycStatus, O.rentalType, O.createdAt, O.updatedAt, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, P.type as propertyType, P.name as propName, R.roomNum, R.flatId, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.bedId = ? and O.status not in (?, ?) order by Date(O.moveInDate) desc";
  const data = [
    bedId,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByBedIdAndTenantId = async ({ bedId, tenantId }: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.isGstEnabled, O.bookingAmt, O.notes, O.stayType, O.gId, O.discount, O.discountType, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.moveOutReason, O.clientId, O.electricityReading, O.isOnlinePaymentEnabled, O.rentalBond, O.isFineEnabled, O.fine, O.fineType, O.gracePeriod, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.kycStatus, O.rentalType, O.createdAt, O.updatedAt, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, P.type as propertyType, P.name as propName, R.roomNum, R.flatId, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.bedId = ? and O.tenantId = ?";
  const data = [bedId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByRoomId = async ({ roomId }: occupancyTypes) => {
  const query = "select * from Occupancies where roomId = ?";
  const data = [roomId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByPropId = async ({ propId }: occupancyTypes) => {
  const query = "select * from Occupancies where propId = ? and status not in (?, ?)";
  const data = [
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByFlatId = async ({ flatId }: occupancyTypes) => {
  const query =
    "select O.* from Occupancies as O inner Join Rooms as R on R.id = O.roomId where R.flatId = ?";
  const data = [flatId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByRoomIdandTenantId = async ({
  roomId,
  tenantId,
}: occupancyTypes) => {
  const query = "select * from Occupancies where roomId = ? and tenantId = ?";
  const data = [roomId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutTenant = async ({
  bedId,
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select * from Occupancies where bedId = ? and clientId = ? and propId = ? and status = ?";
  const data = [bedId, clientId, propId, CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupiedOnlyByRoomId = async ({ roomId }: occupancyTypes) => {
  const query =
    "select * from Occupancies where roomId = ? and status in (?, ?) order by id";
  const data = [
    roomId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.addPropId = async ({
  tenantId,
  propId,
  clientId,
}: occupancyTypes) => {
  const query =
    "Insert into Occupancies (tenantId, propId, clientId) values (?, ?, ?)";
  const data = [tenantId, propId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

occupancyDB.updatePropId = async ({ propId, clientId, id }: occupancyTypes) => {
  const query = "Update Occupancies set propId = ?, clientId = ?  where id = ?";
  const data = [propId, clientId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateBookedBy = async ({ bookedBy, id }: occupancyTypes) => {
  const query = "Update Occupancies set bookedBy = ? where id = ?";
  const data = [bookedBy, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateBookedByClientIdAndTenantId = async ({
  bookedBy,
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set bookedBy = ? where clientId = ? and tenantId = ?";
  const data = [bookedBy, clientId, tenantId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.addBasicDetails = async ({
  clientId,
  tenantId,
  propId,
  roomId,
  flatId,
  bedId,
  floor,
  isOnlinePaymentEnabled,
  rentalBond,
  isFoodOpted=0,
}: occupancyTypes) => {
  const query =
    "Insert into Occupancies (clientId, tenantId, propId, roomId, flatId, bedId, floor, isOnlinePaymentEnabled, rentalBond, isFoodOpted) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
  const data = [
    clientId,
    tenantId,
    propId,
    roomId,
    flatId,
    bedId,
    floor,
    isOnlinePaymentEnabled,
    rentalBond,
    isFoodOpted,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

occupancyDB.updateBasicDetails = async ({
  clientId,
  tenantId,
  propId,
  roomId,
  flatId,
  bedId,
  floor,
  isOnlinePaymentEnabled,
  rentalBond,
  isFoodOpted=0,
  id,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set clientId = ?, tenantId = ?, propId = ?, roomId = ?, flatId = ?, bedId = ?, floor = ?, isOnlinePaymentEnabled = ?, rentalBond = ?, isFoodOpted = ? where id = ?";
  const data = [
    clientId,
    tenantId,
    propId,
    roomId,
    flatId,
    bedId,
    floor,
    isOnlinePaymentEnabled,
    rentalBond,
    isFoodOpted,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

occupancyDB.updateAgreementDetails = async ({
  id,
  rent,
  security,
  agreementStartDate,
  rentalCycle,
  agreementPeriod,
  noticePeriod,
  lockInPeriod,
  moveInDate,
  electricityReading = 0,
  fine,
  fineType,
  gracePeriod,
  status,
}: occupancyTypes) => {
  let isFineEnabled = 1;
  if (fine == 0) {
    isFineEnabled = 0;
  }
  const query =
    "Update Occupancies  set rent =?, security =?, agreementStartDate =?, rentalCycle =?, agreementPeriod =?, noticePeriod =?, lockInPeriod =?, moveInDate =?, electricityReading=?, fine=?, fineType=?, gracePeriod=?, status =?, isFineEnabled=? where id = ?";
  const data = [
    rent,
    security,
    agreementStartDate,
    rentalCycle,
    agreementPeriod,
    noticePeriod,
    lockInPeriod,
    moveInDate,
    electricityReading,
    fine,
    fineType,
    gracePeriod,
    status,
    isFineEnabled,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

// rental type and advance rent
occupancyDB.updateAgreementDetailsX = async ({
  id,
  rent,
  security,
  agreementStartDate,
  rentalCycle,
  rentalType,
  rentalMonths,
  agreementPeriod,
  noticePeriod,
  lockInPeriod,
  moveInDate,
  electricityReading = 0,
  fine,
  fineType,
  gracePeriod,
  status,
  bookingAmt = 0,
  bookingAdjustType = 0,
}: occupancyTypes) => {
  let isFineEnabled = 1;
  if (fine == 0) {
    isFineEnabled = 0;
  }
  const query =
    "Update Occupancies  set rent =?, security =?, agreementStartDate =?, rentalCycle =?, rentalType = ?, rentalMonths = ?, agreementPeriod =?, noticePeriod =?, lockInPeriod =?, moveInDate =?, electricityReading=?, fine=?, fineType=?, gracePeriod=?, status =?, isFineEnabled=?, bookingAmt = ?, bookingAdjustType = ? where id = ?";
  const data = [
    rent,
    security,
    agreementStartDate,
    rentalCycle,
    rentalType,
    rentalMonths,
    agreementPeriod,
    noticePeriod,
    lockInPeriod,
    moveInDate,
    electricityReading,
    fine,
    fineType,
    gracePeriod,
    status,
    isFineEnabled,
    bookingAmt,
    bookingAdjustType,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateAgreementDetailsShortStay = async ({
  id,
  rent,
  rentalCycle,
  rentalType,
  security,
  agreementPeriod,
  moveInDate,
  moveOutDate,
  status,
  stayType
}: occupancyTypes) => {
  const query =
    "Update Occupancies  set rent = ?, rentalCycle = ?, rentalType = ?, security = ?, moveInDate = ?, moveOutDate = ?, status = ?, stayType = ?, agreementPeriod = ? where id = ?";
  const data = [
    rent,
    rentalCycle,
    rentalType,
    security,
    moveInDate,
    moveOutDate,
    status,
    stayType,
    agreementPeriod,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.renewAgreementByTenantIdAndClientId = async ({
  tenantId,
  clientId,
  rent,
  agreementStartDate,
  agreementPeriod,
  noticePeriod,
  lockInPeriod,
  isRentAgreementSigned,
  security,
}: occupancyTypes) => {
  const query =
    "Update Occupancies  set  rent=?, agreementStartDate =?, agreementPeriod =?, noticePeriod =?, lockInPeriod =?, isRentAgreementSigned = ?, security = ? where tenantId = ? and clientId = ?";
  const data = [
    rent,
    agreementStartDate,
    agreementPeriod,
    noticePeriod,
    lockInPeriod,
    isRentAgreementSigned,
    security,
    tenantId,
    clientId,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.requestApproved = async ({
  id,
  rent,
  bedId,
  security,
  agreementStartDate,
  rentalCycle,
  rentalMonths,
  agreementPeriod,
  noticePeriod,
  lockInPeriod,
  moveInDate,
  status,
  electricityReading = 0,
  fine,
  fineType,
  gracePeriod,
  isOnlinePaymentEnabled
}: occupancyTypes) => {
  const query =
    "Update Occupancies  set rent =?, bedId=?,  security =?,  agreementStartDate =?, rentalCycle =?, rentalMonths = ?, agreementPeriod =?, noticePeriod =?, lockInPeriod =?, moveInDate =?, status =?, electricityReading=?, fine=?, fineType=?, gracePeriod=?, isOnlinePaymentEnabled=? where id = ?";
  const data = [
    rent,
    bedId,
    security,
    agreementStartDate,
    rentalCycle,
    rentalMonths,
    agreementPeriod,
    noticePeriod,
    lockInPeriod,
    moveInDate,
    status,
    electricityReading,
    fine,
    fineType,
    gracePeriod,
    isOnlinePaymentEnabled,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.addFullOccupancy = async ({
  clientId,
  tenantId,
  propId,
  roomId,
  floor,
  rent,
  bedId,
  security,
  agreementStartDate,
  rentalCycle,
  rentalMonths,
  agreementPeriod,
  noticePeriod,
  lockInPeriod,
  moveInDate,
  electricityReading = 0,
  fine,
  fineType,
  gracePeriod,
  status,
}: occupancyTypes) => {
  const query =
    "Insert into Occupancies (clientId, tenantId, propId, roomId, floor, rent, bedId, security, agreementStartDate, rentalCycle, rentalMonths, agreementPeriod, noticePeriod, lockInPeriod, moveInDate, status, electricityReading, fine, fineType, gracePeriod) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
  const data = [
    clientId,
    tenantId,
    propId,
    roomId,
    floor,
    rent,
    bedId,
    security,
    agreementStartDate,
    rentalCycle,
    rentalMonths,
    agreementPeriod,
    noticePeriod,
    lockInPeriod,
    moveInDate,
    status,
    electricityReading,
    fine,
    fineType,
    gracePeriod,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

occupancyDB.duplicateOccupancy = async ({
  clientId,
  tenantId,
  propId,
  roomId,
  bedId,
  floor,
  rent,
  rentalCycle,
  rentalType,
  rentalMonths,
  noticePeriod,
  lockInPeriod,
  agreementPeriod,
  security,
  agreementStartDate,
  moveInDate,
  moveOutDate,
  status,
  electricityReading,
  fine,
  fineType,
  gracePeriod,
  isFineEnabled,
  isOnlinePaymentEnabled,
  flatId,
  rentalBond,
  stayType,
  notes,
  moveOutReason,
  isPoliceVerified,
  isRentAgreementSigned,
  kycStatus,
  discountType,
  discount,
  discountPeriod,
  discountStartDate,
  discountEndDate,
  isDiscountFromFirstMonth,
  verificationId,
  referenceId,
  gId,
  lastRemindedOn,
  isFoodOpted,
  bookingAmt,
  bookedBy,
  tallyStatus,
  tallyLedgerName,
  isGstEnabled,
}: occupancyTypes) => {

  const query =
    `Insert into Occupancies(clientId, tenantId, propId, roomId, bedId, floor, rent, rentalCycle, rentalType, rentalMonths, noticePeriod, lockInPeriod, agreementPeriod, security, agreementStartDate, moveInDate, moveOutDate, status, electricityReading, fine, fineType, gracePeriod, isFineEnabled, isOnlinePaymentEnabled, flatId, rentalBond, stayType, notes, moveOutReason, isPoliceVerified, isRentAgreementSigned, kycStatus, discountType, discount, discountPeriod, discountStartDate, discountEndDate, isDiscountFromFirstMonth, verificationId, referenceId, gId, lastRemindedOn, isFoodOpted, bookingAmt, bookedBy, tallyStatus, tallyLedgerName, isGstEnabled) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`

  const data = [
    clientId,
    tenantId,
    propId,
    roomId,
    bedId,
    floor,
    rent,
    rentalCycle,
    rentalType,
    rentalMonths,
    noticePeriod,
    lockInPeriod,
    agreementPeriod,
    security,
    agreementStartDate,
    moveInDate,
    moveOutDate,
    status,
    electricityReading,
    fine,
    fineType,
    gracePeriod,
    isFineEnabled,
    isOnlinePaymentEnabled,
    flatId,
    rentalBond,
    stayType,
    notes,
    moveOutReason,
    isPoliceVerified,
    isRentAgreementSigned,
    kycStatus,
    discountType,
    discount,
    discountPeriod,
    discountStartDate,
    discountEndDate,
    isDiscountFromFirstMonth,
    verificationId,
    referenceId,
    gId,
    lastRemindedOn,
    isFoodOpted,
    bookingAmt,
    bookedBy,
    tallyStatus,
    tallyLedgerName,
    isGstEnabled,
  ];

  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

occupancyDB.getByTenantId = async ({ tenantId }: occupancyTypes) => {
  const query = "select * from Occupancies where tenantId = ? order by id desc";
  const data = [tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

// occupancyDB.getByTenantIdAndClientId = async ({ tenantId, clientId }: occupancyTypes) => {
//   const query = "select * from Occupancies where tenantId = ? and clientId = ? order by id desc";
//   const data = [tenantId, clientId];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0];
//   else return false;
// };

occupancyDB.getByTenantIdAsc = async ({ tenantId }: occupancyTypes) => {
  const query = "select * from Occupancies where tenantId = ?";
  const data = [tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.isAllBedOccupiedByTenantId = async ({
  tenantId,
}: occupancyTypes) => {
  const query =
    "select COUNT(id) as count from Occupancies where tenantId = ? order by id desc";
  const data = [tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].count) > 1 ? true : false;
  else return false;
};

occupancyDB.getTotalCountByClientId = async ({ clientId }: occupancyTypes) => {
  const query =
    "select Count(DISTINCT tenantId) as totalOccupanciesCount from Occupancies where clientId = ? and status not in (?, ?)";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTotalCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    "select Count(DISTINCT tenantId) as totalOccupanciesCount from Occupancies where clientId = ? and propId in ( " +
    `${propertiesIds}` +
    ") and status not in (?, ?)";
  const data = [
    clientId,
    //propertiesIds,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTotalCountByClientIdForWeb = async ({ clientId, propIds, }: occupancyTypes & { propIds: any }) => {
  let query =
    "select Count(DISTINCT tenantId) as totalOccupanciesCount from Occupancies where clientId = ? and status not in (?, ?)";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTotalCountForWebStaff = async ({
  clientId,
  propertiesIds,
  propIds,
}: occupancyTypes & { propertiesIds: string; propIds: any; }) => {
  let query =
    `select Count(DISTINCT tenantId) as totalOccupanciesCount from Occupancies where clientId = ? and propId in (${propertiesIds}) and status not in (?, ?)`;
  const data = [
    clientId,
    //propertiesIds,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTotalCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select Count(DISTINCT tenantId) as totalOccupanciesCount from Occupancies where clientId = ? and propId = ? and status not in (?, ?)";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi client occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndLocation = async ({
  clientId,
  locationId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; locationId: number; }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and P.locationId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    locationId,
    //CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndGender = async ({
  clientId,
  pageNum,
  limit,
  gender,
}: occupancyTypes & { pageNum: number; limit: number; gender: any; }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and T.gender =? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndBookedBy = async ({
  clientId,
  pageNum,
  limit,
  filterVal,
}: occupancyTypes & { pageNum: number; limit: number; filterVal: any[]; }) => {
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  let filterCondition = '';

  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }

  let query =
    `select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition} order by O.id desc limit ?, ? `;

  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`)
  data.push(`${limit}`)

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndBookedByAndDate = async ({
  clientId,
  pageNum,
  limit,
  bookedBy,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  
  let query =
  `select O.id as occupancyId, 'occupied' as occupancy, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) and O.bookedBy = ? and DATE(O.createdAt) BETWEEN ? and ? order by O.id desc limit ?, ? `;

  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    bookedBy,
    startDate,
    endDate,
  ];
  
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`)
  data.push(`${limit}`)

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndBookedByAndDate = async ({
  clientId,
  bookedBy,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  
  let query =
  `select COUNT(*) as total from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) and O.bookedBy = ? and DATE(O.createdAt) BETWEEN ? and ?`;

  const data: any = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    bookedBy,
    startDate,
    endDate,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

occupancyDB.getByClientIdOnlineEnabled = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdOnlineNotEnabled = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdTodayBooking = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND DATE(O.createdAt) = curDate() AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    //CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdSortByRoom = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F  on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, CASE WHEN O.flatId IS NOT NULL THEN CAST(F.name AS UNSIGNED) ELSE CAST(O.floor AS UNSIGNED) END, R.id, O.id limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdSortByCreatedAt = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F  on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc, O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

//NOT IN USE
occupancyDB.getByClientIdSortByProp = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F  on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by P.name, R.id limit ?, ? ";
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F  on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, R.id limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery Multi Tenant senerio
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientId = async ({ clientId }: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc "; //Pallav added innerO.clientId = O.clientId in subquery for multi client
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndLocation = async ({ clientId, locationId }: occupancyTypes & { locationId: number }) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and P.locationId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc "; //Pallav added innerO.clientId = O.clientId in subquery for multi client
  const data = [
    clientId,
    locationId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndGender = async ({ clientId, gender }: occupancyTypes & { gender: any }) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndBookedBy = async ({ clientId, filterVal }: occupancyTypes & { filterVal: any[] }) => {

  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];

  let filterCondition = '';

  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }
  const query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition} `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdOnlineEnabled = async ({ clientId }: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdOnlineNotEnabled = async ({ clientId }: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdTodayBooking = async ({ clientId }: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and DATE(O.createdAt) = curdate() AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc "; //Pallav added innerO.clientId = O.clientId in subquery for multi client
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, O.id, O.createdAt desc limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndLocationForStaff = async ({
  clientId,
  locationId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  locationId: number;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND P.locationId = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    locationId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndGenderForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  gender,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  gender: any;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndBookedByForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  filterVal,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  filterVal: any[];
}) => {
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];

  let filterCondition = '';

  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }

  const query =
    `select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (${propertiesIds}) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition} order by O.id desc limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdOnlineEnabledForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};
occupancyDB.getByClientIdOnlineNotEnabledForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getForStaffTodayBooking = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? and DATE(O.createdAt) = curdate() AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getForStaffSortByRoom = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by P.name, CASE WHEN O.flatId IS NOT NULL THEN CAST(F.name AS UNSIGNED) ELSE CAST(O.floor AS UNSIGNED) END, R.id, O.id limit ?, ? ";
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, CASE WHEN O.flatId IS NOT NULL THEN CAST(F.name AS UNSIGNED) ELSE CAST(O.floor AS UNSIGNED) END, R.id, O.id limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant occupancies
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getForStaffSortByCreatedAt = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc, O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};
occupancyDB.getByClientIdAndPropIdOnlineEnabled = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.agreementStartDate, O.agreementPeriod, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};
occupancyDB.getByClientIdAndPropIdOnlineNotEnabled = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropIdAndGender = async ({
  clientId,
  propId,
  pageNum,
  limit,
  gender
}: occupancyTypes & { pageNum: number; limit: number; gender: any; }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropIdAndBookedBy = async ({
  clientId,
  propId,
  pageNum,
  limit,
  filterVal,
}: occupancyTypes & { pageNum: number; limit: number; filterVal: any; }) => {
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  let filterCondition = '';
  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }

  const query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition} order by O.id desc limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`)
  data.push(`${limit}`)
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropIdSortByRoomFlat = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by REGEXP_SUBSTR(F.name, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(F.name, '[0-9]+') AS UNSIGNED), R.id, O.id limit ?, ? ";
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId AND innerO.clientId= O.clientId GROUP BY innerO.tenantId ) order by REGEXP_SUBSTR(F.name, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(F.name, '[0-9]+') AS UNSIGNED), R.id, O.id limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery Molti tenant senerio
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropIdSortByRoomPg = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by ISNULL(REGEXP_SUBSTR(O.floor, '^[A-Za-z]+')), REGEXP_SUBSTR(O.floor, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(O.floor, '[0-9]+') AS UNSIGNED), R.id, O.id limit ?, ? ";
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by ISNULL(REGEXP_SUBSTR(O.floor, '^[A-Za-z]+')), REGEXP_SUBSTR(O.floor, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(O.floor, '[0-9]+') AS UNSIGNED), R.id, O.id limit ?, ? "; //Pallav addded innerO.clientId = O.clientId in subquery for multi tenant senerio
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndPropIdSortByCreatedAt = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc, O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};
occupancyDB.getCountByClientIdAndPropIdOnlineEnabled = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};
occupancyDB.getCountByClientIdAndPropIdOnlineNotEnabled = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndPropIdAndGender = async ({
  clientId,
  propId,
  gender,
}: occupancyTypes & { gender: any }) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndPropIdAndBookedBy = async ({
  clientId,
  propId,
  filterVal,
}: occupancyTypes & { filterVal: any }) => {
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  let filterCondition = '';
  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }

  const query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition} `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnpaidTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  //const query = "select * from (select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(amount) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) and date(moveInDate)<=curdate() AND LEFT(SUBSTRING_index(O.rentalCycle, '-', 1), char_length(SUBSTRING_index(O.rentalCycle, '-', 1)) - 2)< DATE_FORMAT(CURRENT_TIMESTAMP, '%d') AND adddate(date(moveInDate), P.gracePeriod)<curdate() order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ?;   ";

  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(amount) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) and date(moveInDate)<=curdate() AND if(MONTH(moveInDate)= MONTH(now()), , ) adddate(CONCAT(DATE_FORMAT(now(),'%Y-%m'), '-',SUBSTRING_index(O.rentalCycle, '-', 1)), P.gracePeriod)<curdate() AND adddate(date(moveInDate), P.gracePeriod)<curdate() order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ?;   ";

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnpaidTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v  where totalDues IS NOT NULL";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnpaidTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnpaidTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate,O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnpaidTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v  where totalDues IS NOT NULL";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getPaidTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues is NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPaidTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues is NULL";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getPaidTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues is NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPaidTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues is NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPaidTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues is NULL ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getMovingOutTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.moveOutDate asc, O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveOutDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    // CONSTANTS.OCCUPANCY_STATUS.PENDING,
    // CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    // CONSTANTS.TENANT_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT, //Pallav O.status NOT IN (?, ?) changed to O.status = ?
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getMovingOutTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    // CONSTANTS.OCCUPANCY_STATUS.PENDING,
    // CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    // CONSTANTS.TENANT_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT, //Pallav O.status NOT IN (?, ?) changed to O.status = ?
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getMovingOutTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    // CONSTANTS.OCCUPANCY_STATUS.PENDING,
    // CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    // CONSTANTS.TENANT_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

//Pallav O.status NOT IN (?, ?) (Pending & Requested), changed to O.status = ? in the below function and removed T.status = ?
occupancyDB.getMovingOutTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status =? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveOutDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

//Pallav O.status NOT IN (?, ?) (Pending & Requested), changed to O.status = ? in the below function and removed T.status = ?
occupancyDB.getMovingOutTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, T.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v limit ?, ? "; //Pallav added and innerM.clientId=M.clientId  to handle Multi tenant senerio
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsByClientIdAndDateRange = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, (CASE WHEN M.refundStatus in (?, ?) THEN (select COALESCE((balance)*-1, 0) from Ledgers where clientId = M.clientId and tenantId = M.tenantId and description like ? and DATE(createdAt) >= M.moveInDate order by id limit 1) - (select COALESCE(SUM(balance), 0) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) ELSE 0 END) as refundAmount, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId and innerM.status = ? GROUP BY innerM.tenantId) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.REFUND_STATUS.PENDING,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
    "%Refund after eviction%",
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientIdAndDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND DATE(M.moveOutDate) BETWEEN ? and ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, startDate, endDate, CONSTANTS.MOVE_OUT_STATUS.INITIATED, CONSTANTS.MOVE_OUT_STATUS.MOVEOUT];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsSearchByClientId = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.agreementStartDate, M.agreementPeriod, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsSearchCountByClientId = async ({
  clientId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsSearchByPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.agreementStartDate, M.agreementPeriod, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsSearchCountByPropId = async ({
  clientId,
  propId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsSearchByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string; propertiesIds: string }) => {
  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.agreementStartDate, M.agreementPeriod, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsSearchCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  searchVal,
}: occupancyTypes & { searchVal: string; propertiesIds: string }) => {
  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v `;
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.propId in (" +
    `${propertiesIds}` +
    ") and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsForStaffAndDateRange = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  startDate: string;
  endDate: string;
}) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.propId in (" +
    `${propertiesIds}` +
    ") and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    //propertiesIds,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsByClientIdAndPropIdWithSearch = async ({
  clientId,
  propId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v  where v.name LIKE ? or v.mobile LIKE ? limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientIdAndPropIdWithSearch = async ({
  clientId,
  propId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) and T.name LIKE ? or T.mobile LIKE ? order by M.createdAt desc) as v";
  const data = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, `%${searchVal}%`, `%${searchVal}%`];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsByClientIdAndPropIdAndDateRange = async ({
  clientId,
  propId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientIdAndPropIdAndDateRange = async ({
  clientId,
  propId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string; }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, propId, startDate, endDate, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCurMonthEvictedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and Month(moveOutDate) = Month(curdate()) and Year(moveOutDate) = Year(curdate()) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCurMonthEvictedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and Month(moveOutDate) = Month(curdate()) and Year(moveOutDate) = Year(curdate()) and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCurMonthEvictedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and Month(M.moveOutDate) = Month(curdate()) and Year(M.moveOutDate) = Year(curdate()) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCurMonthEvictedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and Month(moveOutDate) = Month(curdate()) and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCurMonthEvictedTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and Month(moveOutDate) = Month(curdate()) and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCurMonthEvictedTenantsCountByClientIdForStaff = async ({
  clientId,
  propertiesIds
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and Month(moveOutDate) = Month(curdate()) and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v `;
  const data = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getDefaulterEvictedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v where totalDues > 0 limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getDefaulterEvictedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.tenantDues > 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getDefaulterEvictedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.tenantDues > 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getDefaulterEvictedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.tenantDues > 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getDefaulterEvictedTenantsByClientIdAndDateRange = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string }) => {
  const query =
    "select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v where totalDues > 0 limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getDefaulterEvictedTenantsCountByClientIdAndDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string; }) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.tenantDues > 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, startDate, endDate, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getDefaulterEvictedTenantsByClientIdAndDateRangeForStaff = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
  propertiesIds,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propertiesIds: string; }) => {
  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) and DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v where totalDues > 0 limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    clientId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getDefaulterEvictedTenantsCountByClientIdAndDateRangeForStaff = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
}: occupancyTypes & { startDate: string; endDate: string; propertiesIds: string; }) => {
  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) and DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.tenantDues > 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v `;
  const data = [clientId, startDate, endDate, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getSearchResultByClientId = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.name as propertyName, R.roomNum, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id as occupancyId, 1 as movingOut, M.createdAt, M.moveInDate, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, P.name as propertyName, R.roomNum, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, NULL as profilePicture from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v order by createdAt desc limit ?,? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSearchResultCountByClientId = async ({
  clientId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantSearchByClientId = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, O.isPoliceVerified, O.isRentAgreementSigned, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId=O.clientId GROUP BY innerO.tenantId) order by createdAt desc limit ?,? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantSearchCountByClientId = async ({
  clientId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "Select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getSearchResultForStaff = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  searchVal: string;
  propertiesIds: string;
}) => {
  // const query =
  //   "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId=O.clientId GROUP BY innerO.tenantId )  UNION Select M.id as occupancyId, 1 as movingOut, M.createdAt, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, NULL as profilePicture from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId )) as v order by createdAt desc limit ?,? ";
  const query =
    "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.propId in (" + `${propertiesIds}` + ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId=O.clientId GROUP BY innerO.tenantId )) as v order by createdAt desc limit ?,? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    //propertiesIds,
    // clientId,
    // CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    // `%${searchVal}%`,
    // `%${searchVal}%`,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

// occupancyDB.getSearchResultByClientIdAndPropId = async ({
//   clientId,
//   propId,
//   pageNum,
//   limit,
//   searchVal,
// }: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
//   const query =
//     "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, O.kycStatus, T.device as platform, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id as occupancyId, 1 as movingOut, M.createdAt, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, M.kycStatus as kycStatus, NULL as platform, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, NULL as profilePicture from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.propId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v order by createdAt desc limit ?,? ";
//   const offset: number = (pageNum - 1) * limit;
//   const data = [
//     CONSTANTS.DOCUMENT_TYPES.SELFI,
//     clientId,
//     propId,
//     CONSTANTS.OCCUPANCY_STATUS.PENDING,
//     CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//     clientId,
//     propId,
//     CONSTANTS.MOVE_OUT_STATUS.INITIATED,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//     `${offset}`,
//     `${limit}`,
//   ];

//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows;
//   else return false;
// };

// occupancyDB.getSearchResultCountByClientIdAndPropId = async ({
//   clientId,
//   propId,
//   searchVal,
// }: occupancyTypes & { searchVal: string }) => {
//   const query =
//     "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.propId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v";
//   const data = [
//     clientId,
//     propId,
//     CONSTANTS.OCCUPANCY_STATUS.PENDING,
//     CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//     clientId,
//     propId,
//     CONSTANTS.MOVE_OUT_STATUS.INITIATED,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//   ];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0].count;
//   else return 0;
// };


occupancyDB.getSearchResultByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, O.kycStatus, T.device as platform, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )) as v order by createdAt desc limit ?,? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSearchResultCountByClientIdAndPropId = async ({
  clientId,
  propId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )) as v";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByTenantIdForWeb = async ({ tenantId }: occupancyTypes) => {
  const query =
    "select O.id, O.clientId, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, C.mobile as ownerMobile, P.name as propName, P.address as propertyAddress, P.streetAddress as propertyStreetAddress, P.isIdVerificationEnabled, P.isPanVerificationEnabled, P.isRentAgreementEnabled, P.isPoliceVerificationEnabled, P.isOnlinePaymentEnabled, R.roomNum from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Clients as C on C.id = O.clientId where O.tenantId = ?";
  const data = [tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByTenantIdAndClientIdForWeb = async ({ tenantId, clientId }: occupancyTypes) => {
  const query =
    "select O.id, O.bookingAmt, O.bookingAdjustType, O.isFoodOpted, O.isBusOpted, O.isGstEnabled, O.clientId, O.tenantId, O.gId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.isOnlinePaymentEnabled as isOnlinePaymentEnabledTenant, O.status, O.stayType, C.mobile as ownerMobile, P.name as propName, P.address as propertyAddress, P.streetAddress as propertyStreetAddress, P.isIdVerificationEnabled, P.isPanVerificationEnabled, P.isRentAgreementEnabled, P.isPoliceVerificationEnabled, P.isOnlinePaymentEnabled, R.roomNum from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Clients as C on C.id = O.clientId where O.tenantId = ? and O.clientId = ?";
  const data = [tenantId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByTenantIdAndClientId = async ({
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.tallyStatus, O.tallyLedgerName, O.lastRemindedOn, O.referenceId, O.bookingAmt, O.isGstEnabled, O.verificationId, O.notes, O.kycStatus, O.discountType, O.gId, O.discount, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.stayType, O.moveOutReason, O.isPoliceVerified, O.isRentAgreementSigned, O.isOnlinePaymentEnabled, O.rentalBond, O.createdAt, O.clientId, O.tenantId, O.isFineEnabled, O.fine, R.flatId, O.fineType, O.gracePeriod, O.electricityReading, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.rentalType, O.rentalMonths, O.bookedBy, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, C.mobile as ownerMobile, P.name as propName, P.type as propType, P.address as propertyAddress, P.streetAddress as propertyStreetAddress, P.isIdVerificationEnabled, P.isPanVerificationEnabled, P.isRentAgreementEnabled, P.isPoliceVerificationEnabled, P.isOnlinePaymentEnabled as propOnlineEnable, R.roomNum, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities, (Select value from Documents where tenantId = O.tenantId and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.clientId = ? and O.tenantId = ?";
  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByMultipleTenantIdAndClientId = async ({
  clientId,
  tenantIds,
}: occupancyTypes & { tenantIds: any }) => {
  const query =
    `select O.id, O.isFoodOpted, O.isBusOpted, O.bookingAmt, O.verificationId, O.notes, O.kycStatus, O.discountType, O.gId, O.discount, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.stayType, O.moveOutReason, O.isPoliceVerified, O.isRentAgreementSigned, O.isOnlinePaymentEnabled, O.rentalBond, O.createdAt, O.clientId, O.tenantId, O.isFineEnabled, O.fine, R.flatId, O.fineType, O.gracePeriod, O.electricityReading, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.rentalType, O.rentalMonths, O.bookedBy, CASE WHEN O.bookedBy IS NULL OR O.bookedBy = 0 THEN C.name ELSE S.name END as bookedByName, C.mobile as ownerMobile, P.name as propName, P.type as propType, P.address as propertyAddress, P.streetAddress as propertyStreetAddress, P.isIdVerificationEnabled, P.isPanVerificationEnabled, P.isRentAgreementEnabled, P.isPoliceVerificationEnabled, P.isOnlinePaymentEnabled as propOnlineEnable, R.roomNum, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId left join Staffs as S on S.id = O.bookedBy where O.clientId = ? and O.tenantId in (${tenantIds})`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAllByTenantIdAndClientId = async ({
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query =
    "select O.id, O.isFoodOpted, O.isBusOpted, O.tallyStatus, O.isGstEnabled, O.bookingAmt, O.bookedBy, O.verificationId, O.notes, O.kycStatus, O.discountType, O.gId, O.discount, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.stayType, O.moveOutReason, O.isPoliceVerified, O.isRentAgreementSigned, O.isOnlinePaymentEnabled, O.rentalBond, O.createdAt, O.clientId, O.tenantId, O.isFineEnabled, O.fine, R.flatId, O.fineType, O.gracePeriod, O.electricityReading, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.rentalType, O.rentalMonths, C.mobile as ownerMobile, P.name as propName, P.type as propType, P.address as propertyAddress, P.streetAddress as propertyStreetAddress, P.isIdVerificationEnabled, P.isPanVerificationEnabled, P.isRentAgreementEnabled, P.isPoliceVerificationEnabled, P.isOnlinePaymentEnabled as propOnlineEnable, R.roomNum, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join RoomOptions as RO on RO.id = R.roomOptionId left join Clients as C on C.id = O.clientId where O.clientId = ? and O.tenantId = ? order by O.id desc";
  const data = [clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAllByTenantIdAndClientIdAsc = async ({
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query =
    "select O.id, O.gId, O.notes, O.tallyStatus, O.isGstEnabled, O.stayType, O.bookedBy, O.discountType, O.discount, O.discountPeriod, O.discountStartDate, O.discountEndDate, O.isDiscountFromFirstMonth, O.kycStatus, O.moveOutReason, O.isOnlinePaymentEnabled, O.isPoliceVerified, O.isRentAgreementSigned, O.rentalBond, O.clientId, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.rent, O.rentalCycle, O.rentalType, O.rentalMonths, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.createdAt, R.flatId, P.name as propName, R.roomNum from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId where O.clientId = ? and O.tenantId = ?";
  const data = [clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getParticularOccupancies = async ({
  clientId,
  tenantId,
  propId,
  roomId,
}: occupancyTypes) => {
  const query =
    "select * from Occupancies where clientId = ? and tenantId = ? and propId = ? and roomId = ?";
  const data = [clientId, tenantId, propId, roomId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.updateStatus = async ({ status, id }: occupancyTypes) => {
  const query = "Update Occupancies set status=? where id =?";
  const data = [status, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateRent = async ({
  tenantId,
  clientId,
  rent,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set rent=? where tenantId = ? and clientId = ?";
  const data = [rent, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.disableFine = async ({ clientId, tenantId }: occupancyTypes) => {
  const query = "Update Occupancies set isFineEnabled=? where clientId = ? and tenantId = ?";
  const data = ["0", clientId, tenantId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.enableFine = async ({ clientId, tenantId }: occupancyTypes) => {
  const query = "Update Occupancies set isFineEnabled=? where clientId = ? and tenantId = ?";
  const data = ["1", clientId, tenantId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.switchRoom = async ({
  id,
  roomId,
  bedId,
  floor,
  rent,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set roomId=?, bedId=?, floor=?, rent=? where id =?";
  const data = [roomId, bedId, floor, rent, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.switchRoomAndFlat = async ({
  id,
  roomId,
  flatId,
  bedId,
  floor,
  rent,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set roomId=?, bedId=?, floor=?, rent=?, flatId=? where id =?";
  const data = [roomId, bedId, floor, rent, flatId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateSecurity = async ({
  tenantId,
  clientId,
  security,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set security=? where tenantId = ? and clientId = ?";
  const data = [security, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.addSecurity = async ({
  tenantId,
  clientId,
  security,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set security = security + ? where tenantId = ? and clientId = ?";
  const data = [security, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateAgreementPeriod = async ({
  tenantId,
  clientId,
  agreementPeriod,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set agreementPeriod=? where tenantId = ? and clientId = ?";
  const data = [agreementPeriod, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateFine = async ({ fine, id }: occupancyTypes) => {
  const query = "Update Occupancies set fine=? where id =?";
  const data = [fine, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateGracePeriod = async ({ gracePeriod, id }: occupancyTypes) => {
  const query = "Update Occupancies set gracePeriod=? where id =?";
  const data = [gracePeriod, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateMoveInDate = async ({
  tenantId,
  clientId,
  moveInDate,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set moveInDate=?, agreementStartDate=? where tenantId = ? and clientId = ?";
  const data = [moveInDate, moveInDate, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateMoveOutDateNew = async ({
  tenantId,
  clientId,
  moveOutDate,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set moveOutDate=? where tenantId = ? and clientId = ?";
  const data = [moveOutDate, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateMoveOutDate = async ({ moveOutDate, id, moveOutReason }: occupancyTypes) => {
  const query = "Update Occupancies set moveOutDate=?, moveOutReason=? where id =?";
  const data = [moveOutDate, moveOutReason, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.initiateMoveOut = async ({
  status,
  id,
  moveOutDate,
}: occupancyTypes) => {
  const query = "Update Occupancies set status=?, moveOutDate=? where id =?";
  const data = [status, moveOutDate, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.extendStay = async ({ id, moveOutDate }: occupancyTypes) => {
  const query = "Update Occupancies set moveOutDate=? where id =?";
  const data = [moveOutDate, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.cancelMoveOut = async ({ status, id }: occupancyTypes) => {
  const query = "Update Occupancies set status=?, moveOutDate=NULL where id =?";
  const data = [status, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.cancelMoveOutShortStay = async ({ status, id, moveOutDate }: occupancyTypes) => {
  const query = "Update Occupancies set status = ?, moveOutDate = ? where id = ?";
  const data = [status, moveOutDate, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.addRoomId = async ({ roomId, floor, id }: occupancyTypes) => {
  const query = "Update Occupancies set roomId=?, floor=? where id=?";
  const data = [roomId, floor, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.addFlatId = async ({ flatId, id }: occupancyTypes) => {
  const query = "Update Occupancies set flatId=? where id=?";
  const data = [flatId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

// occupancyDB.updateSecurity = async ({ security, id }: occupancyTypes) => {
//   const query = "Update Occupancies set security=? where id=?";
//   const data = [security, id];
//   const [rows] = await DB.query<ResultSetHeader>(query, data);
//   return true;
// };

occupancyDB.updateElectricityUnits = async ({
  electricityReading,
  tenantId,
  clientId,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set electricityReading=? where tenantId=? and clientId=? ";
  const data = [electricityReading, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.removeByTenantId = async ({ tenantId }: occupancyTypes) => {
  const query = "Delete from Occupancies where tenantId=?";
  const data = [tenantId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.removeByClinetIdAndTenantId = async ({ clientId, tenantId }: occupancyTypes) => {
  const query = "Delete from Occupancies where clientId = ? and tenantId=?";
  const data = [clientId, tenantId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.removeById = async ({ id }: occupancyTypes) => {
  const query = "Delete from Occupancies where id=?";
  const data = [id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getSearchResultCountForStaff = async ({
  clientId,
  searchVal,
  propertiesIds,
}: occupancyTypes & {
  searchVal: string;
  propertiesIds: string;
}) => {
  // const query =
  //   "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND  M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.propId in (" +
  //   `${propertiesIds}` +
  //   ") AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v";
  const query =
    "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.propId in (" + `${propertiesIds}` + ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )) as v";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    //propertiesIds,
    // clientId,
    // CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    // `%${searchVal}%`,
    // `%${searchVal}%`,
    //propertiesIds,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnpaidTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select O.id, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues IS NOT NULL";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getMovingOutTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and O.status = ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    // CONSTANTS.OCCUPANCY_STATUS.PENDING,
    // CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    // CONSTANTS.TENANT_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.propId in (" +
    `${propertiesIds}` +
    ") and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v  ";
  const data = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    //propertiesIds
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsCountForStaffAndDateRange = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & {
  propertiesIds: string;
  startDate: string;
  endDate: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND DATE(M.moveOutDate) BETWEEN ? and ? AND M.status != ? and M.propId in (" +
    `${propertiesIds}` +
    ") and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId and innerM.status = ? GROUP BY innerM.tenantId ) order by M.createdAt desc) as v  ";
  const data = [
    clientId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    //propertiesIds
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndLocationForStaff = async ({
  clientId,
  locationId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
  locationId: number;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and P.locationId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    locationId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndGenderForStaff = async ({
  clientId,
  propertiesIds,
  gender,
}: occupancyTypes & {
  propertiesIds: string;
  gender: any;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and T.gender = ? AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    gender,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdAndBookedByForStaff = async ({
  clientId,
  propertiesIds,
  filterVal,
}: occupancyTypes & {
  propertiesIds: string;
  filterVal: any[];
}) => {

  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    //propertiesIds,
  ];

  let filterCondition = '';
  if (filterVal && filterVal.length > 0) {
    filterCondition += ` and O.bookedBy in (${filterVal.map(() => '?').join(',')})`;
    data.push(...filterVal);
  }

  const query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) AND O.propId in (${propertiesIds}) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ${filterCondition}`;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdOnlineEnabledForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountByClientIdOnlineNotEnabledForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getCountForStaffTodayBooking = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? and DATE(O.createdAt) = curDate() AND O.status NOT IN (?, ?) AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getOccupiedAndVacantByMonth = async (
  clientId: number,
  year: any
) => {
  const query =
    "SELECT MONTH(createdAt) AS month, SUM(CASE WHEN status IN (3, 4) THEN 1 ELSE 0 END) AS occupied_count, SUM(CASE WHEN status IN (1, 2, 5) THEN 1 ELSE 0 END) AS vacant_count FROM Occupancies WHERE clientId = ? and YEAR(createdAt) = ? GROUP BY MONTH(createdAt) ORDER BY MONTH(createdAt);";
  const data = [clientId, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

occupancyDB.getMovingOutTenantByPropId = async (
  clientId: number,
  propId: number
) => {
  const query =
    "SELECT COUNT(moveOutDate) as moveOut FROM Occupancies WHERE clientId = ? AND propId = ? AND moveOutDate IS NOT NULL;";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInTenantByPropId = async (
  clientId: number,
  propId: number
) => {
  const query =
    "SELECT COUNT(moveOutDate) as moveIn FROM Occupancies WHERE clientId = ? AND propId = ? AND moveOutDate IS NOT NULL;";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

// Not getting used anywhere
occupancyDB.getVerifiedTenantByPropId = async (
  clientId: number,
  propId: number
) => {
  const query =
    "SELECT COUNT(t.id) AS verified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.propId = ? AND t.kycStatus > ?";
  const data = [clientId, propId, CONSTANTS.KYC_STATUS.PENDING];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};
// Not getting used anywhere
occupancyDB.getUnverifiedTenantByPropId = async (
  clientId: number,
  propId: number
) => {
  const query =
    "SELECT COUNT(t.id) AS notVerified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.propId = ? AND t.kycStatus <?;";
  const data = [clientId, propId, CONSTANTS.KYC_STATUS.ID_UPLOADED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupancyStatsForClient = async (clientId: number) => {
  const query =
    `select (SELECT COUNT(DISTINCT(tenantId)) as moveOut FROM Occupancies WHERE clientId = ? AND status = ?) as moveOut, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND status =?) as moveIn, (SELECT COUNT(DISTINCT t.id) AS verified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.kycStatus > ? and o.status NOT IN (?, ?)) as verified, (SELECT COUNT(DISTINCT t.id) AS notVerified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND t.kycStatus <? and o.status NOT IN (?, ?)) as unVerified, (SELECT COUNT(DISTINCT t.id) AS totalTenants FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.status NOT IN (?, ?)) as totalTenants, (SELECT COUNT(DISTINCT(tenantId)) AS newTenants from Occupancies where clientId = ? and date(moveInDate) = curdate()) as newTenants, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND status =?) as reserved, (Select COUNT(DISTINCT(tenantId)) as todayBooking from Occupancies where clientId = ? and status not in (?, ?) and DATE(createdAt) = curDate()) as todayBooking`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.KYC_STATUS.SELFI_UPLOADED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupancyStatsForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select (SELECT COUNT(DISTINCT(tenantId)) as moveOut FROM Occupancies WHERE clientId = ? and propId in (${propertiesIds}) AND status = ?) as moveOut, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? and propId in (${propertiesIds}) AND status =?) as moveIn, (SELECT COUNT(DISTINCT t.id) AS verified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? and o.propId in (${propertiesIds}) AND t.kycStatus > ? and o.status NOT IN (?, ?)) as verified, (SELECT COUNT(DISTINCT t.id) AS notVerified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? and o.propId in (${propertiesIds}) AND t.kycStatus <? and o.status NOT IN (?, ?)) as unVerified, (SELECT COUNT(DISTINCT t.id) AS totalTenants FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? and o.propId in (${propertiesIds}) AND o.status NOT IN (?, ?)) as totalTenants, (SELECT COUNT(DISTINCT(tenantId)) AS newTenants from Occupancies where clientId = ? and propId in (${propertiesIds}) and date(moveInDate) = curdate()) as newTenants, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? and propId in (${propertiesIds}) AND status =?) as reserved, (Select COUNT(DISTINCT(tenantId)) as todayBooking from Occupancies where clientId = ? and status not in (?, ?) and propId in (${propertiesIds}) and DATE(createdAt) = curDate()) as todayBooking`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.KYC_STATUS.SELFI_UPLOADED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupancyStatsForWebClient = async ({
  clientId,
  propIds,
}: occupancyTypes & { propIds: any }) => {

  let filterCondition = "";

  if (propIds && propIds.length > 0) {
    filterCondition = ` and O.propId in (${propIds.join(",")})`;
  }

  const query =
    `select 
    (SELECT COUNT(DISTINCT(O.tenantId)) as moveOut FROM Occupancies as O WHERE O.clientId = ? AND O.status = ? ${filterCondition}) as moveOut, 
    (SELECT COUNT(DISTINCT O.tenantId) as moveIn FROM Occupancies as O WHERE O.clientId = ? AND O.status =? ${filterCondition}) as moveIn, 
    (SELECT COUNT(DISTINCT T.id) AS verified FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? AND O.kycStatus > ? and O.status NOT IN (?, ?) ${filterCondition}) as verified, 
    (SELECT COUNT(DISTINCT T.id) AS notVerified FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? AND O.kycStatus <? and O.status NOT IN (?, ?) ${filterCondition}) as unVerified, 
    (SELECT COUNT(DISTINCT T.id) AS totalTenants FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? AND O.status NOT IN (?, ?) ${filterCondition}) as totalTenants, 
    (SELECT COUNT(DISTINCT(O.tenantId)) AS newTenants from Occupancies as O where O.clientId = ? and date(O.moveInDate) = curdate() ${filterCondition}) as newTenants, 
    (SELECT COUNT(DISTINCT O.tenantId) as moveIn FROM Occupancies as O WHERE O.clientId = ? AND O.status =? ${filterCondition}) as reserved, 
    (Select COUNT(DISTINCT(O.tenantId)) as todayBooking from Occupancies as O where O.clientId = ? and O.status not in (?, ?) and DATE(O.createdAt) = curDate() ${filterCondition}) as todayBooking`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.KYC_STATUS.SELFI_UPLOADED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupancyStatsForWebStaff = async ({
  clientId,
  propertiesIds,
  propIds,
}: occupancyTypes & { propertiesIds: string; propIds: any; }) => {

  let filterCondition = "";

  if (propIds && propIds.length > 0) {
    filterCondition = ` and O.propId in (${propIds.join(",")})`;
  }

  const query =
    `select 
    (SELECT COUNT(DISTINCT(O.tenantId)) as moveOut FROM Occupancies as O WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.status = ? ${filterCondition}) as moveOut, 
    (SELECT COUNT(DISTINCT O.tenantId) as moveIn FROM Occupancies as O WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.status =? ${filterCondition}) as moveIn, 
    (SELECT COUNT(DISTINCT T.id) AS verified FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.kycStatus > ? and O.status NOT IN (?, ?) ${filterCondition}) as verified, 
    (SELECT COUNT(DISTINCT T.id) AS notVerified FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.kycStatus < ? and O.status NOT IN (?, ?) ${filterCondition}) as unVerified, 
    (SELECT COUNT(DISTINCT T.id) AS totalTenants FROM Tenants T JOIN Occupancies O ON T.id = O.tenantId WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.status NOT IN (?, ?) ${filterCondition}) as totalTenants, 
    (SELECT COUNT(DISTINCT(O.tenantId)) AS newTenants from Occupancies as O where O.clientId = ? and O.propId in (${propertiesIds}) and date(O.moveInDate) = curdate() ${filterCondition}) as newTenants, 
    (SELECT COUNT(DISTINCT O.tenantId) as moveIn FROM Occupancies as O WHERE O.clientId = ? and O.propId in (${propertiesIds}) AND O.status =? ${filterCondition}) as reserved, 
    (Select COUNT(DISTINCT(O.tenantId)) as todayBooking from Occupancies as O where O.clientId = ? and O.status not in (?, ?) and O.propId in (${propertiesIds}) and DATE(O.createdAt) = curDate() ${filterCondition}) as todayBooking`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.KYC_STATUS.SELFI_UPLOADED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getOccupancyStatsByPropId = async (
  clientId: number,
  propId: number
) => {
  const query =
    "select (SELECT COUNT(DISTINCT(tenantId)) as moveOut FROM Occupancies WHERE clientId = ? AND propId = ? AND status = ?) as moveOut, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND propId = ? AND status =?) as moveIn, (SELECT COUNT(DISTINCT t.id) AS verified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.propId = ? AND o.kycStatus > ? and o.status NOT IN (?, ?)) as verified, (SELECT COUNT(DISTINCT t.id) AS notVerified FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.propId = ? AND o.kycStatus <? and o.status NOT IN (?, ?)) as unVerified, (SELECT COUNT(DISTINCT t.id) AS totalTenants FROM Tenants t JOIN Occupancies o ON t.id = o.tenantId WHERE o.clientId = ? AND o.propId = ? AND o.status NOT IN (?, ?)) as totalTenants, (SELECT COUNT(DISTINCT(tenantId)) AS newTenants from Occupancies where clientId = ? and date(moveInDate) = curdate() AND propId = ?) as newTenants, (SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND propId = ? AND status =?) as reserved, (Select COUNT(DISTINCT(tenantId)) as todayBooking from Occupancies where clientId = ? and propId = ? and status not in (?, ?) and DATE(createdAt) = curDate()) as todayBooking";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    propId,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    propId,
    CONSTANTS.KYC_STATUS.SELFI_UPLOADED,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    propId,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

// occupancyDB.getTenantsMoveInAndMoveOutDate = async ({
//   clientId,
//   propId,
//   roomId,
//   startDate,
//   endDate,
// }: occupancyTypes & { startDate: string; endDate: string }) => {
//   // const query =
//   //   "WITH CurrentTenants AS ( SELECT tenantId,moveInDate,'9999-12-31' AS moveOutDate FROM Occupancies where clientId=? and propId=? and status IN (?,?) and roomId=?),HistoricalTenants AS (SELECT tenantId,moveInDate,moveOutDate FROM MoveOut WHERE clientId= ?  and propId=? and roomId=? and moveOutDate >= ? AND moveInDate <= ?), CombinedTenants AS (SELECT * FROM CurrentTenants UNION SELECT * FROM HistoricalTenants) SELECT tenantId, GREATEST(moveInDate, ?) AS effectiveMoveIn, LEAST(moveOutDate, ?) AS effectiveMoveOut FROM CombinedTenants WHERE moveInDate <=? AND moveOutDate >= ?";
//   const query =
//     "WITH CurrentTenants AS ( SELECT tenantId,date(moveInDate) as moveInDate,'9999-12-31' AS moveOutDate FROM Occupancies where clientId=? and propId=? and status IN (?,?) and roomId=?),HistoricalTenants AS (SELECT tenantId,date(moveInDate) as moveInDate,date(moveOutDate) as moveOutDate FROM MoveOut WHERE clientId= ?  and propId=? and roomId=? and date(moveOutDate) >= ? AND date(moveInDate) <= ? and status = ?), CombinedTenants AS (SELECT * FROM CurrentTenants UNION SELECT * FROM HistoricalTenants) SELECT tenantId, GREATEST(date(moveInDate), ?) AS effectiveMoveIn, LEAST(date(moveOutDate), ?) AS effectiveMoveOut FROM CombinedTenants WHERE date(moveInDate) <=? AND date(moveOutDate) >= ?";

//   const data = [
//     clientId,
//     propId,
//     CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
//     CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
//     roomId,
//     clientId,
//     propId,
//     roomId,
//     startDate,
//     endDate,
//     CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
//     startDate,
//     endDate,
//     endDate,
//     startDate,
//   ];

//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows;
//   else return [];
// };

occupancyDB.getTenantsMoveInAndMoveOutDate = async ({
  clientId,
  propId,
  roomIds,
  startDate,
  endDate,
}: occupancyTypes & { roomIds: any; startDate: string; endDate: string }) => {

  const query =
    `WITH CurrentTenants AS ( SELECT 'occupied' as type, tenantId,date(moveInDate) as moveInDate,'9999-12-31' AS moveOutDate, roomId FROM Occupancies where clientId=? and propId=? and status IN (?,?) and roomId in (${roomIds.map(() => '?').join(',')})),HistoricalTenants AS (SELECT 'moveOut' as type, tenantId,date(moveInDate) as moveInDate,date(moveOutDate) as moveOutDate, roomId FROM MoveOut WHERE clientId= ?  and propId=? and wasCancelled = 0 and roomId in (${roomIds.map(() => '?').join(',')}) and date(moveOutDate) >= ? AND date(moveInDate) <= ? and status = ?), CombinedTenants AS (SELECT * FROM CurrentTenants UNION SELECT * FROM HistoricalTenants) SELECT tenantId, GREATEST(date(moveInDate), ?) AS effectiveMoveIn, LEAST(date(moveOutDate), ?) AS effectiveMoveOut, roomId FROM CombinedTenants WHERE date(moveInDate) <=? AND date(moveOutDate) >= ?`;
  //log.info(`${query}`);

  let data: any = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  data.push(...roomIds);
  data.push(clientId);
  data.push(propId);
  data.push(...roomIds);
  data.push(startDate);
  data.push(endDate);
  data.push(CONSTANTS.MOVE_OUT_STATUS.MOVEOUT);
  data.push(startDate);
  data.push(endDate);
  data.push(endDate);
  data.push(startDate);
  //   roomIds,
  //   clientId,
  //   propId,
  //   roomIds,
  //   startDate,
  //   endDate,
  //   CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
  //   startDate,
  //   endDate,
  //   endDate,
  //   startDate,
  // ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

occupancyDB.getTenantsMoveInAndMoveOutDateByFlatId = async ({
  clientId,
  propId,
  flatId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string }) => {
  const query =
    "WITH CurrentTenants AS ( SELECT tenantId,date(moveInDate) as moveInDate,'9999-12-31' AS moveOutDate FROM Occupancies where clientId=? and propId=? and status IN (?,?) and flatId=?),HistoricalTenants AS (SELECT tenantId,date(moveInDate) as moveInDate,date(moveOutDate) as moveOutDate FROM MoveOut WHERE clientId= ?  and propId=? and flatId=? and date(moveOutDate) >= ? AND date(moveInDate) <= ? and status = ?), CombinedTenants AS (SELECT * FROM CurrentTenants UNION SELECT * FROM HistoricalTenants) SELECT tenantId, GREATEST(date(moveInDate), ?) AS effectiveMoveIn, LEAST(date(moveOutDate), ?) AS effectiveMoveOut FROM CombinedTenants WHERE date(moveInDate) <=? AND date(moveOutDate) >= ?";
  // const query =
  //   "WITH CurrentTenants AS ( SELECT tenantId,moveInDate,'9999-12-31' AS moveOutDate FROM Occupancies where clientId=57 and propId=267 and roomId='9201' and status in (3,4)),HistoricalTenants AS (SELECT tenantId,moveInDate,moveOutDate FROM MoveOut WHERE clientId=57 and propId=267 and roomId='9201' and moveOutDate >='2024-11-01' AND moveInDate <= '2024-11-30'), CombinedTenants AS (SELECT * FROM CurrentTenants UNION SELECT * FROM HistoricalTenants) SELECT tenantId, GREATEST(moveInDate, '2024-11-01') AS effectiveMoveIn, LEAST(moveOutDate, '2024-11-30') AS effectiveMoveOut FROM CombinedTenants WHERE moveInDate <= '2024-11-30' AND moveOutDate >= '2024-11-01';";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    flatId,
    clientId,
    propId,
    flatId,
    startDate,
    endDate,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    startDate,
    endDate,
    endDate,
    startDate,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

// to solve tenants who have multiple occupancies
// occupancyDB.getExpectedRentForPropertyOld = async ({
//   clientId,
//   propId,
// }: occupancyTypes) => {
//   const query =
//     // "select SUM(rent) as expectedRent from Occupancies where clientId=? and propId=?";
//     "select SUM(rent) as expectedRent from (select MAX(rent) as rent from Occupancies where clientId=? and propId=? and DATE(moveInDate) <= LAST_DAY(curDate()) group by tenantId) as I;";
//   const data = [clientId, propId];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0]["expectedRent"];
//   else return [];
// };

occupancyDB.getExpectedRentForProperty = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    // "select SUM(rent) as expectedRent from Occupancies where clientId=? and propId=?";
    "select SUM(rent) as expectedRent from (select MAX(rent) as rent from Occupancies where clientId=? and propId=? and DATE(moveInDate) <= LAST_DAY(curDate()) and (stayType = 0 OR (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by tenantId) as I;";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedExtraChargesForProperty = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    `select SUM(E.amount * V.tenantCount) as expectedExtraCharges from ExtraCharges as E join ExtraChargesProperty as ECP on E.id = ECP.extraChargeId join (select O.propId, Count(distinct O.tenantId) as tenantCount from Occupancies as O where O.clientId = ? and propId = ? and DATE(O.moveInDate) <= LAST_DAY(curDate()) and (O.stayType = 0 OR (O.rentalMonths = 0 OR (O.rentalMonths = O.rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by O.propId) as V on ECP.propId = V.propId where E.clientId = ?;`;
  const data = [clientId, propId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedExtraCharges"];
  else return [];
};

occupancyDB.getRentToBeAddedForProperty = async ({
  clientId,
  propId,
}: occupancyTypes & { month: any; year: any }) => {
  const query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    "select IFNULL(SUM(rent), 0) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and propId = ? and DATE(moveInDate) <= LAST_DAY(curDate()) and CAST(rentalCycle as SIGNED) > Day(curdate()) and (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED))) group by tenantId) as I;";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedSecurityForProperty = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    // "select SUM(rent) as expectedRent from Occupancies where clientId=? and propId=?";
    "select SUM(security) as expectedSecurity from (select MAX(security) as security from Occupancies where clientId=? and propId=? and Month(moveInDate) = Month(curdate()) group by tenantId) as I;";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedSecurity"];
  else return [];
};

// to solve tenants who have multiple occupancies
// occupancyDB.getExpectedRentForClientOld = async ({
//   clientId,
//   month,
//   year,
// }: occupancyTypes & { month: any; year: any }) => {
//   const query =
//     // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
//     "select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and DATE(moveInDate) <= LAST_DAY(curDate()) group by tenantId) as I;";
//   const data = [clientId];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0]["expectedRent"];
//   else return [];
// };

occupancyDB.getExpectedRentForClient = async ({
  clientId,
  month,
  year,
}: occupancyTypes & { month: any; year: any }) => {
  const query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    "select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and DATE(moveInDate) <= LAST_DAY(curDate()) and (stayType = 0 OR (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by tenantId) as I;";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedExtraChargesForClient = async ({
  clientId,
}: occupancyTypes & { month: any; year: any }) => {
  const query =
    "select SUM(E.amount * V.tenantCount) as expectedExtraCharges from ExtraCharges as E join ExtraChargesProperty as ECP on E.id = ECP.extraChargeId join (select O.propId, Count(distinct O.tenantId) as tenantCount from Occupancies as O where O.clientId = ? and DATE(O.moveInDate) <= LAST_DAY(curDate()) and (O.stayType = 0 OR (O.rentalMonths = 0 OR (O.rentalMonths = O.rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by O.propId) as V on ECP.propId = V.propId where E.clientId = ?;";
  const data = [clientId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedExtraCharges"];
  else return [];
};

occupancyDB.getRentToBeAddedForClient = async ({
  clientId,
}: occupancyTypes & { month: any; year: any }) => {
  const query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    "select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and DATE(moveInDate) <= LAST_DAY(curDate()) and CAST(rentalCycle as SIGNED) > Day(curdate()) and (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED))) group by tenantId) as I;";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getRentToBeAddedForStaff = async ({
  clientId,
  propertiesIds
}: occupancyTypes & { month: any; year: any; propertiesIds: string }) => {
  const query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    `select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and propId in (${propertiesIds}) and DATE(moveInDate) <= LAST_DAY(curDate()) and CAST(rentalCycle as SIGNED) > Day(curdate()) and (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED))) group by tenantId) as I;`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedSecurityForClient = async ({
  clientId,
  month,
  year,
}: occupancyTypes & { month: any; year: any }) => {
  const query =
    "select SUM(security) as expectedSecurity from (select Max(security) as security from Occupancies where clientId = ? and Month(moveInDate) = Month(curdate()) group by tenantId) as I;";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedSecurity"];
  else return [];
};

occupancyDB.getExpectedSecurityForClientForWeb = async ({
  clientId,
  propIds,
}: occupancyTypes & { propIds: any }) => {
  let query =
    `select SUM(security) as expectedSecurity from (select Max(security) as security from Occupancies where clientId = ? and Month(moveInDate) = Month(curdate())`;
  const data = [clientId];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as I`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedSecurity"];
  else return [];
};

occupancyDB.getExpectedRentForClientForWeb = async ({
  clientId,
  propIds,
}: occupancyTypes & { propIds: any }) => {
  let query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    "select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and DATE(moveInDate) <= LAST_DAY(curDate()) and (stayType = 0 OR (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED))))";
  const data = [clientId];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as I`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedExtraChargesForClientForWeb = async ({
  clientId,
  propIds,
}: occupancyTypes & { propIds: any }) => {
  let query =
    "select SUM(E.amount * V.tenantCount) as expectedExtraCharges from ExtraCharges as E join ExtraChargesProperty as ECP on E.id = ECP.extraChargeId join (select O.propId, Count(distinct O.tenantId) as tenantCount from Occupancies as O where O.clientId = ? and DATE(O.moveInDate) <= LAST_DAY(curDate()) and (O.stayType = 0 OR (O.rentalMonths = 0 OR (O.rentalMonths = O.rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))";
  const data = [clientId, clientId];

  if (propIds && propIds.length > 0) {
    query += ` and O.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` ) group by O.propId) as V on ECP.propId = V.propId where E.clientId = ?`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedExtraCharges"];
  else return [];
};

occupancyDB.getExpectedSecurityForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
}: occupancyTypes & { propIds: any; propertiesIds: string }) => {
  let query =
    `select SUM(security) as expectedSecurity from (select Max(security) as security from Occupancies where clientId = ? and propId in (${propertiesIds}) and Month(moveInDate) = Month(curdate())`;
  const data = [clientId];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as I`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedSecurity"];
  else return [];
};

occupancyDB.getExpectedRentForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
}: occupancyTypes & { propIds: any; propertiesIds: string }) => {
  let query =
    // "select SUM(rent) as expectedRent from (select rent from Occupancies where clientId = ? group by tenantId);";
    `select SUM(rent) as expectedRent from (select Max(rent) as rent from Occupancies where clientId = ? and propId in (${propertiesIds}) and DATE(moveInDate) <= LAST_DAY(curDate()) and (stayType = 0 OR (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED))))`;
  const data = [clientId];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as I`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedExtraChargesForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
}: occupancyTypes & { propIds: any; propertiesIds: string }) => {
  let query =
    `select SUM(E.amount * V.tenantCount) as expectedExtraCharges from ExtraCharges as E join ExtraChargesProperty as ECP on E.id = ECP.extraChargeId join (select O.propId, Count(distinct O.tenantId) as tenantCount from Occupancies as O where O.clientId = ? and O.propId in (${propertiesIds}) and DATE(O.moveInDate) <= LAST_DAY(curDate()) and (O.stayType = 0 OR (O.rentalMonths = 0 OR (O.rentalMonths = O.rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))`;
  const data = [clientId, clientId];

  if (propIds && propIds.length > 0) {
    query += ` and O.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` ) group by O.propId) as V on ECP.propId = V.propId where E.clientId = ?`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedExtraCharges"];
  else return [];
};

// to solve tenants for multiple occupancies
// occupancyDB.getExpectedRentForStaffOld = async ({
//   clientId,
//   propertiesIds,
// }: occupancyTypes & { month: any; year: any; propertiesIds: any }) => {
//   // const query = `select SUM(rent) as expectedRent from Occupancies WHERE clientId = ? and propId in (${propertiesIds});`;
//   const query = `select SUM(rent) as expectedRent from (select MAX(rent) as rent from Occupancies where clientId=? and propId in (${propertiesIds}) and DATE(moveInDate) <= LAST_DAY(curDate()) group by tenantId) as I;`;
//   const data = [clientId];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0]["expectedRent"];
//   else return [];
// };

occupancyDB.getExpectedRentForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { month: any; year: any; propertiesIds: any }) => {
  // const query = `select SUM(rent) as expectedRent from Occupancies WHERE clientId = ? and propId in (${propertiesIds});`;
  const query = `select SUM(rent) as expectedRent from (select MAX(rent) as rent from Occupancies where clientId=? and propId in (${propertiesIds}) and DATE(moveInDate) <= LAST_DAY(curDate()) and (stayType = 0 OR (rentalMonths = 0 OR (rentalMonths = rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by tenantId) as I;`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedExtraChargesForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { month: any; year: any; propertiesIds: any }) => {
  const query = `select SUM(E.amount * V.tenantCount) as expectedExtraCharges from ExtraCharges as E join ExtraChargesProperty as ECP on E.id = ECP.extraChargeId join (select O.propId, Count(distinct O.tenantId) as tenantCount from Occupancies as O where O.clientId = ? and propId in (${propertiesIds}) and DATE(O.moveInDate) <= LAST_DAY(curDate()) and (O.stayType = 0 OR (O.rentalMonths = 0 OR (O.rentalMonths = O.rentalType-1 and Day(curdate()) >= CAST(rentalCycle as SIGNED)))) group by O.propId) as V on ECP.propId = V.propId where E.clientId = ?;`;
  const data = [clientId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedRent"];
  else return [];
};

occupancyDB.getExpectedSecurityForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { month: any; year: any; propertiesIds: any }) => {
  // const query = `select SUM(rent) as expectedRent from Occupancies WHERE clientId = ? and propId in (${propertiesIds});`;
  const query = `select SUM(security) as expectedSecurity from (select MAX(security) as security from Occupancies where clientId=? and propId in (${propertiesIds}) and Month(moveInDate) = Month(curdate()) group by tenantId) as I;`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0]["expectedSecurity"];
  else return [];
};

// occupancyDB.getDailyExpectedRentForClientOld = async ({
//   clientId,
//   month,
//   year,
// }: any) => {
//   const query =
//     "SELECT rentalCycle AS day, SUM(rent) AS amount FROM ( SELECT rentalCycle, rent FROM Occupancies WHERE clientId = ? AND (YEAR(moveInDate) < ? OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ?)) AND status in (3, 4)  UNION ALL SELECT rentalCycle, rent FROM MoveOut WHERE clientId = ? AND (YEAR(moveInDate) < ? AND (YEAR(MoveOutDate) > ? OR (YEAR(MoveOutDate) = ? AND MONTH(MoveOutDate) >= ?)) OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ? AND MONTH(moveOutDate) >= ?)) AND status = 2) AS combined group by rentalCycle;";
//   const data = [
//     clientId,
//     year,
//     year,
//     month,
//     clientId,
//     year,
//     year,
//     year,
//     month,
//     year,
//     month,
//     month,
//   ];
//   const [rows]: [RowDataPacket[], any] = await DB.execute(query, data);

//   if (Array.isArray(rows)) {
//     return rows.map((row: any) => ({
//       date: `${year}-${String(month).padStart(2, "0")}-${String(
//         row.day
//       ).padStart(2, "0")}`,
//       rentExpected: row.amount,
//     }));
//   }
//   return [];
// };

occupancyDB.getDailyExpectedRentForClient = async ({
  clientId,
  month,
  year,
}: any) => {
  const query =
    "SELECT rentalCycle AS day, SUM(rent) AS amount FROM ( SELECT rentalCycle, rent FROM Occupancies WHERE clientId = ? AND (YEAR(moveInDate) < ? OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ?)) AND status in (3, 4) and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED) UNION ALL SELECT rentalCycle, rent FROM MoveOut WHERE clientId = ? AND (YEAR(moveInDate) < ? AND (YEAR(MoveOutDate) > ? OR (YEAR(MoveOutDate) = ? AND MONTH(MoveOutDate) >= ?)) OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ? AND MONTH(moveOutDate) >= ?)) AND status = 2 and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED)) AS combined group by rentalCycle;";
  const data = [
    clientId,
    year,
    year,
    month,
    clientId,
    year,
    year,
    year,
    month,
    year,
    month,
    month,
  ];
  const [rows]: [RowDataPacket[], any] = await DB.execute(query, data);

  if (Array.isArray(rows)) {
    return rows.map((row: any) => ({
      date: `${year}-${String(month).padStart(2, "0")}-${String(
        row.day
      ).padStart(2, "0")}`,
      rentExpected: row.amount,
    }));
  }
  return [];
};

occupancyDB.getDailyExpectedRentForStaff = async ({
  clientId,
  propertiesIds,
  month,
  year,
}: any) => {
  const query =
    `SELECT rentalCycle AS day, SUM(rent) AS amount FROM ( SELECT rentalCycle, rent FROM Occupancies WHERE clientId = ? and propId in (${propertiesIds}) AND (YEAR(moveInDate) < ? OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ?)) AND status in (3, 4) and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED) UNION ALL SELECT rentalCycle, rent FROM MoveOut WHERE clientId = ? and propId in (${propertiesIds}) AND (YEAR(moveInDate) < ? AND (YEAR(MoveOutDate) > ? OR (YEAR(MoveOutDate) = ? AND MONTH(MoveOutDate) >= ?)) OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ? AND MONTH(moveOutDate) >= ?)) AND status = 2 and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED)) AS combined group by rentalCycle;`;
  const data = [
    clientId,
    year,
    year,
    month,
    clientId,
    year,
    year,
    year,
    month,
    year,
    month,
    month,
  ];
  const [rows]: [RowDataPacket[], any] = await DB.execute(query, data);

  if (Array.isArray(rows)) {
    return rows.map((row: any) => ({
      date: `${year}-${String(month).padStart(2, "0")}-${String(
        row.day
      ).padStart(2, "0")}`,
      rentExpected: row.amount,
    }));
  }
  return [];
};

occupancyDB.getDailyExpectedRentForProp = async ({
  propId,
  month,
  year,
}: any) => {
  const query =
    "SELECT rentalCycle AS day, SUM(rent) AS amount FROM ( SELECT rentalCycle, rent FROM Occupancies WHERE propId = ? AND (YEAR(moveInDate) < ? OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ?)) AND status in (3, 4) and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED) UNION ALL SELECT rentalCycle, rent FROM MoveOut WHERE propId = ? AND (YEAR(moveInDate) < ? AND (YEAR(MoveOutDate) > ? OR (YEAR(MoveOutDate) = ? AND MONTH(MoveOutDate) >= ?)) OR (YEAR(moveInDate) = ? AND MONTH(moveInDate) <= ? AND MONTH(moveOutDate) >= ?)) AND status = 2 and rentalMonths = rentalType-1 and Day(curdate()) = CAST(rentalCycle as SIGNED)) AS combined group by rentalCycle;";
  const data = [
    propId,
    year,
    year,
    month,
    propId,
    year,
    year,
    year,
    month,
    year,
    month,
    month,
  ];
  const [rows]: [RowDataPacket[], any] = await DB.execute(query, data);

  if (Array.isArray(rows)) {
    return rows.map((row: any) => ({
      date: `${year}-${String(month).padStart(2, "0")}-${String(
        row.day
      ).padStart(2, "0")}`,
      rentExpected: row.amount,
    }));
  }
  return [];
};

occupancyDB.deleteFullOccupiedExtraEntry = async ({
  tenantId,
  clientId,
}: occupancyTypes) => {
  const query =
    "delete from Occupancies where tenantId = ? and clientId = ? order by id limit 1;";
  const data = [tenantId, clientId];
  const [rows] = await DB.execute<ResultSetHeader[]>(query, data);
  if (rows?.length > 0) return true;
  else return false;
};

occupancyDB.getOccupanciesForFlat = async ({
  clientId,
  tenantId,
  propId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select * from Occupancies where clientId = ? and tenantId = ? and propId = ? and flatId = ?;";
  const data = [clientId, tenantId, propId, flatId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSearchResultByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (Select O.id as occupancyId, 0 as movingOut, O.createdAt, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id as occupancyId, 1 as movingOut, M.createdAt, M.moveInDate, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, M.kycStatus as kycStatus, NULL as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId) as totalDues, NULL as dueDate, NULL as profilePicture from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.flatId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v order by createdAt desc limit ?,? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    clientId,
    flatId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSearchResultCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (Select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ? AND O.status NOT IN (?, ?) AND (T.name Like ? or T.mobile Like ? ) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )  UNION Select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.flatId = ? AND M.status != ? AND (T.name Like ? or T.mobile Like ? ) AND M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId )) as v";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    clientId,
    flatId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnpaidTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v where totalDues IS NOT NULL limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnpaidTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ? AND O.status NOT IN (?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v  where totalDues IS NOT NULL";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getMovingOutTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveOutDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getMovingOutTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.flatId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.flatId = ? AND M.status != ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId ) order by M.createdAt desc) as v ";
  const data = [clientId, flatId, CONSTANTS.MOVE_OUT_STATUS.INITIATED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};
occupancyDB.getByClientIdAndFlatIdOnlineEnabled = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.agreementStartDate, O.agreementPeriod, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndFlatIdOnlineEnabled = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? and O.isOnlinePaymentEnabled = 1 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};
occupancyDB.getByClientIdAndFlatIdOnlineNotEnabled = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.agreementStartDate, O.agreementPeriod, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndFlatIdOnlineNotEnabled = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? and O.isOnlinePaymentEnabled = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRequestedOccupancy = async ({
  roomId,
  status,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query = "select * from Occupancies where roomId = ? and status = ?";
  const data = [roomId, status];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getPlatformResultByClientIdAndPropId = async ({
  clientId,
  propId,
  platform,
  pageNum,
  limit,
}: occupancyTypes & { platform: string; pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppInstalledTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppInstalledTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppNotInstalledTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppNotInstalledTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppInstalledTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppInstalledTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppNotInstalledTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppNotInstalledTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppInstalledTenantsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId in (" + `${propertiesIds}` + ") AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppInstalledTenantsCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {propertiesIds: string;}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId in (" + `${propertiesIds}` + ") AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppNotInstalledTenantsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId in (" + `${propertiesIds}` + ") AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppNotInstalledTenantsCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {propertiesIds: string;}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId in (" + `${propertiesIds}` + ") AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppInstalledTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppInstalledTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND T.device != 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getAppNotInstalledTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getAppNotInstalledTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND T.device = 0 AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByTenantIdForSwitchRoom = async ({
  tenantId,
  clientId,
}: occupancyTypes) => {
  const query =
    "select * from Occupancies where tenantId = ? and clientId = ? and (status = ? || status = ? || status=?) order by id desc";
  const data = [
    tenantId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsWithoutReservedByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.status != ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, // Pallav - Removed T.status and changed O.status to NOT IN (PENDING, REQUESTED, RESERVED)
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsWithoutReservedCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and T.status != ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, // Pallav - Removed T.status and changed O.status to NOT IN (PENDING, REQUESTED, RESERVED)
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, // Pallav - Removed T.status and changed O.status to = RESERVED
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, // Pallav - Removed T.status and changed O.status to = RESERVED
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantSearchByClientId = async ({
  clientId,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and (T.name Like ? or T.mobile Like ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantSearchCountByClientId = async ({
  clientId,
  searchVal,
}: occupancyTypes & { searchVal: string }) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and (T.name Like ? or T.mobile Like ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, // Pallav - Removed T.status and changed O.status to = RESERVED
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getVerifiedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getVerifiedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnverifiedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and T.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? "; // Pallav Added innerO.clientId = O.clientId condition to Handle multi tenant scenario
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnverifiedTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and T.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v "; // Pallav Added innerO.clientId = O.clientId condition to Handle multi tenant scenario
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNewTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNewTenantsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsWithoutReservedForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and O.status != ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //CONSTANTS.TENANT_STATUS.RESERVED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,//Pallav - Removed T.status and changed O.status to NOT IN (PENDING, REQUESTED, RESERVED)
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsWithoutReservedCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and T.status != ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //CONSTANTS.TENANT_STATUS.RESERVED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,//Pallav - Removed T.status and changed O.status to NOT IN (PENDING, REQUESTED, RESERVED)
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, //Pallav - Removed T.status and changed O.status to = RESERVED
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status =? and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, //Pallav - Removed T.status and changed O.status to = RESERVED
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantSearchForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  searchVal
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  searchVal: string;
}) => {
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status = ? and (T.name Like ? or T.mobile Like ? ) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, //Pallav - Removed T.status and changed O.status to = RESERVED
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantSearchCountForStaff = async ({
  clientId,
  propertiesIds,
  searchVal,
}: occupancyTypes & {
  propertiesIds: string;
  searchVal: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status =? and (T.name Like ? or T.mobile Like ? ) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED, //Pallav - Removed T.status and changed O.status to = RESERVED
    `%${searchVal}%`,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getVerifiedTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, T.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and T.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? "; // Pallav - Changed T.kycStatus to O.kycStatus
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getVerifiedTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and T.kycStatus > ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.kycStatus > ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";//Pallav - Changed T.kycStatus to O.kycStatus
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnverifiedTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, T.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and T.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? "; // Pallav - Changed T.kycStatus to O.kycStatus
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnverifiedTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  // const query =
  //   "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
  //   `${propertiesIds}` +
  //   ") and T.kycStatus <= ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and O.kycStatus <= ? and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v "; //Pallav - Changed T.kycStatus to O.kycStatus
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNewTenantsForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNewTenantsCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) and O.propId in (" +
    `${propertiesIds}` +
    ") and date(O.moveInDate) = curdate() and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getPVTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
  isPoliceVerified,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.isPoliceVerified = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isPoliceVerified,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPVTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
  isPoliceVerified,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.isPoliceVerified = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isPoliceVerified,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRATenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
  isRentAgreementSigned,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.isRentAgreementSigned = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isRentAgreementSigned,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRATenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
  isRentAgreementSigned,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.isRentAgreementSigned = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isRentAgreementSigned,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondAvailedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and ET.status = ? and O.rentalBond = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondAvailedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and ET.status = ? and O.rentalBond = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAllowedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.rentalBond <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAllowedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.rentalBond <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAvailedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and (ET.status != NULL OR ET.status != ?) and O.rentalBond = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAvailedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and (ET.status != NULL OR ET.status = ?) and O.rentalBond = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsWithoutReservedByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsWithoutReservedCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getVerifiedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getVerifiedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnverifiedTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnverifiedTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNewTenantsByClientIdAndFlatId = async ({
  clientId,
  flatId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNewTenantsCountByClientIdAndFlatId = async ({
  clientId,
  flatId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.flatId = ?  AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getReservedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const query =
    "select * from (select O.id as occupancyId, O.security, O.bookingAmt, O.rentalCycle, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  and O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,//Sukhbir - MultiOccupancy
    //CONSTANTS.OCCUPANCY_STATUS.PENDING,
    //CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    //CONSTANTS.TENANT_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    // CONSTANTS.OCCUPANCY_STATUS.PENDING,
    // CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    // CONSTANTS.TENANT_STATUS.RESERVED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,//Pallav 
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

//Function Not getting used anywhere - Pallav
occupancyDB.getTenantsWithoutReservedByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

//Function Not getting used anywhere - Pallav
occupancyDB.getTenantsWithoutReservedCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getVerifiedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and T.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";

  //Pallav Changed T.kycStatus to O.kycStatus
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getVerifiedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  //Pallav Changed T.kycStatus to O.kycStatus
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and O.kycStatus > ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getUnverifiedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  //Pallav Changed T.kycStatus to O.kycStatus
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getUnverifiedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  //Pallav Changed T.kycStatus to O.kycStatus
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and O.kycStatus <= ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.KYC_STATUS.PERSONAL_INFO,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNewTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNewTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?) and date(O.moveInDate) = curdate() and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.switchPropertyPg = async ({
  id,
  roomId,
  bedId,
  floor,
  propId,
  rent,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set roomId = ?, bedId = ?, floor = ?, rent = ?, propId = ? where id = ?";
  const data = [roomId, bedId, floor, rent, propId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.switchPropertyFlat = async ({
  id,
  roomId,
  flatId,
  bedId,
  floor,
  propId,
  rent,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set roomId = ?, bedId = ?, floor = ?, rent = ?, flatId = ?, propId = ? where id = ?";
  const data = [roomId, bedId, floor, rent, flatId, propId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getByPropIdForWeb = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementPeriod, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc";
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};
occupancyDB.getByPropIdForWebSortByRoomFlat = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId join Flats as F on F.id = O.flatId WHERE O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by REGEXP_SUBSTR(F.name, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(F.name, '[0-9]+') AS UNSIGNED), R.id";
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};
occupancyDB.getByPropIdForWebSortByRoomPg = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.propId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by ISNULL(REGEXP_SUBSTR(O.floor, '^[A-Za-z]+')), REGEXP_SUBSTR(O.floor, '^[A-Za-z]+'), CAST(REGEXP_SUBSTR(O.floor, '[0-9]+') AS UNSIGNED), R.id";
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.updateTenantRentDetails = async ({
  tenantId,
  clientId,
  rent,
  security,
  moveInDate,
  rentalCycle,
  agreementPeriod,
  lockInPeriod,
  noticePeriod,
  moveOutDate,
  isOnlinePaymentEnabled,
  agreementStartDate
}: occupancyTypes) => {
  let query = ``;
  let data = [];
  if (!agreementStartDate) {
    query =
      "update Occupancies set rent = ?, security = ?, moveInDate = ?, rentalCycle = ?, agreementPeriod = ?, lockInPeriod = ?, noticePeriod = ?, moveOutDate = ?, isOnlinePaymentEnabled = ? where tenantId = ? and clientId = ?";
    data = [
      rent,
      security,
      moveInDate,
      rentalCycle,
      agreementPeriod,
      lockInPeriod,
      noticePeriod,
      moveOutDate,
      isOnlinePaymentEnabled,
      tenantId,
      clientId,
    ];
  } else {
    query =
      "update Occupancies set rent = ?, security = ?, moveInDate = ?, rentalCycle = ?, agreementPeriod = ?, lockInPeriod = ?, noticePeriod = ?, moveOutDate = ?, isOnlinePaymentEnabled = ?, agreementStartDate = ? where tenantId = ? and clientId = ?";
    data = [
      rent,
      security,
      moveInDate,
      rentalCycle,
      agreementPeriod,
      lockInPeriod,
      noticePeriod,
      moveOutDate,
      isOnlinePaymentEnabled,
      agreementStartDate,
      tenantId,
      clientId,
    ];
  }
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

// occupancyDB.getBySearchValAndClientId = async ({
//   clientId,
//   searchVal,
// }: occupancyTypes & { searchVal: any }) => {
//   // const query =
//   //   `select "occupied" as type, T.name, T.id, O.propId, O.roomId, O.status from Occupancies as O inner join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? or T.mobile like ?) and O.status NOT IN (?, ?) and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) UNION select "moveOut" as type, MT.name, MT.id, MO.propId, MO.roomId, MT.status from MoveOut as MO inner join Tenants as MT on MT.id = MO.tenantId where MO.clientId = ? and MO.tenantId NOT IN (SELECT innerO1.tenantId FROM Occupancies as innerO1 WHERE innerO1.tenantId = MO.tenantId and innerO1.clientId=MO.clientId)  and (MT.name like ? or MT.mobile like ?) and MO.status = ? and MO.id IN (SELECT MAX(innerMO.id) FROM MoveOut as innerMO WHERE innerMO.tenantId = MO.tenantId and innerMO.clientId = MO.clientId GROUP BY innerMO.tenantId )`;
//   const query =
//     `select "occupied" as type, T.name, T.id, O.propId, O.kycStatus, O.roomId, O.status, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = 4 and moveOut=0 limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId where O.clientId = ? and (T.name like ? or T.mobile like ?) and O.status NOT IN (?, ?) and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) UNION select "moveOut" as type, MT.name, MT.id, MO.propId, MO.kycStatus, MO.roomId, MT.status, (select value from Documents where tenantId = MO.tenantId and clientId = MO.clientId and type = 4 and moveOut=1 limit 1) as profilePicture from MoveOut as MO inner join Tenants as MT on MT.id = MO.tenantId where MO.clientId = ? and (MT.name like ? or MT.mobile like ?) and MO.status = ? and MO.id IN (SELECT MAX(innerMO.id) FROM MoveOut as innerMO WHERE innerMO.tenantId = MO.tenantId and innerMO.clientId = MO.clientId and innerMO.status=? GROUP BY innerMO.tenantId )`;
//   const data = [
//     clientId,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//     CONSTANTS.OCCUPANCY_STATUS.PENDING,
//     CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
//     clientId,
//     `%${searchVal}%`,
//     `%${searchVal}%`,
//     CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
//     CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
//   ];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows;
//   else return false;
// };

occupancyDB.getBySearchValAndClientId = async ({
  clientId,
  searchVal,
}: occupancyTypes & { searchVal: any }) => {
  const query =
    `select "occupied" as type, T.name, T.id, O.propId, O.kycStatus, O.roomId, O.status, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = 4 and moveOut=0 limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Rooms as R ON R.id= O.roomId where O.clientId = ? and (T.name like ? or T.mobile like ? or R.roomNum = ?) and O.status NOT IN (?, ?) and O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) UNION select "moveOut" as type, MT.name, MT.id, MO.propId, MO.kycStatus, MO.roomId, MT.status, (select value from Documents where tenantId = MO.tenantId and clientId = MO.clientId and type = 4 and moveOut=1 limit 1) as profilePicture from MoveOut as MO inner join Tenants as MT on MT.id = MO.tenantId left join Rooms as MOR ON MOR.id= MO.roomId where MO.clientId = ? and (MT.name like ? or MT.mobile like ? or MOR.roomNum = ?) and MO.status = ? and MO.id IN (SELECT MAX(innerMO.id) FROM MoveOut as innerMO WHERE innerMO.tenantId = MO.tenantId and innerMO.clientId = MO.clientId and innerMO.status=? GROUP BY innerMO.tenantId )`;
  const data = [
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${searchVal}`,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${searchVal}`,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getActiveAndMovingOutByPropId = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select (select count(Distinct(tenantId)) from Occupancies where propId = ? and status = ?) as active, (select count(Distinct(tenantId)) from Occupancies where propId = ? and status = ?) as movingOut";
  const data = [
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsForExpiringAgreements = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE())) OR DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() OR (YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 MONTH))))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and (DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)<= LAST_DAY(DATE_ADD(curdate(), INTERVAL 1 MONTH)))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForExpiringAgreementsCount = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.propId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE())) OR (DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE()) OR (YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 MONTH))))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsForExpiringAgreementsByClientId = async ({
  clientId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE())) OR DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE() OR (YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) <= MONTH(DATE_ADD(CURDATE(), INTERVAL 3 MONTH))))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and (DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)<= LAST_DAY(DATE_ADD(curdate(), INTERVAL 1 MONTH)))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForExpiringAgreementsCountByClientId = async ({
  clientId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE())) OR (DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH) < CURDATE()) OR (YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 MONTH))))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsForExpiringAgreementsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (${propertiesIds}) and (DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)<= LAST_DAY(DATE_ADD(curdate(), INTERVAL 1 MONTH)))  AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc`;

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreements = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreementsCount = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.propId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(CURDATE()) and DATE(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.id Desc";
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.propId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH( DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))=month(curdate()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreementsByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreementsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  // const query =
  //   "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(CURDATE()) and DATE(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.id Desc";
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH( DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))=month(curdate()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc;";

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreementsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string; }) => {
  const query =
    `select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (${propertiesIds}) and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = MONTH(CURDATE()) and DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc`;

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForCurMonthExpiringAgreementsCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  // const query =
  //   "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(CURDATE()) and DATE(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) >= DATE(CURDATE()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId ) order by O.id Desc";
  const query =
    `select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and O.propId in (${propertiesIds}) and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH( DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))=month(curdate()))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc;`;

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsWithNextMonthExpiringAgreements = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and ((YEAR(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod - 1 MONTH))) = YEAR(CURDATE()) and MONTH(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForNextMonthExpiringAgreementsCount = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  // "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.propId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId))";
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.propId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 DAY)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId))";

  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsWithNextMonthExpiringAgreementsByClientId = async ({
  clientId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForNextMonthExpiringAgreementsCountClientId = async ({
  clientId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  // const query =
  //   "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId))";
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH( DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))=month(DATE_ADD(curdate(), INTERVAL 1 MONTH)))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsWithNextMonthExpiringAgreementsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (${propertiesIds}) and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId)) order by DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) asc, T.id Desc`;

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsForNextMonthExpiringAgreementsCountClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  // const query =
  //   "select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and ((YEAR(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) = YEAR(CURDATE()) and MONTH(DATE_SUB(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH), INTERVAL 1 MONTH)) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 MONTH))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId GROUP BY innerO.tenantId))";
  const query =
    `select Count(Distinct(O.tenantId)) as count from Occupancies as O where O.clientId = ? and propId in (${propertiesIds}) and ((YEAR(LAST_DAY(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))) = YEAR(CURDATE()) and MONTH( DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH))=month(DATE_ADD(curdate(), INTERVAL 1 MONTH)))) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc`;

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsExpiredAgreements = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsExpiredAgreementsCount = async ({
  propId,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.propId = ? and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsExpiredAgreementsByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc";

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsExpiredAgreementsCountByClientId = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select Count(Distinct(O.tenantId)) as count from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc";

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTenantsExpiredAgreementsByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select O.id, O.clientId, O.electricityReading, O.tenantId, O.propId, O.roomId, O.bedId, O.floor, O.flatId, O.rent, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.security, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, P.name as propName, P.type as propType, R.roomNum, T.name as tenantName, T.kycStatus as tenantKycStatus, O.kycStatus, T.mobile as tenantMobile, (select SUM(balance) from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture, DATE(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) as agreementExpiry from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (${propertiesIds}) and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)), T.id Desc`;

  const data = [CONSTANTS.DOCUMENT_TYPES.SELFI, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsExpiredAgreementsCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select Count(Distinct(O.tenantId)) as count from Occupancies as O left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId left join Tenants as T on T.id = O.tenantId where O.clientId = ? and O.propId in (${propertiesIds}) and Date(DATE_ADD(O.agreementStartDate, INTERVAL O.agreementPeriod MONTH)) < Date(curdate()) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.id Desc`;

  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.updateRentalMonths = async ({
  tenantId,
  clientId,
  rentalMonths,
}: occupancyTypes) => {
  const query =
    "update Occupancies set rentalMonths = rentalMonths + ? where tenantId = ? and clientId = ?";
  const data = [rentalMonths, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateOnlinePaymentStatus = async ({
  tenantId,
  clientId,
  isOnlinePaymentEnabled,
}: occupancyTypes) => {
  const query =
    "update Occupancies set isOnlinePaymentEnabled = ? where tenantId = ? and clientId = ?";
  const data = [isOnlinePaymentEnabled, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateGstStatus = async ({
  tenantId,
  clientId,
  isGstEnabled,
}: occupancyTypes) => {
  const query =
    "update Occupancies set isGstEnabled = ? where tenantId = ? and clientId = ?";
  const data = [isGstEnabled, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getMovingInCurrentMonthCount = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and Month(moveInDate) = Month(curdate()) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInImpactCountByMonthYear = async ({
  clientId,
  month,
  year,
}: occupancyTypes & { month: string; year: string }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and Month(moveInDate) = ? and Year(moveInDate) = ? group by tenantId) as v";
  const data = [clientId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInImpactCountByMonthYearForWeb = async ({
  clientId,
  month,
  year,
  propIds,
}: occupancyTypes & { month: string; year: string; propIds: any }) => {
  let query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and Month(moveInDate) = ? and Year(moveInDate) = ? ";
  const data = [clientId, month, year];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as v`

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextMonthCount = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and Month(moveInDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextToNextMonthCount = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and Month(moveInDate) = Month(Date_Add(curdate(), Interval 2 Month)) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutCurrentMonthCount = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and Month(moveOutDate) = Month(curdate()) and Year(moveOutDate) = Year(curdate()) group by tenantId) as v";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutImpactCountByMonthYear = async ({
  clientId,
  month,
  year,
}: occupancyTypes & { month: string; year: string; }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and Month(moveOutDate) = ? and Year(moveOutDate) = ? group by tenantId) as v";
  const data = [clientId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutImpactCountByMonthYearForWeb = async ({
  clientId,
  propIds,
  month,
  year,
}: occupancyTypes & { month: string; year: string; propIds: any }) => {
  let query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and Month(moveOutDate) = ? and Year(moveOutDate) = ? ";
  const data = [clientId, month, year];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as v`

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutNextMonthCount = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and Month(moveOutDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(moveOutDate) = Year(curdate()) group by tenantId) as v";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInCurrentMonthCountForStaff = async ({
  clientId,
  staffId,
}: occupancyTypes & { staffId: number }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select O.tenantId, min(O.rent) as rent from Occupancies as O join PropertyStaff as PS on O.propId = PS.propId where O.clientId = ? and O.propId in (select propId from PropertyStaff where staffId = ?) and Month(O.moveInDate) = Month(curdate()) and Year(O.moveInDate) = Year(curdate()) group by O.tenantId) as v";
  const data = [clientId, staffId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInImpactCountByMonthYearStaff = async ({
  clientId,
  propertiesIds,
  month,
  year,
}: occupancyTypes & { month: string; year: string; propertiesIds: string; }) => {
  const query =
    `select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and propId in (${propertiesIds}) and Month(moveInDate) = ? and Year(moveInDate) = ? group by tenantId) as v`;
  const data = [clientId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInImpactCountByMonthYearForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
  month,
  year,
}: occupancyTypes & { month: string; year: string; propertiesIds: string; propIds: any }) => {
  let query =
    `select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where clientId = ? and propId in (${propertiesIds}) and Month(moveInDate) = ? and Year(moveInDate) = ? `;
  const data = [clientId, month, year];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as v`;

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextMonthCountForStaff = async ({
  clientId,
  staffId,
}: occupancyTypes & { staffId: number }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select O.tenantId, min(O.rent) as rent from Occupancies as O join PropertyStaff as PS on O.propId = PS.propId where O.clientId = ? and O.propId in (select propId from PropertyStaff where staffId = ?) and Month(O.moveInDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(O.moveInDate) = Year(curdate()) group by O.tenantId) as v";
  const data = [clientId, staffId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextToNextMonthCountForStaff = async ({
  clientId,
  staffId,
}: occupancyTypes & { staffId: number }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select O.tenantId, min(O.rent) as rent from Occupancies as O join PropertyStaff as PS on O.propId = PS.propId where O.clientId = ? and O.propId in (select propId from PropertyStaff where staffId = ?) and Month(O.moveInDate) = Month(Date_Add(curdate(), Interval 2 Month)) and Year(O.moveInDate) = Year(curdate()) group by O.tenantId) as v";
  const data = [clientId, staffId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutCurrentMonthCountForStaff = async ({
  clientId,
  staffId,
}: occupancyTypes & { staffId: number }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select MO.tenantId, min(MO.rent) as rent from MoveOut as MO join PropertyStaff as PS on MO.propId = PS.propId where MO.clientId = ? and MO.propId in (select propId from PropertyStaff where staffId = ?) and Month(MO.moveOutDate) = Month(curdate()) and Year(MO.moveOutDate) = Year(curdate()) group by MO.tenantId) as v";
  const data = [clientId, staffId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutImpactCountByMonthYearStaff = async ({
  clientId,
  propertiesIds,
  month,
  year,
}: occupancyTypes & { month: string; year: string; propertiesIds: string }) => {
  const query =
    `select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and propId in (${propertiesIds}) and Month(moveOutDate) = ? and Year(moveOutDate) = ? group by tenantId) as v`;
  const data = [clientId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutImpactCountByMonthYearForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
  month,
  year,
}: occupancyTypes & { month: string; year: string; propertiesIds: string; propIds: any }) => {
  let query =
    `select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where clientId = ? and propId in (${propertiesIds}) and Month(moveOutDate) = ? and Year(moveOutDate) = ? `;
  const data = [clientId, month, year];

  if (propIds && propIds.length > 0) {
    query += ` and propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  query += ` group by tenantId) as v`

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutNextMonthCountForStaff = async ({
  clientId,
  staffId,
}: occupancyTypes & { staffId: number }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select MO.tenantId, min(MO.rent) as rent from MoveOut as MO join PropertyStaff as PS on MO.propId = PS.propId where MO.clientId = ? and MO.propId in (select propId from PropertyStaff where staffId = ?) and Month(MO.moveOutDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(MO.moveOutDate) = Year(curdate()) group by MO.tenantId) as v";
  const data = [clientId, staffId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInCurrentMonthCountProp = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where propId = ? and Month(moveInDate) = Month(curdate()) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInImpactCountByMonthYearProp = async ({
  propId,
  month,
  year,
}: occupancyTypes & { month: string; year: string }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where propId = ? and Month(moveInDate) = ? and Year(moveInDate) = ? group by tenantId) as v";
  const data = [propId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextMonthCountProp = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where propId = ? and Month(moveInDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingInNextToNextMonthCountProp = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from Occupancies where propId = ? and Month(moveInDate) = Month(Date_Add(curdate(), Interval 2 Month)) and Year(moveInDate) = Year(curdate()) group by tenantId) as v";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutCurrentMonthCountProp = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where propId = ? and Month(moveOutDate) = Month(curdate()) and Year(moveOutDate) = Year(curdate()) group by tenantId) as v";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutImpactCountByMonthYearProp = async ({
  propId,
  month,
  year,
}: occupancyTypes & { month: string; year: string; }) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where propId = ? and Month(moveOutDate) = ? and Year(moveOutDate) = ? group by tenantId) as v";
  const data = [propId, month, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getMovingOutNextMonthCountProp = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select count(distinct(tenantId)) as count, IFNULL(sum(rent), 0) as totalRent from (select tenantId, min(rent) as rent from MoveOut where propId = ? and Month(moveOutDate) = Month(Date_Add(curdate(), Interval 1 Month)) and Year(moveOutDate) = Year(curdate()) group by tenantId) as v";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.updateInitialSettlementNotes = async ({
  clientId,
  tenantId,
  notes,
}: occupancyTypes) => {
  const query =
    "update Occupancies set notes = ? where clientId = ? and tenantId = ?";
  const data = [notes, clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByPropIdandDateRange = async ({
  propId,
  startDate,
  endDate,
}: { propId: any; startDate: string; endDate: string }) => {
  const query = `select * from (SELECT ANY_VALUE(O.propId) AS propId, ANY_VALUE(T.gender) AS gender, ANY_VALUE(T.alternateMobile) as alternateMobile, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(O.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.courseEndMonth) AS courseEndMonth, ANY_VALUE(T.courseEndYear) AS courseEndYear, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(O.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(O.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(O.rent) AS rent, ANY_VALUE(O.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(O.rentalCycle) AS rentalCycle, ANY_VALUE(O.notes) AS notes, ANY_VALUE(O.status) AS occupancyStatus, ANY_VALUE(O.moveOutDate) AS moveOutDate, ANY_VALUE(O.lockInPeriod) AS lockInPeriod, ANY_VALUE(O.noticePeriod) AS noticePeriod, ANY_VALUE(O.flatId) as flatId, ANY_VALUE(O.floor) as floor FROM Occupancies AS O JOIN Tenants AS T ON T.id = O.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = O.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id WHERE O.propId in (${propId.map(() => '?').join(',')}) AND DATE(O.moveInDate) <= ? AND (DATE(O.moveOutDate) >= ? OR O.moveOutDate IS NULL) GROUP BY O.tenantId UNION SELECT ANY_VALUE(MO.propId) AS propId, ANY_VALUE(T.gender) AS gender,  ANY_VALUE(T.alternateMobile) as alternateMobile, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(MO.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.courseEndMonth) AS courseEndMonth, ANY_VALUE(T.courseEndYear) AS courseEndYear, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(MO.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(MO.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(MO.rent) AS rent, ANY_VALUE(MO.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(MO.rentalCycle) AS rentalCycle, ANY_VALUE(MO.notes) AS notes, ANY_VALUE(MO.status) AS occupancyStatus, ANY_VALUE(MO.moveOutDate) AS moveOutDate, ANY_VALUE(MO.lockInPeriod) AS lockInPeriod, ANY_VALUE(MO.noticePeriod) AS noticePeriod, ANY_VALUE(MO.flatId) as flatId, ANY_VALUE(MO.floor) as floor FROM MoveOut AS MO JOIN Tenants AS T ON T.id = MO.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = MO.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id WHERE MO.status = ? AND MO.propId in (${propId.map(() => '?').join(',')}) AND DATE(MO.moveInDate) <= ? AND DATE(MO.moveOutDate) >= ? GROUP BY MO.tenantId) as V order by V.propId, V.roomNum`;
  const data = [...propId, endDate, startDate, CONSTANTS.MOVE_OUT_STATUS.MOVEOUT, ...propId, endDate, startDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdandDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string }) => {
  // const query =
  //   "select ANY_VALUE(O.propId) as propId, ANY_VALUE(T.gender) as gender, ANY_VALUE(T.email) as email, ANY_VALUE(T.dob) as dob, ANY_VALUE(T.aadharNumber) as aadhaarNumber, ANY_VALUE(T.bloodGroup) as bloodGroup, ANY_VALUE(T.occupation) as occupation, ANY_VALUE(O.kycStatus) as kycStatus, ANY_VALUE(TG.fatherName) as fatherName, ANY_VALUE(TG.fatherMobile) as fatherMobile, ANY_VALUE(TG.fatherOccupation) as fatherOccupation, ANY_VALUE(TG.fatherAnnualIncome) as fatherAnnualIncome, ANY_VALUE(TG.motherName) as motherName, ANY_VALUE(TG.motherMobile) as motherMobile, ANY_VALUE(TG.localGuardianName) as localGuardianName, ANY_VALUE(TG.localGuardianMobile) as localGuardianMobile, ANY_VALUE(TG.localGuardianRelation) as localGuardianRelation, ANY_VALUE(T.institutionName) as institutionName, ANY_VALUE(T.institutionEmail) as institutionEmail, ANY_VALUE(T.title) as title, ANY_VALUE(T.address) as address, COUNT(O.tenantId) as occupiedBeds, ANY_VALUE(DATE_FORMAT(O.moveInDate, '%Y-%m-%d')) as moveInDate, ANY_VALUE(O.rent) as rent, ANY_VALUE(O.security) as security, ANY_VALUE(T.name) name, ANY_VALUE(T.mobile) as mobile, ANY_VALUE(R.roomNum) as roomNum, ANY_VALUE(T.id) as id, ANY_VALUE(RO.name) as roomOptionName, ANY_VALUE(O.rentalCycle) as rentalCycle, ANY_VALUE(O.notes) as notes, ANY_VALUE(O.status) as occupancyStatus, ANY_VALUE(O.moveOutDate) as moveOutDate, ANY_VALUE(O.lockInPeriod) as lockInPeriod, ANY_VALUE(O.noticePeriod) as noticePeriod from Occupancies as O join Tenants as T on T.id = O.tenantId join TenantGuardians as TG on T.id = TG.tenantId join Rooms as R on R.id = O.roomId join RoomOptions as RO on R.roomOptionId = RO.id left join Properties as P on O.propId = P.id where O.clientId = ? and P.status = ? and Date(O.moveInDate) <= ? and (Date(O.moveOutDate) > ?  OR O.moveOutDate is null) GROUP BY O.tenantId UNION select ANY_VALUE(MO.propId) as propId, ANY_VALUE(T.gender) as gender, ANY_VALUE(T.email) as email, ANY_VALUE(T.dob) as dob, ANY_VALUE(T.aadharNumber) as aadhaarNumber, ANY_VALUE(T.bloodGroup) as bloodGroup, ANY_VALUE(T.occupation) as occupation, ANY_VALUE(MO.kycStatus) as kycStatus, ANY_VALUE(TG.fatherName) as fatherName, ANY_VALUE(TG.fatherMobile) as fatherMobile, ANY_VALUE(TG.fatherOccupation) as fatherOccupation, ANY_VALUE(TG.fatherAnnualIncome) as fatherAnnualIncome, ANY_VALUE(TG.motherName) as motherName, ANY_VALUE(TG.motherMobile) as motherMobile, ANY_VALUE(TG.localGuardianName) as localGuardianName, ANY_VALUE(TG.localGuardianMobile) as localGuardianMobile, ANY_VALUE(TG.localGuardianRelation) as localGuardianRelation, ANY_VALUE(T.institutionName) as institutionName, ANY_VALUE(T.institutionEmail) as institutionEmail, ANY_VALUE(T.title) as title, ANY_VALUE(T.address) as address, COUNT(MO.tenantId) as occupiedBeds, ANY_VALUE(DATE_FORMAT(MO.moveInDate, '%Y-%m-%d')) as moveInDate, ANY_VALUE(MO.rent) as rent, ANY_VALUE(MO.security) as security, ANY_VALUE(T.name) name, ANY_VALUE(T.mobile) as mobile, ANY_VALUE(R.roomNum) as roomNum, ANY_VALUE(T.id) as id, ANY_VALUE(RO.name) as roomOptionName, ANY_VALUE(MO.rentalCycle) as rentalCycle, ANY_VALUE(MO.notes) as notes, ANY_VALUE(MO.status) as occupancyStatus, ANY_VALUE(MO.moveOutDate) as moveOutDate, ANY_VALUE(MO.lockInPeriod) as lockInPeriod, ANY_VALUE(MO.noticePeriod) as noticePeriod from MoveOut as MO join Tenants as T on T.id = MO.tenantId join TenantGuardians as TG on T.id = TG.tenantId join Rooms as R on R.id = MO.roomId join RoomOptions as RO on R.roomOptionId = RO.id left join Properties as P on MO.propId = P.id where MO.status=? and  MO.clientId = ? and P.status = ? and Date(MO.moveInDate) <= ? and Date(MO.moveOutDate) > ? GROUP BY MO.tenantId";
  const query = "select * from (SELECT ANY_VALUE(O.propId) AS propId, ANY_VALUE(T.gender) AS gender,  ANY_VALUE(T.alternateMobile) as alternateMobile, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(O.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.courseEndMonth) AS courseEndMonth, ANY_VALUE(T.courseEndYear) AS courseEndYear, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(O.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(O.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(O.rent) AS rent, ANY_VALUE(O.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(O.rentalCycle) AS rentalCycle, ANY_VALUE(O.notes) AS notes, ANY_VALUE(O.status) AS occupancyStatus, ANY_VALUE(O.moveOutDate) AS moveOutDate, ANY_VALUE(O.lockInPeriod) AS lockInPeriod, ANY_VALUE(O.noticePeriod) AS noticePeriod, ANY_VALUE(O.flatId) as flatId, ANY_VALUE(O.floor) as floor FROM Occupancies AS O JOIN Tenants AS T ON T.id = O.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = O.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id LEFT JOIN Properties AS P ON O.propId = P.id WHERE O.clientId = ? AND P.status = ? AND DATE(O.moveInDate) <= ? AND (DATE(O.moveOutDate) > ? OR O.moveOutDate IS NULL) GROUP BY O.tenantId UNION SELECT ANY_VALUE(MO.propId) AS propId, ANY_VALUE(T.gender) AS gender,  ANY_VALUE(T.alternateMobile) as alternateMobile, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(MO.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.courseEndMonth) AS courseEndMonth, ANY_VALUE(T.courseEndYear) AS courseEndYear, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(MO.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(MO.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(MO.rent) AS rent, ANY_VALUE(MO.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(MO.rentalCycle) AS rentalCycle, ANY_VALUE(MO.notes) AS notes, ANY_VALUE(MO.status) AS occupancyStatus, ANY_VALUE(MO.moveOutDate) AS moveOutDate, ANY_VALUE(MO.lockInPeriod) AS lockInPeriod, ANY_VALUE(MO.noticePeriod) AS noticePeriod, ANY_VALUE(MO.flatId) as flatId, ANY_VALUE(MO.floor) as floor FROM MoveOut AS MO JOIN Tenants AS T ON T.id = MO.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = MO.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id LEFT JOIN Properties AS P ON MO.propId = P.id WHERE MO.status = ? AND MO.clientId = ? AND P.status = ? AND DATE(MO.moveInDate) <= ? AND DATE(MO.moveOutDate) > ? GROUP BY MO.tenantId) as V order by V.propId, V.roomNum";
  const data = [
    clientId,
    CONSTANTS.PROPERTY_STATUS.ACTIVE,
    endDate,
    startDate,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    clientId,
    CONSTANTS.PROPERTY_STATUS.ACTIVE,
    endDate,
    startDate
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByPropIdandDateRangeWithoutMovedOut = async ({
  propId,
  startDate,
  endDate,
}: { propId: any; startDate: string; endDate: string }) => {
  const query =
    `select O.propId, DATE_FORMAT(O.moveInDate, '%Y-%m-%d') as moveInDate, O.rent, O.security, T.name, T.mobile, R.roomNum, R.id as roomId, T.id, RO.name as roomOptionName, O.rentalCycle, O.notes, O.rentalBond, O.kycStatus, O.isRentAgreementSigned, O.status as occupancyStatus, O.moveOutDate from Occupancies as O join Tenants as T on T.id = O.tenantId join Rooms as R on R.id = O.roomId join RoomOptions as RO on R.roomOptionId = RO.id where O.propId in (${propId.map(() => '?').join(',')}) and Date(O.moveInDate) <= ? and (Date(O.moveOutDate) >= ? OR O.moveOutDate is null)`;
  const data = [...propId, endDate, startDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdandDateRangeWithoutMovedOut = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string; endDate: string }) => {
  const query =
    "select O.propId, DATE_FORMAT(O.moveInDate, '%Y-%m-%d') as moveInDate, O.rent, O.security, T.name, T.mobile, R.roomNum, R.id as roomId, T.id, RO.name as roomOptionName, O.rentalCycle, O.notes, O.rentalBond, O.kycStatus, O.isRentAgreementSigned, O.status as occupancyStatus, O.moveOutDate, O.rentalType, O.stayType from Occupancies as O join Tenants as T on T.id = O.tenantId join Rooms as R on R.id = O.roomId join RoomOptions as RO on R.roomOptionId = RO.id left join Properties as P on O.propId = P.id where O.clientId = ? and P.status = ? and Date(O.moveInDate) <= ? and (Date(O.moveOutDate) > ?  OR O.moveOutDate is null)";
  const data = [clientId, CONSTANTS.PROPERTY_STATUS.ACTIVE, endDate, startDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};


occupancyDB.getByPropIdWithoutMovedOut = async ({
  propId,
}: { propId: any }) => {
  const query =
    `select O.propId, DATE_FORMAT(O.moveInDate, '%Y-%m-%d') as moveInDate, O.rent, O.security, T.name, T.mobile, R.roomNum, R.id as roomId, T.id, RO.name as roomOptionName, O.rentalCycle, O.notes, O.rentalBond, O.kycStatus, O.isRentAgreementSigned, O.status as occupancyStatus, O.moveOutDate, O.createdAt, O.rentalType, O.stayType from Occupancies as O join Tenants as T on T.id = O.tenantId join Rooms as R on R.id = O.roomId join RoomOptions as RO on R.roomOptionId = RO.id where O.propId in (${propId.map(() => '?').join(',')})`;
  const data = [...propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdWithoutMovedOut = async ({
  clientId
}: occupancyTypes) => {
  const query =
    "select O.propId, DATE_FORMAT(O.moveInDate, '%Y-%m-%d') as moveInDate, O.rent, O.security, T.name, T.mobile, R.roomNum, R.id as roomId, T.id, RO.name as roomOptionName, O.rentalCycle, O.notes, O.rentalBond, O.kycStatus, O.isRentAgreementSigned, O.status as occupancyStatus, O.moveOutDate, O.createdAt from Occupancies as O join Tenants as T on T.id = O.tenantId join Rooms as R on R.id = O.roomId join RoomOptions as RO on R.roomOptionId = RO.id left join Properties as P on O.propId = P.id where O.clientId = ? and O.stayType !=2 and P.status = ?";
  const data = [clientId, CONSTANTS.PROPERTY_STATUS.ACTIVE];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndTenantId = async ({
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query = "select * from Occupancies where clientId = ? and tenantId = ?";
  const data = [clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdAndTenantIdAndPartner = async ({
  clientId,
  tenantId,
}: occupancyTypes) => {
  const query = "select * from Occupancies where clientId in (select id from Clients where id = ? or parentId = ?) and tenantId = ?";
  const data = [clientId, clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.deletePendingByBedId = async ({ bedId }: occupancyTypes) => {
  const query = "delete from Occupancies where bedId = ? and status = ?";
  const data = [bedId, CONSTANTS.OCCUPANCY_STATUS.PENDING];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getTotalSecurityInHand = async ({
  clientId,
}: occupancyTypes) => {
  const query =
    "Select sum(CASE WHEN L.type = ? THEN abs(L.amount) WHEN L.subType = ? THEN L.amount ELSE 0 END) as amount from Ledgers as L where L.clientId = ? and L.amount < 0 and (L.type = ? OR L.subType = ?) and L.tenantId in (select innerO.tenantId from Occupancies as innerO where innerO.clientId = ? and innerO.status in (?, ?) group by innerO.tenantId)";
  const data = [
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].amount;
  else return 0;
};

occupancyDB.getTotalSecurityInHandForWeb = async ({
  clientId,
  propIds,
}: occupancyTypes & { propIds: any }) => {
  let query =
    "Select sum(CASE WHEN L.type = ? THEN abs(L.amount) WHEN L.subType = ? THEN L.amount ELSE 0 END) as amount from Ledgers as L where L.clientId = ? and L.amount < 0 and (L.type = ? OR L.subType = ?) and L.tenantId in (select innerO.tenantId from Occupancies as innerO where innerO.clientId = ? and innerO.status in (?, ?) group by innerO.tenantId)";
  const data = [
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and L.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].amount;
  else return 0;
};

occupancyDB.getTotalSecurityInHandForProp = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "Select sum(CASE WHEN L.type = ? THEN abs(L.amount) WHEN L.subType = ? THEN L.amount ELSE 0 END) as amount from Ledgers as L where L.clientId = ? and L.propId = ? and L.amount < 0 and (L.type = ? OR L.subType = ?) and L.tenantId in (select innerO.tenantId from Occupancies as innerO where innerO.clientId = ? and innerO.propId = ? and innerO.status in (?, ?) group by innerO.tenantId)";
  const data = [
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    propId,
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].amount;
  else return 0;
};

occupancyDB.getTotalSecurityInHandForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `Select sum(CASE WHEN L.type = ? THEN abs(L.amount) WHEN L.subType = ? THEN L.amount ELSE 0 END) as amount from Ledgers as L where L.clientId = ? and L.propId in (${propertiesIds}) and (L.type = ? OR L.subType = ?) and L.tenantId in (select innerO.tenantId from Occupancies as innerO where innerO.clientId = ? and innerO.propId in (${propertiesIds}) and innerO.status in (?, ?) group by innerO.tenantId)`;
  const data = [
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].amount;
  else return 0;
};

occupancyDB.getTotalSecurityInHandForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string; propIds: any; }) => {
  let query =
    `Select sum(CASE WHEN L.type = ? THEN abs(L.amount) WHEN L.subType = ? THEN L.amount ELSE 0 END) as amount from Ledgers as L where L.clientId = ? and L.propId in (${propertiesIds}) and (L.type = ? OR L.subType = ?) and L.tenantId in (select innerO.tenantId from Occupancies as innerO where innerO.clientId = ? and innerO.propId in (${propertiesIds}) and innerO.status in (?, ?) group by innerO.tenantId)`;
  const data = [
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.DUES_TYPES.SECURITY,
    CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and L.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].amount;
  else return 0;
};

occupancyDB.getOccupancyReportDataByPropId = async ({
  propId
}: any) => {
  const query =
    `select propId, name as propertyName, roomNum, roomStatus, if(totalDues IS NULL, 0, totalDues) as totalDues, totalSecurity, totalRent, if(totalCollection IS NULL, 0, totalCollection) as totalCollection, rentPerBed, security, noOfTenants, noOfReservedTenants, noOfMovingOutTenants, noOfBeds, noOfVacantBeds, if(floor IS NULL, (select name from Flats as F where F.id=flatId), floor) as floor from (Select P.id as propId, P.name, R.floor, R.flatId, R.id as roomId, R.roomNum, R.status as roomStatus, (select sum(balance) from Dues as D where D.tenantId IN (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (3,4))) as totalDues, (select RO.rent from RoomOptions as RO where RO.id=R.roomOptionId and RO.propId=P.id) as rentPerBed, P.security, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (3,4) group by O.tenantId) as V) as noOfTenants, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (5) group by O.tenantId) as V) as noOfReservedTenants, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (4) group by O.tenantId) as V) as noOfMovingOutTenants, (select count(*) from Beds as B where B.roomId=R.id) as noOfBeds, (select count(*) from Beds as B where B.roomId=R.id and B.status=1) as noOfVacantBeds, (select SUM(T.amount) from Transactions as T where T.roomId = R.id) as totalCollection, (select sum(O.rent) from Occupancies as O where O.roomId = R.id) as totalRent, (select sum(O.security) from Occupancies as O where O.roomId = R.id) as totalSecurity from Properties as P INNER JOIN Rooms as R ON R.propId=P.id where P.id in (${propId.map(() => '?').join(',')})) as V1`;
  const data = [...propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getOccupancyReportDataByClientId = async ({
  clientId
}: occupancyTypes) => {
  const query =
    "select propId, name as propertyName, roomNum, roomStatus, if(totalDues IS NULL, 0, totalDues) as totalDues, totalSecurity, totalRent, if(totalCollection IS NULL, 0, totalCollection) as totalCollection, rentPerBed, security, noOfTenants, noOfReservedTenants, noOfMovingOutTenants, noOfBeds, noOfVacantBeds, if(floor IS NULL, (select name from Flats as F where F.id=flatId), floor) as floor from (Select P.id as propId, P.name, R.floor, R.flatId, R.id as roomId, R.roomNum, R.status as roomStatus, (select sum(balance) from Dues as D where D.tenantId IN (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (3,4))) as totalDues, (select RO.rent from RoomOptions as RO where RO.id=R.roomOptionId and RO.propId=P.id) as rentPerBed, P.security, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (3,4) group by O.tenantId) as V) as noOfTenants, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (5) group by O.tenantId) as V) as noOfReservedTenants, (select count(*) from (select O.tenantId from Occupancies as O where O.roomId=R.id and O.status IN (4) group by O.tenantId) as V) as noOfMovingOutTenants, (select count(*) from Beds as B where B.roomId=R.id) as noOfBeds, (select count(*) from Beds as B where B.roomId=R.id and B.status=1) as noOfVacantBeds, (select SUM(T.amount) from Transactions as T where T.roomId = R.id) as totalCollection, (select sum(O.rent) from Occupancies as O where O.roomId = R.id) as totalRent, (select sum(O.security) from Occupancies as O where O.roomId = R.id) as totalSecurity from Properties as P INNER JOIN Rooms as R ON R.propId=P.id where P.clientId =? and P.status = ?) as V1";
  const data = [clientId, CONSTANTS.PROPERTY_STATUS.ACTIVE];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getBedOccupancyReportDataByPropId = async ({
  propId
}: any) => {
  const query =
    `SELECT P.id AS propId, B.id AS bedId, B.status AS bedStatus, P.name AS propertyName, O.status as occupancyStatus, O.rent AS tenantRent, T.mobile AS tenantMobile, R.roomNum, IFNULL(T.name, '') AS tenantName, IFNULL(DU.totalDues, 0) AS totalDues, DATE(O.moveOutDate) AS moveOutDate, RO.rent AS rentPerBed, P.security, DATE(O.moveInDate) AS moveInDate, O.security AS tenantSecurity, IFNULL(R.floor, F.name) AS floor FROM Properties P INNER JOIN Rooms R ON R.propId = P.id INNER JOIN Beds B ON B.roomId = R.id LEFT JOIN Occupancies O ON O.bedId = B.id AND O.status IN (3, 4, 5) LEFT JOIN Tenants T ON T.id = O.tenantId LEFT JOIN RoomOptions RO ON RO.id = R.roomOptionId AND RO.propId = P.id LEFT JOIN Flats F ON F.id = R.flatId LEFT JOIN (SELECT O.tenantId, O.clientId, SUM(D.balance) AS totalDues FROM Dues D JOIN Occupancies O ON O.tenantId = D.tenantId and O.clientId = D.clientId WHERE O.propId in (${propId.map(() => '?').join(',')}) and O.status IN (3, 4, 5) GROUP BY O.clientId, O.tenantId) DU ON DU.tenantId = O.tenantId and DU.clientId = O.clientId WHERE P.id in (${propId.map(() => '?').join(',')}) and R.status != ?;`;
  const data = [...propId, ...propId, CONSTANTS.ROOM_STATUS.INACTIVE];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getBedOccupancyReportDataByClientId = async ({
  clientId
}: occupancyTypes) => {
  const query =
    "SELECT P.id AS propId, B.id AS bedId, B.status AS bedStatus, P.name AS propertyName, O.status as occupancyStatus, O.rent AS tenantRent, T.mobile AS tenantMobile, R.roomNum, IFNULL(T.name, '') AS tenantName, IFNULL(DU.totalDues, 0) AS totalDues,DATE(O.moveOutDate) AS moveOutDate, DATE(O.moveInDate) AS moveInDate, RO.rent AS rentPerBed, P.security, O.security AS tenantSecurity, IFNULL(R.floor, F.name) AS floor FROM Properties P INNER JOIN Rooms R ON R.propId = P.id INNER JOIN Beds B ON B.roomId = R.id LEFT JOIN Occupancies O ON O.bedId = B.id AND O.status IN (3, 4, 5) LEFT JOIN Tenants T ON T.id = O.tenantId LEFT JOIN RoomOptions RO ON RO.id = R.roomOptionId AND RO.propId = P.id LEFT JOIN Flats F ON F.id = R.flatId LEFT JOIN (SELECT O.tenantId, O.clientId, SUM(D.balance) AS totalDues FROM Dues D JOIN Occupancies O ON O.tenantId = D.tenantId and O.clientId = D.clientId WHERE O.clientId = ? and O.status IN (3, 4, 5) GROUP BY O.clientId, O.tenantId) DU ON DU.tenantId = O.tenantId and DU.clientId = O.clientId WHERE P.clientId = ? and P.status = ? AND R.status != ?";
  const data = [clientId, clientId, CONSTANTS.PROPERTY_STATUS.ACTIVE, CONSTANTS.ROOM_STATUS.INACTIVE];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.updateMoveOutReasonByTenantId = async ({ tenantId, clientId, moveOutReason }: occupancyTypes) => {
  const query = "Update Occupancies set moveOutReason = ? where tenantId = ? and clientId = ?";
  const data = [moveOutReason, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateRentalCycle = async ({
  tenantId,
  clientId,
  rentalCycle,
}: occupancyTypes) => {
  const query = "Update Occupancies set rentalCycle = ? where tenantId = ? and clientId = ?";
  const data = [rentalCycle, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  if (rows.affectedRows > 0) return true;
  else return false;
};

occupancyDB.getGreaterKycStatusTenants = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGreaterKycStatusTenantsCount = async ({ clientId, kycStatus, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getPVCompletedTenants = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPVCompletedTenantsCount = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getRentalBondAvailedTenants = async ({
  clientId,
  pageNum,
  limit
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondAvailedTenantsCount = async ({ clientId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAvailedTenants = async ({
  clientId,
  pageNum,
  limit
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) AND O.rentalBond=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAvailedTenantsCount = async ({ clientId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) AND O.rentalBond=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAllowedTenants = async ({
  clientId,
  pageNum,
  limit
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.rentalBond<=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAllowedTenantsCount = async ({ clientId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.rentalBond<=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getPVPendingTenants = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};


occupancyDB.getPVPendingTenantsCount = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getPVCompletedTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.agreementStartDate, O.agreementPeriod, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPVCompletedTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getPVPendingTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.agreementStartDate, O.agreementPeriod, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPVPendingTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getRentalBondAvailedTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? AND O.rentalBond = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondAvailedTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? AND O.rentalBond = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAllowedTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.rentalBond <= ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAllowedTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.rentalBond <= ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRentalBondNotAvailedTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) AND O.rentalBond = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRentalBondNotAvailedTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) AND O.rentalBond = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRASignedTenants = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRASignedTenantsCount = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRAPendingTenants = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, O.agreementStartDate, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRAPendingTenantsCount = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRASignedTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.agreementStartDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRASignedTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    1,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRAPendingTenantsForProp = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? and P.id=? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRAPendingTenantsCountForProp = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? and P.id=? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    0,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};
occupancyDB.getSmallerKycStatusTenants = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ?  ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSmallerKycStatusTenantsCount = async ({ clientId, propId, kycStatus }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getGreaterKycStatusTenantsForProp = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.propId = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    propId,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGreaterKycStatusTenantsCountForProp = async ({ clientId, kycStatus, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.propId = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getSmallerKycStatusTenantsForProp = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.propId = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSmallerKycStatusTenantsCountForProp = async ({ clientId, propId, kycStatus }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.propId = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getGreaterKycStatusTenantsForFlat = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  flatId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.flatId = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    flatId,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGreaterKycStatusTenantsCountForFlat = async ({ clientId, kycStatus, flatId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.flatId = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    flatId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getSmallerKycStatusTenantsForFlat = async ({
  clientId,
  kycStatus,
  pageNum,
  limit,
  flatId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.flatId = ? ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    flatId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSmallerKycStatusTenantsCountForFlat = async ({ clientId, flatId, kycStatus }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.flatId = ? order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    flatId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getGreaterKycStatusTenantsForStaff = async ({
  clientId,
  propertiesIds,
  kycStatus,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGreaterKycStatusTenantsCountForStaff = async ({ clientId, kycStatus, propertiesIds, }: occupancyTypes & { kycStatus: number; propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus >= ? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getPVTenantsForStaff = async ({
  clientId,
  isPoliceVerified,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isPoliceVerified,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getPVTenantsCountForStaff = async ({ clientId, isPoliceVerified, propertiesIds, }: occupancyTypes & { propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isPoliceVerified = ? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isPoliceVerified,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getRBAvailedTenantsForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0  order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? and O.rentalBond =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRBAvailedTenantsCountForStaff = async ({ clientId, isPoliceVerified, propertiesIds, }: occupancyTypes & { propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId INNER JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND ET.status = ? and O.rentalBond =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getRBNotAvailedTenantsForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) and O.rentalBond =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRBNotAvailedTenantsCountForStaff = async ({ clientId, isPoliceVerified, propertiesIds, }: occupancyTypes & { propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId=ET.tenantId AND O.propId=ET.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND (ET.status IS NULL OR ET.status != ?) and O.rentalBond =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED,
    CONSTANTS.RENTAL_BOND.MANDATORY,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getRBNotAllowedTenantsForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) and O.rentalBond <=? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRBNotAllowedTenantsCountForStaff = async ({ clientId, isPoliceVerified, propertiesIds, }: occupancyTypes & { propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) and O.rentalBond <=? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.RENTAL_BOND.NOT_REQUIRED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};


occupancyDB.getRATenantsForStaff = async ({
  clientId,
  isRentAgreementSigned,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned =? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isRentAgreementSigned,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getRATenantsCountForStaff = async ({ clientId, isRentAgreementSigned, propertiesIds, }: occupancyTypes & { propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isRentAgreementSigned = ? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    isRentAgreementSigned,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getSmallerKycStatusTenantsForStaff = async ({
  clientId,
  propertiesIds,
  kycStatus,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number; propertiesIds: any }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.propId in (" +
    `${propertiesIds}` +
    ") ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getSmallerKycStatusTenantsCountForStaff = async ({ clientId, kycStatus, propertiesIds, }: occupancyTypes & { kycStatus: number; propertiesIds: any }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND T.kycStatus < ? AND O.propId in (" +
    `${propertiesIds}` +
    ") order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    kycStatus,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.setPoliceVerificationStatus = async ({
  tenantId,
  clientId,
  isPoliceVerified
}: occupancyTypes) => {
  const query = "Update Occupancies set isPoliceVerified = ? where tenantId = ? and clientId = ?";
  const data = [isPoliceVerified, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  if (rows.affectedRows > 0) return true;
  else return false;
};

occupancyDB.setRentAgreementStatus = async ({
  tenantId,
  clientId,
  isRentAgreementSigned
}: occupancyTypes) => {
  const query = "Update Occupancies set isRentAgreementSigned = ? where tenantId = ? and clientId = ?";
  const data = [isRentAgreementSigned, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  if (rows.affectedRows > 0) return true;
  else return false;
};

occupancyDB.getByClientIdAndStayType = async ({
  clientId,
  stayType,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.agreementStartDate, O.agreementPeriod, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndStayType = async ({ clientId, stayType }: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getForStaffAndStayType = async ({
  clientId,
  stayType,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
}) => {
  const query =
    "select O.id as occupancyId, O.agreementStartDate, O.agreementPeriod, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId left join Flats as F on F.id = O.flatId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by P.name, O.id, O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountForStaffAndStayType = async ({
  clientId,
  stayType,
  propertiesIds,
}: occupancyTypes & {
  propertiesIds: string;
}) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.propId in (" +
    `${propertiesIds}` +
    ") AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) ";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
    //propertiesIds,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByClientIdAndFlatIdAndStayType = async ({
  clientId,
  flatId,
  pageNum,
  limit,
  stayType,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndFlatIdAndStayType = async ({
  clientId,
  flatId,
  stayType,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByClientIdAndPropIdAndStayType = async ({
  clientId,
  propId,
  pageNum,
  limit,
  stayType,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.agreementStartDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndPropIdAndStayType = async ({
  clientId,
  propId,
  stayType,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? AND O.status NOT IN (?, ?) AND O.stayType = ? AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    stayType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByClientIdAndPropIdTodayBooking = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {
  const query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.agreementStartDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and DATE(O.createdAt) = curdate() AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndPropIdTodayBooking = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ? and DATE(O.createdAt) = curdate() AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.updateKycStatus = async ({ kycStatus, tenantId }: occupancyTypes) => {
  const query = "Update Occupancies set kycStatus = ? where tenantId = ?";
  const data = [kycStatus, tenantId];
  await DB.execute<ResultSetHeader[]>(query, data);
  return true;
};

occupancyDB.updateKycStatusWithClientId = async ({ kycStatus, tenantId, clientId }: occupancyTypes) => {
  const query = "Update Occupancies set kycStatus = ? where tenantId = ? and clientId = ?";
  const data = [kycStatus, tenantId, clientId];
  await DB.execute<ResultSetHeader[]>(query, data);
  return true;
};

occupancyDB.getAvgTenantDuration = async ({
  clientId,
  startDate,
  endDate
}: occupancyTypes & { startDate: any; endDate: any; }) => {
  const query =
    `SELECT ROUND(AVG(DATEDIFF(LEAST(COALESCE(moveOutDate, ?), ?), GREATEST(moveInDate, ?)))) AS avgStayDays FROM (SELECT tenantId, moveInDate, moveOutDate FROM Occupancies WHERE clientId = ? and stayType != ? and moveInDate <= ? AND (moveOutDate IS NULL OR moveOutDate >= ?) UNION ALL SELECT tenantId, moveInDate, moveOutDate FROM MoveOut WHERE clientId = ? and stayType != ? and moveInDate <= ? AND moveOutDate >= ? and status = ?) AS AllTenants WHERE DATEDIFF(LEAST(COALESCE(moveOutDate, ?), ?), GREATEST(moveInDate, ?)) > 0`;
  const data = [
    endDate,
    endDate,
    startDate,
    clientId,
    CONSTANTS.STAY_TYPE.SHORT,
    endDate,
    startDate,
    clientId,
    CONSTANTS.STAY_TYPE.SHORT,
    endDate,
    startDate,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
    endDate,
    endDate,
    startDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].avgStayDays;
  else return 0;
};

occupancyDB.getActiveTenantCountForDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: any; endDate: any }) => {
  const query =
    `Select COUNT(DISTINCT tenantId) AS count from (select tenantId from Occupancies where clientId = ? and stayType != ? and moveInDate <= ? and (moveOutDate is null or moveOutDate >= ?) UNION ALL select tenantId from MoveOut where clientId = ? and stayType != ? and moveInDate <= ? and moveOutDate >= ? and status = ? and wasCancelled = 0) as AllTenants`;
  const data = [
    clientId,
    CONSTANTS.STAY_TYPE.SHORT,
    endDate,
    startDate,
    clientId,
    CONSTANTS.STAY_TYPE.SHORT,
    endDate,
    startDate,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTotalActiveTenantsByPropIds = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: string }) => {
  const query =
    `select COUNT(DISTINCT O.tenantId) as totalTenants from Occupancies as O inner join Properties as P on P.id = O.propId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId) AND O.propId in (${propertiesIds})`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalTenants;
  else return 0;
};

occupancyDB.addDiscount = async ({
  tenantId,
  clientId,
  discount,
  discountType,
  discountPeriod,
  discountStartDate,
  discountEndDate,
  isDiscountFromFirstMonth,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set discount = ?, discountType = ?, discountPeriod = ?, discountStartDate = ?, discountEndDate = ?, isDiscountFromFirstMonth = ? where tenantId = ? and clientId = ?";
  const data = [discount, discountType, discountPeriod, discountStartDate, discountEndDate, isDiscountFromFirstMonth, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  if (rows.affectedRows > 0) return true;
  else return false;
};

occupancyDB.updateDiscountStartEndDate = async ({
  tenantId,
  clientId,
  discountStartDate,
  discountEndDate,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set discountStartDate = ?, discountEndDate = ? where tenantId = ? and clientId = ?";
  const data = [discountStartDate, discountEndDate, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  if (rows.affectedRows > 0) return true;
  else return false;
};

occupancyDB.getByBedIdWithoutStatus = async ({ bedId }: occupancyTypes) => {
  const query =
    "SELECT O.*, P.type as propertyType, P.name as propName, R.roomNum, R.flatId, RO.name as roomOptionName, RO.type as roomOptionType, RO.amenities FROM Occupancies AS O LEFT JOIN Properties AS P ON P.id = O.propId LEFT JOIN Rooms AS R ON R.id = O.roomId LEFT JOIN RoomOptions AS RO ON RO.id = R.roomOptionId JOIN (SELECT MAX(id) as maxId FROM Occupancies WHERE bedId = ? AND status NOT IN (?, ?) GROUP BY tenantId) as latest ON latest.maxId = O.id;";
  const data = [
    bedId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNewTenantByDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: any; endDate: any }) => {
  const query =
    "select Count(*) as newTenants from (select tenantId from Occupancies where clientId = ? and Date(moveInDate) BETWEEN ? and ? group by tenantId UNION select tenantId from MoveOut where clientId = ? and status = 2 and Date(moveInDate) BETWEEN ? and ? group by tenantId) as V1"
  const data = [
    clientId,
    startDate,
    endDate,
    clientId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].newTenants;
  else return false;
}

occupancyDB.getMoveOutTenantByDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: any; endDate: any }) => {
  const query =
    "select Count(*) as moveOutTenants from (select tenantId from MoveOut where clientId = ? and wasCancelled=0 and Date(moveOutDate) BETWEEN ? and ? and status = 2 group by tenantId) as V1"
  const data = [
    clientId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveOutTenants;
  else return false;
};

occupancyDB.getCancelledReservationTenantByDateRange = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: any; endDate: any }) => {
  const query =
    "select Count(*) as moveOutTenants from (select tenantId from MoveOut where clientId = ? and wasCancelled=1 and Date(moveOutDate) BETWEEN ? and ? and status = 2 group by tenantId) as V1"
  const data = [
    clientId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveOutTenants;
  else return false;
};

occupancyDB.getByBedIdAndTenantIdAndStatus = async ({
  clientId,
  tenantId,
  bedId,
  status,
}: occupancyTypes) => {
  const query = `Select * from Occupancies where clientId = ? and tenantId = ? and bedId = ? and status = ? order by id desc limit 1`;
  const data = [
    clientId,
    tenantId,
    bedId,
    status,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByBedIdAndStatus = async ({
  clientId,
  bedId,
  status,
}: occupancyTypes) => {
  const query = `Select * from Occupancies where clientId = ? and bedId = ? and status = ? order by id desc limit 1`;
  const data = [
    clientId,
    bedId,
    status,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.updateTenantFineDetails = async ({
  clientId,
  propId,
  fine,
  fineType,
  gracePeriod,
}: occupancyTypes) => {
  const query = `update Occupancies set fine = ?, fineType = ?, gracePeriod = ? where clientId = ? and propId = ?`;
  const data = [
    fine,
    fineType,
    gracePeriod,
    clientId,
    propId,
  ];

  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getByTenantIdForLogin = async ({
  tenantId,
}: occupancyTypes) => {
  const query = `Select "occupied" as type, O.id as id, O.clientId, O.tenantId, O.propId, O.roomId, O.bedId, O.createdAt, O.updatedAt, O.rent, O.security, O.rentalCycle, O.rentalType, O.lockInPeriod, O.noticePeriod, O.agreementPeriod, O.agreementStartDate, O.moveInDate, O.moveOutDate, O.status, O.kycStatus, O.stayType, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.flatId, O.propertyName, O.propertyAddress, O.roomNum, O.clientName from ( Select O.*, P.name as propertyName, P.address as propertyAddress, R.roomNum as roomNum, C.name as clientName, ROW_NUMBER() OVER (PARTITION BY O.clientId ORDER BY O.updatedAt DESC) as rn from Occupancies as O left join Clients as C on C.id = O.clientId left join Properties as P on P.id = O.propId left join Rooms as R on R.id = O.roomId where O.tenantId = ?) as O where O.rn = 1
  Union All
  Select "moveOut" as type, M.id as id, M.clientId, M.tenantId, M.propId, M.roomId, M.bedId, M.createdAt, M.updatedAt, M.rent, M.security, M.rentalCycle, M.rentalType, M.lockInPeriod, M.noticePeriod, M.agreementPeriod, M.agreementStartDate, M.moveInDate, M.moveOutDate, M.status, M.kycStatus, M.stayType, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.flatId, M.propertyName, M.propertyAddress, M.roomNum, M.clientName from ( Select M.*, P.name as propertyName, P.address as propertyAddress, R.roomNum as roomNum, C.name as clientName, ROW_NUMBER() OVER (PARTITION BY M.clientId ORDER BY M.updatedAt DESC) as rn from MoveOut as M left join Clients as C on C.id = M.clientId left join Properties as P on P.id = M.propId left join Rooms as R on R.id = M.roomId where M.tenantId = ? and wasCancelled != 1) as M where M.rn = 1`;

  const data = [
    tenantId,
    tenantId,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantStayDetails = async ({ tenantId }: occupancyTypes) => {
  try {
    const occupancyQuery = `
      WITH RankedOccupancies AS (
        SELECT 
          "occupied" AS type,
          O.id,
          O.clientId,
          O.tenantId,
          O.propId,
          O.roomId,
          O.bedId,
          O.createdAt,
          O.updatedAt,
          O.rent,
          O.security,
          O.rentalCycle,
          O.rentalType,
          O.lockInPeriod,
          O.noticePeriod,
          O.agreementPeriod,
          O.agreementStartDate,
          O.moveInDate,
          O.moveOutDate,
          O.status,
          O.kycStatus,
          O.stayType,
          O.isPoliceVerified,
          O.isRentAgreementSigned,
          O.rentalBond,
          O.floor,
          O.flatId,
          P.name AS propertyName,
          P.address AS propertyAddress,
          ROW_NUMBER() OVER (PARTITION BY O.clientId ORDER BY O.createdAt ASC) as rowNum
        FROM Occupancies AS O
        LEFT JOIN Properties AS P ON P.id = O.propId
        WHERE O.tenantId = ? and O.status NOT IN (1)
      )
      SELECT type, id, clientId, tenantId, propId, roomId, bedId, createdAt, updatedAt,
        rent, security, rentalCycle, rentalType, lockInPeriod, noticePeriod,
        agreementPeriod, agreementStartDate, moveInDate, moveOutDate, status,
        kycStatus, stayType, isPoliceVerified, isRentAgreementSigned, rentalBond,
        floor, flatId, propertyName, propertyAddress
      FROM RankedOccupancies
      WHERE rowNum = 1
      ORDER BY updatedAt DESC;`;

    const [occupancyRows] = await DB.execute<RowDataPacket[]>(occupancyQuery, [tenantId]);

    const moveOutQuery = `
      SELECT 
        "moveOut" AS type,
        M.id,
        M.clientId,
        M.tenantId,
        M.propId,
        M.roomId,
        M.bedId,
        M.createdAt,
        M.updatedAt,
        M.rent,
        M.security,
        M.rentalCycle,
        M.rentalType,
        M.lockInPeriod,
        M.noticePeriod,
        M.agreementPeriod,
        M.agreementStartDate,
        M.moveInDate,
        M.moveOutDate,
        M.status,
        M.kycStatus,
        M.stayType,
        M.isPoliceVerified,
        M.isRentAgreementSigned,
        M.rentalBond,
        M.floor,
        M.flatId,
        P.name AS propertyName,
        P.address AS propertyAddress
      FROM MoveOut AS M
      LEFT JOIN Properties AS P ON P.id = M.propId
      WHERE M.tenantId = ? 
        AND M.wasCancelled != 1 AND M.status != 1
      ORDER BY M.updatedAt DESC;
    `;

    const [moveOutRows] = await DB.execute<RowDataPacket[]>(moveOutQuery, [tenantId]);

    const result = [...occupancyRows, ...moveOutRows];
    if (result.length > 0) return result;
    return false;
  } catch (error) {
    console.error("Error fetching tenant stay details:", error);
    throw error;
  }
};

occupancyDB.getTenantStayDetailsWithClientId = async ({ tenantId, clientId }: occupancyTypes) => {
  try {

    const occupancyQuery = `
      SELECT 
        "occupied" AS type,
        O.id,
        O.clientId,
        O.tenantId,
        O.propId,
        O.roomId,
        O.bedId,
        O.createdAt,
        O.updatedAt,
        O.rent,
        O.security,
        O.rentalCycle,
        O.rentalType,
        O.lockInPeriod,
        O.noticePeriod,
        O.agreementPeriod,
        O.agreementStartDate,
        O.moveInDate,
        O.moveOutDate,
        O.status,
        O.kycStatus,
        O.stayType,
        O.isPoliceVerified,
        O.isRentAgreementSigned,
        O.rentalBond,
        O.floor,
        O.flatId,
        P.name AS propertyName,
        P.address AS propertyAddress
      FROM Occupancies AS O
      LEFT JOIN Properties AS P ON P.id = O.propId
      WHERE O.tenantId = ? and O.clientId = ? and O.status NOT IN (1)
      ORDER BY O.updatedAt DESC`;

    const [occupancyRows] = await DB.execute<RowDataPacket[]>(occupancyQuery, [tenantId, clientId]);

    const moveOutQuery = `
      SELECT 
        "moveOut" AS type,
        M.id,
        M.clientId,
        M.tenantId,
        M.propId,
        M.roomId,
        M.bedId,
        M.createdAt,
        M.updatedAt,
        M.rent,
        M.security,
        M.rentalCycle,
        M.rentalType,
        M.lockInPeriod,
        M.noticePeriod,
        M.agreementPeriod,
        M.agreementStartDate,
        M.moveInDate,
        M.moveOutDate,
        M.status,
        M.kycStatus,
        M.stayType,
        M.isPoliceVerified,
        M.isRentAgreementSigned,
        M.rentalBond,
        M.floor,
        M.flatId,
        P.name AS propertyName,
        P.address AS propertyAddress
      FROM MoveOut AS M
      LEFT JOIN Properties AS P ON P.id = M.propId
      WHERE M.tenantId = ? 
        AND M.clientId = ? AND M.wasCancelled != 1 AND M.status != 1
      ORDER BY M.updatedAt DESC;
    `;

    const [moveOutRows] = await DB.execute<RowDataPacket[]>(moveOutQuery, [tenantId, clientId]);

    const result = [...occupancyRows, ...moveOutRows];

    if (result.length > 0) return result;
    return false;
  } catch (error) {
    console.error("Error fetching tenant stay details:", error);
    throw error;
  }
};

occupancyDB.getTenantStayDetailsWithPartnerId = async ({ tenantId, clientId }: occupancyTypes) => {
  try {

    const occupancyQuery = `
      SELECT 
        "occupied" AS type,
        O.id,
        O.clientId,
        O.tenantId,
        O.propId,
        O.roomId,
        O.bedId,
        O.createdAt,
        O.updatedAt,
        O.rent,
        O.security,
        O.rentalCycle,
        O.rentalType,
        O.lockInPeriod,
        O.noticePeriod,
        O.agreementPeriod,
        O.agreementStartDate,
        O.moveInDate,
        O.moveOutDate,
        O.status,
        O.kycStatus,
        O.stayType,
        O.isPoliceVerified,
        O.isRentAgreementSigned,
        O.rentalBond,
        O.floor,
        O.flatId,
        P.name AS propertyName,
        P.address AS propertyAddress
      FROM Occupancies AS O
      LEFT JOIN Properties AS P ON P.id = O.propId
      WHERE O.tenantId = ? and O.clientId in (select id from Clients where parentId = ?) and O.status NOT IN (1)
      ORDER BY O.updatedAt DESC`;

    // log.info(`Query [${occupancyQuery}]`);  
    const [occupancyRows] = await DB.execute<RowDataPacket[]>(occupancyQuery, [tenantId, clientId]);

    const moveOutQuery = `
      SELECT 
        "moveOut" AS type,
        M.id,
        M.clientId,
        M.tenantId,
        M.propId,
        M.roomId,
        M.bedId,
        M.createdAt,
        M.updatedAt,
        M.rent,
        M.security,
        M.rentalCycle,
        M.rentalType,
        M.lockInPeriod,
        M.noticePeriod,
        M.agreementPeriod,
        M.agreementStartDate,
        M.moveInDate,
        M.moveOutDate,
        M.status,
        M.kycStatus,
        M.stayType,
        M.isPoliceVerified,
        M.isRentAgreementSigned,
        M.rentalBond,
        M.floor,
        M.flatId,
        P.name AS propertyName,
        P.address AS propertyAddress
      FROM MoveOut AS M
      LEFT JOIN Properties AS P ON P.id = M.propId
      WHERE M.tenantId = ? 
        AND M.clientId in (select id from Clients where parentId = ?) AND M.wasCancelled != 1 AND M.status != 1
      ORDER BY M.updatedAt DESC;
    `;

    // log.info(`Query [${moveOutQuery}]`);

    const [moveOutRows] = await DB.execute<RowDataPacket[]>(moveOutQuery, [tenantId, clientId]);

    const result = [...occupancyRows, ...moveOutRows];

    if (result.length > 0) return result;
    return false;
  } catch (error) {
    console.error("Error fetching tenant stay details:", error);
    throw error;
  }
};

occupancyDB.getWithoutReservedTenantsByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number }) => {

  const query =
    "select * from (select O.id as occupancyId, O.agreementStartDate, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.moveOutDate, O.floor, O.rent, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  and O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.moveInDate asc, O.createdAt desc) as v limit ?, ? ";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getWithoutReservedTenantsCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.propId = ?  AND O.status NOT IN (?, ?, ?) and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.updateTenantDigiLockerIds = async ({
  verificationId,
  referenceId,
  tenantId,
  clientId,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set verificationId = ?, referenceId = ? where tenantId = ? and clientId = ?";
  const data = [verificationId, referenceId, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getByVerificationId = async ({ verificationId }: occupancyTypes) => {
  const query = "Select * from Occupancies where verificationId = ?";
  const data = [verificationId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByGId = async ({ gId }: occupancyTypes) => {
  const query = "Select gId, tenantId, clientId, propId, id from Occupancies where gId = ? UNION Select gId, tenantId, clientId, propId, id from MoveOut where gId = ?";
  const data = [gId, gId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getByGIdX = async ({ gId }: occupancyTypes) => {
  const query = "Select O.gId, O.tenantId, O.clientId, O.propId, O.id, T.name as tenantName, T.mobile as tenantMobile from Occupancies as O join Tenants as T on O.tenantId = T.id where O.gId = ?";
  const data = [gId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.updateGId = async ({
  gId,
  tenantId,
  clientId,
}: occupancyTypes) => {
  const query =
    "Update Occupancies set gId = ? where tenantId = ? and clientId = ?";
  const data = [gId, tenantId, clientId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateLastReminded = async ({ lastRemindedOn, tenantId, clientId }: occupancyTypes) => {
  const query = "Update Occupancies set lastRemindedOn = ? where tenantId = ? and clientId = ?";
  const data = [lastRemindedOn, tenantId, clientId];
  await DB.execute<ResultSetHeader[]>(query, data);
  return true;
};

occupancyDB.remindedToday = async ({ clientId, tenantId }: occupancyTypes) => {
  const query =
    "select * from Occupancies where clientId = ? and tenantId = ? and Date(lastRemindedOn) = curdate();";
  const data = [clientId, tenantId];
  const [rows] = await DB.execute<ResultSetHeader[]>(query, data);
  if (rows.length > 0) return true;
  else return false;
};

occupancyDB.getZeroDepositTenantsByClientId = async ({
  clientId,
  pageNum,
  limit
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getZeroDepositTenantsCountByClientId = async ({ clientId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNonZeroDepositTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
  rentMultiplier,
}: occupancyTypes & { pageNum: number; limit: number; rentMultiplier: number }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNonZeroDepositTenantsCountByClientId = async ({ clientId, rentMultiplier }: occupancyTypes & { rentMultiplier: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getZeroDepositTenantsByClientIdAndPropId = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getZeroDepositTenantsCountByClientIdAndPropId = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 order by O.createdAt desc";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNonZeroDepositTenantsByClientIdAndPropId = async ({
  clientId,
  pageNum,
  limit,
  propId,
  rentMultiplier
}: occupancyTypes & { pageNum: number; limit: number; rentMultiplier: number; }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNonZeroDepositTenantsCountByClientIdAndPropId = async ({ clientId, propId, rentMultiplier, }: occupancyTypes & { rentMultiplier: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent order by O.createdAt desc";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getZeroDepositTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number; propertiesIds: string }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getZeroDepositTenantsCountByClientIdForStaff = async ({ clientId, propertiesIds }: occupancyTypes & { propertiesIds: string }) => {
  let query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = 0 order by O.createdAt desc`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getNonZeroDepositTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  rentMultiplier
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; rentMultiplier: number }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getNonZeroDepositTenantsCountByClientIdForStaff = async ({ clientId, propertiesIds, rentMultiplier, }: occupancyTypes & { propertiesIds: string; rentMultiplier: number }) => {
  let query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.security = ? * O.rent order by O.createdAt desc`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    rentMultiplier,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.updateIsFoodOpted = async ({
  clientId,
  tenantId,
  isFoodOpted,
}: occupancyTypes) => {
  const query = `Update Occupancies set isFoodOpted = ? where clientId = ? and tenantId = ?`;
  const data = [
    isFoodOpted,
    clientId,
    tenantId,
  ];

  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateIsBusOpted = async ({
  clientId,
  tenantId,
  isBusOpted,
}: occupancyTypes) => {
  const query = `Update Occupancies set isBusOpted = ? where clientId = ? and tenantId = ?`;
  const data = [
    isBusOpted,
    clientId,
    tenantId,
  ];

  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getFoodEnabledTenantsByClientId = async ({
  clientId,
  pageNum,
  limit
}: occupancyTypes & { pageNum: number; limit: number; }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodEnabledTenantsCountByClientId = async ({ clientId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodNotEnabledTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodNotEnabledTenantsCountByClientId = async ({ clientId }: occupancyTypes & { rentMultiplier: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 order by O.createdAt desc";
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodEnabledTenantsByClientIdAndPropId = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodEnabledTenantsCountByClientIdAndPropId = async ({ clientId, propId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 order by O.createdAt desc";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodNotEnabledTenantsByClientIdAndPropId = async ({
  clientId,
  pageNum,
  limit,
  propId,
}: occupancyTypes & { pageNum: number; limit: number; }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodNotEnabledTenantsCountByClientIdAndPropId = async ({ clientId, propId, }: occupancyTypes & { rentMultiplier: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 order by O.createdAt desc";
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodEnabledTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number; propertiesIds: string }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodEnabledTenantsCountByClientIdForStaff = async ({ clientId, propertiesIds }: occupancyTypes & { propertiesIds: string }) => {
  let query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 order by O.createdAt desc`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodNotEnabledTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  let query =
    `select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodNotEnabledTenantsCountByClientIdForStaff = async ({ clientId, propertiesIds, }: occupancyTypes & { propertiesIds: string; }) => {
  let query =
    `select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND P.id in (${propertiesIds}) AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 order by O.createdAt desc`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodEnabledTenantsByClientIdAndFlatId = async ({
  clientId,
  pageNum,
  limit,
  flatId,
}: occupancyTypes & { pageNum: number; limit: number; kycStatus: number }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodEnabledTenantsCountByClientIdAndFlatId = async ({ clientId, flatId }: occupancyTypes & { kycStatus: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 1 order by O.createdAt desc";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFoodNotEnabledTenantsByClientIdAndFlatId = async ({
  clientId,
  pageNum,
  limit,
  flatId,
}: occupancyTypes & { pageNum: number; limit: number; }) => {
  let query =
    "select O.id as occupancyId, O.moveInDate, O.isPoliceVerified, O.isRentAgreementSigned, O.floor, O.rent, O.agreementStartDate, O.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 ORDER BY P.name, O.id, O.createdAt DESC LIMIT ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFoodNotEnabledTenantsCountByClientIdAndFlatId = async ({ clientId, flatId, }: occupancyTypes & { rentMultiplier: number }) => {
  let query =
    "select COUNT(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.clientId = ? AND R.flatId = ? AND O.status NOT IN (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId ) AND O.isFoodOpted = 0 order by O.createdAt desc";
  const data = [
    clientId,
    flatId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantCountByPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    `select COUNT(DISTINCT tenantId) AS tenantCount, roomId from Occupancies where clientId = ? and propId = ? and status in (?, ?) group by roomId`;
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return 0;
};

occupancyDB.getTenantCountByClientIdAndPropId = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  const query =
    `select COUNT(DISTINCT tenantId) AS tenantCount from Occupancies where clientId = ? and propId = ? and status in (?, ?, ?)`;
  const data = [
    clientId,
    propId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].tenantCount;
  else return 0;
};

occupancyDB.getTenantCountByClientIdAndPropIds = async ({
  clientId,
  propId,
}: occupancyTypes) => {
  let query =
    `select IFNULL(COUNT(DISTINCT tenantId), 0) AS tenantCount from Occupancies where clientId = ? and status in (?, ?)`;
  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];

  if (Array.isArray(propId) && propId.length > 0) {
    query += ` and propId in (${propId.map(() => '?').join(',')})`;
    data.push(...propId);
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].tenantCount;
  else return 0;
};

occupancyDB.potentialRentPerMonth = async ({
  clientId,
}: occupancyTypes) => {
  const query = `SELECT IFNULL(SUM(o.rent), 0) AS totalRent FROM Occupancies o JOIN (SELECT MAX(id) AS id from Occupancies WHERE clientId = ? GROUP BY tenantId) latest ON latest.id = o.id WHERE o.clientId = ? AND o.status IN (?, ?, ?);`;
  const data = [
    clientId,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalRent;
  else return 0;
}

occupancyDB.getBookingsByPropId = async ({
  propId,
}: { propId: any; }) => {
  const query = `SELECT ANY_VALUE(O.propId) AS propId, ANY_VALUE(O.createdAt) AS createdAt, ANY_VALUE(T.gender) AS gender, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(O.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(O.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(O.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(O.rent) AS rent, ANY_VALUE(O.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(O.rentalCycle) AS rentalCycle, ANY_VALUE(O.notes) AS notes, ANY_VALUE(O.status) AS occupancyStatus, ANY_VALUE(O.moveOutDate) AS moveOutDate, ANY_VALUE(O.lockInPeriod) AS lockInPeriod, ANY_VALUE(O.noticePeriod) AS noticePeriod, ANY_VALUE(O.flatId) as flatId, ANY_VALUE(O.floor) as floor FROM Occupancies AS O JOIN Tenants AS T ON T.id = O.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = O.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id WHERE O.propId in (${propId.map(() => '?').join(',')}) AND O.status=? GROUP BY O.tenantId`;
  const data = [...propId, CONSTANTS.OCCUPANCY_STATUS.RESERVED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getBookingsByClientId = async ({
  clientId,
}: occupancyTypes) => {

  const query = "SELECT ANY_VALUE(O.propId) AS propId, ANY_VALUE(O.createdAt) AS createdAt, ANY_VALUE(T.gender) AS gender, ANY_VALUE(T.email) AS email, ANY_VALUE(T.dob) AS dob, ANY_VALUE(T.aadharNumber) AS aadhaarNumber, ANY_VALUE(T.bloodGroup) AS bloodGroup, ANY_VALUE(T.occupation) AS occupation, ANY_VALUE(O.kycStatus) AS kycStatus, ANY_VALUE(COALESCE(NULLIF(TG.fatherName, ''), '')) AS fatherName, ANY_VALUE(COALESCE(NULLIF(TG.fatherMobile, ''), '')) AS fatherMobile, ANY_VALUE(COALESCE(NULLIF(TG.fatherOccupation, ''), '')) AS fatherOccupation, ANY_VALUE(COALESCE(NULLIF(TG.fatherAnnualIncome, ''), '')) AS fatherAnnualIncome, ANY_VALUE(COALESCE(NULLIF(TG.motherName, ''), '')) AS motherName, ANY_VALUE(COALESCE(NULLIF(TG.motherMobile, ''), '')) AS motherMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianName, ''), '')) AS localGuardianName, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianMobile, ''), '')) AS localGuardianMobile, ANY_VALUE(COALESCE(NULLIF(TG.localGuardianRelation, ''), '')) AS localGuardianRelation, ANY_VALUE(T.institutionName) AS institutionName, ANY_VALUE(T.institutionEmail) AS institutionEmail, ANY_VALUE(T.title) AS title, ANY_VALUE(T.address) AS address, COUNT(O.tenantId) AS occupiedBeds, ANY_VALUE(DATE_FORMAT(O.moveInDate, '%Y-%m-%d')) AS moveInDate, ANY_VALUE(O.rent) AS rent, ANY_VALUE(O.security) AS security, ANY_VALUE(T.name) AS name, ANY_VALUE(T.mobile) AS mobile, ANY_VALUE(R.roomNum) AS roomNum, ANY_VALUE(R.extendedName) AS roomName, ANY_VALUE(T.id) AS id, ANY_VALUE(RO.name) AS roomOptionName, ANY_VALUE(O.rentalCycle) AS rentalCycle, ANY_VALUE(O.notes) AS notes, ANY_VALUE(O.status) AS occupancyStatus, ANY_VALUE(O.moveOutDate) AS moveOutDate, ANY_VALUE(O.lockInPeriod) AS lockInPeriod, ANY_VALUE(O.noticePeriod) AS noticePeriod, ANY_VALUE(O.flatId) as flatId, ANY_VALUE(O.floor) as floor FROM Occupancies AS O JOIN Tenants AS T ON T.id = O.tenantId LEFT JOIN TenantGuardians AS TG ON T.id = TG.tenantId JOIN Rooms AS R ON R.id = O.roomId JOIN RoomOptions AS RO ON R.roomOptionId = RO.id INNER JOIN Properties AS P ON O.propId = P.id WHERE O.clientId = ? AND P.status = ? AND O.status=? GROUP BY O.tenantId";
  const data = [
    clientId,
    CONSTANTS.PROPERTY_STATUS.ACTIVE,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getReservedTenantsCountByPropId = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.propId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId and innerO.propId= O.propId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    propId,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getMovingOutTenantsCountByPropId = async ({
  propId,
}: occupancyTypes) => {
  const query =
    "select COUNT(v.id) as count from (select O.id from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId WHERE O.propId = ? AND O.status = ? and  O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId and innerO.propId= O.propId GROUP BY innerO.tenantId ) order by O.createdAt desc) as v ";
  const data = [
    propId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.updateIsOnlinePaymentEnabledByPropId = async ({
  propId,
  isOnlinePaymentEnabled,
}: occupancyTypes) => {
  const query =
    "update Occupancies set isOnlinePaymentEnabled = ? where propId = ?";
  const data = [isOnlinePaymentEnabled, propId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.updateIsFoodOptedByPropId = async ({
  propId,
  isFoodOpted,
}: occupancyTypes) => {
  const query =
    "update Occupancies set isFoodOpted = ? where propId = ?";
  const data = [isFoodOpted, propId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getTenantsWithMissingRent = async ({
  clientId,
}: occupancyTypes) => {
  const query = `SELECT O.*, T.name as tenantName, T.mobile as tenantMobile, P.name as propName FROM Occupancies O JOIN Tenants T ON T.id = O.tenantId JOIN Properties P ON O.propId = P.id WHERE O.rentalCycle <= DAY(CURDATE()) AND O.clientId = ? AND O.stayType != ? AND O.status in (?, ?) AND NOT EXISTS (SELECT 1 FROM Ledgers L WHERE L.tenantId = O.tenantId AND L.clientId = O.clientId AND L.type = ? AND CURDATE() BETWEEN L.rentStartDate AND L.rentEndDate)`

  const data = [
    clientId,
    CONSTANTS.STAY_TYPE.SHORT,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    CONSTANTS.DUES_TYPES.RENT,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithPendingRefundByClientId = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
    CONSTANTS.REFUND_STATUS.FORFEITED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and amount < 0 and DATE(createdAt) >= M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithPendingRefundCountByClientId = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string | null; endDate: string | null }) => {

  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId, CONSTANTS.REFUND_STATUS.FORFEITED,];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }
  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and amount < 0 and DATE(createdAt) > M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsByClientIdAndWasCancelled = async ({
  clientId,
  wasCancelled,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; startDate: string | null; endDate: string | null; }) => {
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    wasCancelled,
  ];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate, if (M.bookedBy = 0, (select name from Clients where id=M.clientId limit 1), (select name from Staffs where id=M.bookedBy limit 1)) as bookedByName from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND M.wasCancelled = ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;

  data.push(`${offset}`);
  data.push(`${limit}`);

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsByClientIdAndPendingFnF = async ({
  clientId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; startDate: string | null; endDate: string | null; }) => {

  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.wasCancelled = 0 and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) and CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? order by M.createdAt desc) as v limit ?, ?`;

  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsCountByClientIdAndWasCancelled = async ({
  clientId,
  wasCancelled,
  startDate,
  endDate,
}: occupancyTypes & { wasCancelled: number; startDate: string | null; endDate: string | null; }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, wasCancelled];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? AND M.wasCancelled = ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsCountByClientIdAndPendingFnF = async ({
  clientId,
}: occupancyTypes & { wasCancelled: number; startDate: string | null; endDate: string | null; }) => {

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.wasCancelled = 0 and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? order by M.createdAt desc) as v `;

  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsWithPendingRefundByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
    CONSTANTS.REFUND_STATUS.FORFEITED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and propId in (${propertiesIds}) and amount < 0 and DATE(createdAt) >= M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;

  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithPendingRefundCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId, CONSTANTS.REFUND_STATUS.FORFEITED,];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and propId in (${propertiesIds}) and amount < 0 and DATE(createdAt) > M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsWithPendingRefundByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
    propId,
    CONSTANTS.REFUND_STATUS.FORFEITED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and propId =? and amount < 0 and DATE(createdAt) >= M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  // const finalQuery = DB.format(query, data);
  // //console.log(finalQuery);
  // log.info(finalQuery);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithPendingRefundCountByClientIdAndPropId = async ({
  clientId,
  propId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId, propId, CONSTANTS.REFUND_STATUS.FORFEITED,];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId not in (select tenantId from Transactions where clientId = ? and propId = ? and amount < 0 and DATE(createdAt) > M.moveInDate) and M.refundStatus != ? ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsWithProcessedRefundByClientId = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and amount < 0 and DATE(createdAt) >= M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithProcessedRefundCountByClientId = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and amount < 0 and DATE(createdAt) > M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFNFGeneratedEvictedTenantsByClientId = async ({
  clientId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.refundStatus = ? ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFNFGeneratedEvictedTenantsByClientIdCount = async ({
  clientId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.refundStatus = ? ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsWithProcessedRefundByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.propId in (${propertiesIds}) and M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and propId in (${propertiesIds}) and amount < 0 and DATE(createdAt) >= M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithProcessedRefundCountByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and propId in (${propertiesIds}) and amount < 0 and DATE(createdAt) > M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getFNFGeneratedEvictedTenantsByClientIdForStaff = async ({
  clientId,
  pageNum,
  limit,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.propId in (${propertiesIds}) and M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.refundStatus = ? ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getFNFGeneratedEvictedTenantsByClientIdCountForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: occupancyTypes & { propertiesIds: string; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.refundStatus = ? ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsByClientIdAndWasCancelledForStaff = async ({
  clientId,
  propertiesIds,
  wasCancelled,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; propertiesIds: string; startDate: string | null; endDate: string | null; }) => {
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    wasCancelled,
  ];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate, if (M.bookedBy = 0, (select name from Clients where id=M.clientId limit 1), (select name from Staffs where id=M.bookedBy limit 1)) as bookedByName from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId in (${propertiesIds}) AND M.status != ? AND M.wasCancelled = ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;

  data.push(`${offset}`);
  data.push(`${limit}`);

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsCountByClientIdAndWasCancelledForStaff = async ({
  clientId,
  propertiesIds,
  wasCancelled,
  startDate,
  endDate,
}: occupancyTypes & { wasCancelled: number; propertiesIds: string; startDate: string | null; endDate: string | null; }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, wasCancelled];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.propId in (${propertiesIds}) AND M.wasCancelled = ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsByClientIdAndPendingFnFForStaff = async ({
  clientId,
  propertiesIds,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; propertiesIds: string; startDate: string | null; endDate: string | null; }) => {

  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.wasCancelled = 0 and M.propId in (${propertiesIds}) AND M.status != ? AND CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
    `${offset}`,
    `${limit}`
  ];
  //log.info(mysql.format(query, data))
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsCountByClientIdAndPendingFnFForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { wasCancelled: number; propertiesIds: string; startDate: string | null; endDate: string | null; }) => {

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.wasCancelled = 0 and M.propId in (${propertiesIds}) AND CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v `;
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getEvictedTenantsWithProcessedRefundByClientIdAndPropId = async ({
  clientId,
  propId,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; startDate: string | null; endDate: string | null }) => {
  const data: any = [
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    clientId,
    propId,
  ];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.agreementStartDate, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, M.agreementPeriod, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where tenantId = M.tenantId and clientId=M.clientId) as totalDues, NULL as dueDate,  NULL as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and propId = ? and amount < 0 and DATE(createdAt) >= M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v limit ?, ? `;
  const offset: number = (pageNum - 1) * limit;
  data.push(`${offset}`);
  data.push(`${limit}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getEvictedTenantsWithProcessedRefundCountByClientIdAndPropId = async ({
  clientId,
  propId,
  startDate,
  endDate,
}: occupancyTypes & { startDate: string | null; endDate: string | null }) => {
  const data: any = [clientId, propId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, clientId, propId];

  let startEndCheck = "";
  if (startDate && endDate) {
    startEndCheck = " and Date(M.moveOutDate) BETWEEN ? and ?";
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) and M.tenantId in (select tenantId from Transactions where clientId = ? and propId = ? and amount < 0 and DATE(createdAt) > M.moveInDate) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsByClientIdAndPropIdAndWasCancelled = async ({
  clientId,
  propId,
  wasCancelled,
  pageNum,
  limit,
  startDate,
  endDate,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; startDate: string | null; endDate: string | null; }) => {

  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    wasCancelled,
  ];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate, if (M.bookedBy = 0, (select name from Clients where id=M.clientId limit 1), (select name from Staffs where id=M.bookedBy limit 1)) as bookedByName from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.propId = ? AND M.status != ? AND M.wasCancelled = ? and  M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;

  data.push(`${offset}`)
  data.push(`${limit}`)

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsCountByClientIdAndPropIdAndWasCancelled = async ({
  clientId,
  propId,
  wasCancelled,
  startDate,
  endDate,
}: occupancyTypes & { wasCancelled: number; startDate: string | null; endDate: string | null; }) => {
  const data: any = [clientId, CONSTANTS.MOVE_OUT_STATUS.INITIATED, propId, wasCancelled];

  let startEndCheck = "";

  if (startDate && endDate) {
    startEndCheck = ` and DATE(M.moveOutDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.propId = ? AND M.wasCancelled = ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) ${startEndCheck} order by M.createdAt desc) as v `;
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getTenantsByClientIdAndPropIdAndPendingFnF = async ({
  clientId,
  propId,
  pageNum,
  limit,
}: occupancyTypes & { pageNum: number; limit: number; wasCancelled: number; startDate: string | null; endDate: string | null; }) => {


  const query =
    `select * from (select M.id as occupancyId, M.wasCancelled, M.moveInDate, M.isPoliceVerified, M.isRentAgreementSigned, M.floor, M.rent, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, M.status, T.kycStatus as tenantKycStatus, M.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (select sum(balance) from MoveOutDues where clientId=M.clientId and tenantId = M.tenantId) as totalDues, NULL as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ? and moveOut = 1 order by id desc limit 1) as profilePicture, M.moveOutDate from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? and M.wasCancelled = 0 and M.propId = ? AND M.status != ? and CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId=M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    propId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
    `${offset}`,
    `${limit}`,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantsCountByClientIdAndPropIdAndPendingFnF = async ({
  clientId,
  propId,
}: occupancyTypes & { wasCancelled: number; startDate: string | null; endDate: string | null; }) => {

  const query =
    `select COUNT(v.id) as count from (select M.id from MoveOut as M inner join Tenants as T on T.id = M.tenantId inner join Properties as P on P.id = M.propId inner join Rooms as R on R.id = M.roomId WHERE M.clientId = ? AND M.status != ? and M.wasCancelled = 0 and M.propId = ? and CURDATE() > DATE_ADD(M.moveOutDate, INTERVAL 30 DAY) and M.refundStatus < ? and M.id IN (SELECT MAX(innerM.id) FROM MoveOut as innerM WHERE innerM.tenantId = M.tenantId and innerM.clientId = M.clientId GROUP BY innerM.tenantId) order by M.createdAt desc) as v `;
  const data: any = [
    clientId,
    CONSTANTS.MOVE_OUT_STATUS.INITIATED,
    propId,
    CONSTANTS.REFUND_STATUS.STATEMENT_GENERATED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

occupancyDB.getByTenantIdWithStatus = async ({ tenantId, clientId }: occupancyTypes) => {
  const query = "select * from Occupancies where clientId = ? and tenantId = ? and status != 1 order by id desc";
  const data = [clientId, tenantId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.getReservedCountForClient = async ({ clientId }: occupancyTypes) => {
  const query = "SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND status =?";
  const data = [clientId, CONSTANTS.OCCUPANCY_STATUS.RESERVED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveIn;
  else return 0;
};

occupancyDB.getReservedCountForClientStaffs = async ({ clientId, propertiesIds }: occupancyTypes & { propertiesIds: string }) => {
  const query = `SELECT COUNT(DISTINCT tenantId) as moveIn FROM Occupancies WHERE clientId = ? AND status =? and propId in (${propertiesIds})`;
  const data = [clientId, CONSTANTS.OCCUPANCY_STATUS.RESERVED];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveIn;
  else return 0;
};


// occupancyDB.getMovingOutCountForClient = async ({clientId }: occupancyTypes) => {
//   const query = "SELECT COUNT(DISTINCT tenantId) as count FROM Occupancies WHERE clientId = ? AND status =?";
//   const data = [clientId, CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0].count;
//   else return 0;
// };

// occupancyDB.getMovingOutCountForClientStaffs = async ({clientId,  propertiesIds}: occupancyTypes & {propertiesIds: string}) => {
//   const query = `SELECT COUNT(DISTINCT tenantId) as count FROM Occupancies WHERE clientId = ? AND status =? and propId in (${propertiesIds})`;
//   const data = [clientId, CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows[0].count;
//   else return 0;
// };

occupancyDB.getByClientIdAndFilters = async ({
  clientId,
  propIds,
  flatIds,
  filterArr,
  filterVal,
  propertiesIds,
  pageNum,
  limit,
  searchVal,
}: occupancyTypes & { filterArr: any[]; propIds: string; flatIds: string; limit: number; pageNum: number; filterVal: any; propertiesIds: string; searchVal: string; }) => {
  let query = `select O.id as occupancyId, O.moveInDate, O.moveOutDate, O.isPoliceVerified, O.isRentAgreementSigned, O.agreementStartDate, O.agreementPeriod, O.floor, O.rent, O.security, T.id as tenantId, T.name, T.mobile, T.gender, T.occupation, O.status, T.kycStatus as tenantKycStatus, O.kycStatus, T.device as platform, P.type as propertyType, P.name as propertyName, R.roomNum, R.flatId, (Select SUM(balance) as total from Dues where tenantId = O.tenantId and clientId = O.clientId) as totalDues, (Select MAX(dueDate) as dueDate from Dues where tenantId = O.tenantId and clientId = O.clientId) as dueDate, (Select value from Documents where tenantId = T.id and propId = P.id and type = ?  and moveOut=0 order by id desc limit 1) as profilePicture from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN Flats as F on F.id = O.flatId LEFT JOIN EqaroTenants as ET ON O.tenantId = ET.tenantId AND O.propId = ET.propId WHERE O.clientId = ? AND O.status not in (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )`;
  const data: any = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  if (filterArr && Array.isArray(filterArr)) {
    for (let filter of filterArr) {
      //log.info(`Filter [${filter}]`);
      switch (filter) {
        case "R":
          //Reserved Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.RESERVED);
          break;
        case "MOP":
          //Move Out Pending Tenants
          query += ` and O.status = ? and DATE(O.moveOutDate) <= CURDATE()`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT);
          break;
        case "MO":
          //Moving Out Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT);
          break;
        case "O":
          //Occupied Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.OCCUPIED);
          break;
        case "V":
          //Verifiede Tenants
          query += ` and O.kycStatus > ?`;
          data.push(CONSTANTS.KYC_STATUS.PERSONAL_INFO);
          break;
        case "UV":
          //Unverified Tenants
          query += ` and O.kycStatus <= ?`;
          data.push(CONSTANTS.KYC_STATUS.PERSONAL_INFO);
          break;
        case "NT":
          //New Tenants
          query += ` and date(O.moveInDate) = curdate()`;
          break;
        case "I":
          //App Installed
          query += ` and T.device != 0`;
          break;
        case "NI":
          //App Not Installed
          query += ` and T.device = 0`;
          break;
        case "PV":
          //Police Verification
          query += ` and O.isPoliceVerified = 1`;
          break;
        case "PVP":
          //Police Verification Pending
          query += ` and O.isPoliceVerified != 1`;
          break;
        case "RA":
          //Rent Agreement
          query += ` and O.isRentAgreementSigned = 1`;
          break;
        case "RAP":
          //Rent Agreement Pending
          query += ` and O.isRentAgreementSigned != 1`;
          break;
        case "SS":
          //Short Stay
          query += ` and O.stayType = ?`;
          data.push(CONSTANTS.STAY_TYPE.SHORT);
          break;
        case "RB":
          //Rent Bond Availed
          query += ` and ET.status = ?`;
          data.push(CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED);
          break;
        case "RBN":
          //Rent Bond Not Availed
          query += ` and O.rentalBond = ? and (ET.status IS NULL OR ET.status != ?)`;
          data.push(CONSTANTS.RENTAL_BOND.MANDATORY);
          data.push(CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED);
          break;
        case "RBNA":
          //Rent Bond Not Allowed
          query += ` and O.rentalBond <= ?`;
          data.push(CONSTANTS.RENTAL_BOND.NOT_REQUIRED);
          break;
        case "ZS":
          //Zero Security Deposit
          query += ` and O.security = 0`;
          break;
        case "1RS":
          //Security = rent
          query += ` and O.security = 1 * O.rent`;
          break;
        case "1.5RS":
          //Security = 1.5 * rent
          query += ` and O.security = 1.5 * O.rent`;
          break;
        case "2RS":
          // Security = 2 * rent
          query += ` and O.security = 2 * O.rent`;
          break;
        case "FE":
          //Food Enabled
          query += ` and O.isFoodOpted = 1`;
          break;
        case "FNE":
          //Food Not Enabled
          query += ` and O.isFoodOpted = 0`;
          break;
        case "OE":
          //Online Enabled
          query += ` and O.isOnlinePaymentEnabled = 1`;
          break;
        case "ONE":
          //Online Not Enabled
          query += ` and O.isOnlinePaymentEnabled = 0`;
          break;
        case "GM":
          //Gender Male
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.MALE);
          break;
        case "GF":
          //Gender Female
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.FEMALE);
          break;
        case "GO":
          //Gender Other
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.OTHER);
          break;
        case "BE":
          //Bus Enabled
          query += ` and O.isBusOpted = 1`;
          break;
        case "BNE":
          //Bus Not Enable
          query += ` and O.isBusOpted = 0`;
          break;
        case "BY":
          //Booked By
          let filterValArr: any = [];
          if (filterVal && typeof filterVal === 'string') {
            filterValArr = filterVal.split(',').map(v => v.trim()).filter(Boolean);
          }
          query += ` and O.bookedBy in (${filterValArr.map(() => '?').join(',')})`;
          data.push(...filterValArr);
          break;
      }
    }
  }

  if (searchVal && typeof searchVal === 'string' && searchVal.trim() !== "" && searchVal !== "null" && searchVal !== "undefined") {
    //Search Filter
    query += ` and T.name like ?`;
    data.push(`%${searchVal}%`);
  }

  if (propIds && typeof propIds === 'string') {
    //Property Filter
    let propArr: any = [];
    if (propIds && typeof propIds === 'string') {
      propArr = propIds.split(',').map((v: any) => v.trim()).filter(Boolean);
    }
    query += ` and O.propId in (${propArr.map(() => '?').join(',')})`;
    data.push(...propArr);
  }

  // if (flatIds && typeof flatIds === 'string') {
  //   //Flat Filter
  //   let flatArr: any = [];
  //   if (flatIds && typeof flatIds === 'string') {
  //     flatArr = flatArr.split(',').map((v: any) => v.trim()).filter(Boolean);
  //   }
  //   query += ` and O.flatId in (${flatArr.map(() => '?').join(',')})`;
  //   data.push(...flatArr);
  // }
  if (flatIds && typeof flatIds === 'string') {
    //Flat Filter
    let flatArr: any = [];
    if (flatIds && typeof flatIds === 'string') {
      // flatArr = flatArr.split(',').map((v: any) => v.trim()).filter(Boolean);
    }
    query += ` and O.flatId = ?`;
    data.push(flatIds);
  }

  if (propertiesIds) {
    query += ` and O.propId in (${propertiesIds})`
  }

  const offset: number = (pageNum - 1) * limit;
  if (filterArr && Array.isArray(filterArr) && filterArr.includes("RS")) {
    query += ` order by P.name, CASE WHEN O.flatId IS NOT NULL THEN CAST(F.name AS UNSIGNED) ELSE CAST(O.floor AS UNSIGNED) END, R.id, O.id limit ?, ?`;
  } else if (filterArr && Array.isArray(filterArr) && filterArr.includes("CS")) {
    query += ` order by O.createdAt desc, O.id desc limit ?, ?`;
  } else if (filterArr && Array.isArray(filterArr) && filterArr.includes("MO")) {
    query += ` order by O.moveOutDate asc, O.id desc, O.createdAt desc limit ?, ?`;
  } else if (filterArr && Array.isArray(filterArr) && filterArr.includes("R")) {
    query += ` order by O.moveInDate asc, O.id desc, O.createdAt desc limit ?, ?`;
  } else {
    query += ` order by O.moveInDate desc, O.id desc, O.createdAt desc limit ?, ?`;
  }
  data.push(`${offset}`);
  data.push(`${limit}`);

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCountByClientIdAndFilters = async ({
  clientId,
  propIds,
  flatIds,
  filterArr,
  filterVal,
  propertiesIds,
  searchVal,
}: occupancyTypes & { filterArr: any[]; propIds: string; flatIds: string; limit: number; pageNum: number; filterVal: any; propertiesIds: string; searchVal: string; }) => {
  let query = `select Count(O.id) as count from Occupancies as O inner join Tenants as T on T.id = O.tenantId inner join Properties as P on P.id = O.propId inner join Rooms as R on R.id = O.roomId LEFT JOIN EqaroTenants as ET ON O.tenantId = ET.tenantId AND O.propId = ET.propId WHERE O.clientId = ? AND O.status not in (?, ?) AND O.id IN (SELECT MAX(innerO.id) FROM Occupancies as innerO WHERE innerO.tenantId = O.tenantId and innerO.clientId = O.clientId GROUP BY innerO.tenantId )`;
  const data: any = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];

  if (filterArr && Array.isArray(filterArr)) {
    for (let filter of filterArr) {
      switch (filter) {
        case "R":
          //Reserved Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.RESERVED);
          break;
        case "MOP":
          //Move Out Pending Tenants
          query += ` and O.status = ? and DATE(O.moveOutDate) <= CURDATE()`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT);
          break;
        case "MO":
          //Moving Out Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT);
          break;
        case "O":
          //Occupied Tenants
          query += ` and O.status = ?`;
          data.push(CONSTANTS.OCCUPANCY_STATUS.OCCUPIED);
          break;
        case "V":
          //Verifiede Tenants
          query += ` and O.kycStatus > ?`;
          data.push(CONSTANTS.KYC_STATUS.PERSONAL_INFO);
          break;
        case "UV":
          //Unverified Tenants
          query += ` and O.kycStatus <= ?`;
          data.push(CONSTANTS.KYC_STATUS.PERSONAL_INFO);
          break;
        case "NT":
          //New Tenants
          query += ` and date(O.moveInDate) = curdate()`;
          break;
        case "I":
          //App Installed
          query += ` and T.device != 0`;
          break;
        case "NI":
          //App Not Installed
          query += ` and T.device = 0`;
          break;
        case "PV":
          //Police Verification
          query += ` and O.isPoliceVerified = 1`;
          break;
        case "PVP":
          //Police Verification Pending
          query += ` and O.isPoliceVerified != 1`;
          break;
        case "RA":
          //Rent Agreement
          query += ` and O.isRentAgreementSigned = 1`;
          break;
        case "RAP":
          //Rent Agreement Pending
          query += ` and O.isRentAgreementSigned != 1`;
          break;
        case "SS":
          //Short Stay
          query += ` and O.stayType = ?`;
          data.push(CONSTANTS.STAY_TYPE.SHORT);
          break;
        case "RB":
          //Rent Bond Availed
          query += ` and ET.status = ?`;
          data.push(CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED);
          break;
        case "RBN":
          //Rent Bond Not Availed
          query += ` and O.rentalBond = ? and (ET.status IS NULL OR ET.status != ?)`;
          data.push(CONSTANTS.RENTAL_BOND.MANDATORY);
          data.push(CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED);
          break;
        case "RBNA":
          //Rent Bond Not Allowed
          query += ` and O.rentalBond <= ?`;
          data.push(CONSTANTS.RENTAL_BOND.NOT_REQUIRED);
          break;
        case "ZS":
          //Zero Security Deposit
          query += ` and O.security = 0`;
          break;
        case "1RS":
          //Security = rent
          query += ` and O.security = 1 * O.rent`;
          break;
        case "1.5RS":
          //Security = 1.5 * rent
          query += ` and O.security = 1.5 * O.rent`;
          break;
        case "2RS":
          // Security = 2 * rent
          query += ` and O.security = 2 * O.rent`;
          break;
        case "FE":
          //Food Enabled
          query += ` and O.isFoodOpted = 1`;
          break;
        case "FNE":
          //Food Not Enabled
          query += ` and O.isFoodOpted = 0`;
          break;
        case "OE":
          //Online Enabled
          query += ` and O.isOnlinePaymentEnabled = 1`;
          break;
        case "ONE":
          //Online Not Enabled
          query += ` and O.isOnlinePaymentEnabled = 0`;
          break;
        case "GM":
          //Gender Male
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.MALE);
          break;
        case "GF":
          //Gender Female
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.FEMALE);
          break;
        case "GO":
          //Gender Other
          query += ` and T.gender = ?`;
          data.push(CONSTANTS.GENDER.OTHER);
          break;
        case "BE":
          //Gender Other
          query += ` and O.isBusOpted = 1`;
          break;
        case "BNE":
          //Gender Other
          query += ` and O.isBusOpted = 0`;
          break;
        case "BY":
          //Booked By
          let filterValArr: any = [];
          if (filterVal && typeof filterVal === 'string') {
            filterValArr = filterVal.split(',').map(v => v.trim()).filter(Boolean);
          }
          query += ` and O.bookedBy in (${filterValArr.map(() => '?').join(',')})`;
          data.push(...filterValArr);
          break;
      }
    }
  }

  if (searchVal && typeof searchVal === 'string' && searchVal.trim() !== "" && searchVal !== "null" && searchVal !== "undefined") {
    //Search Filter
    query += ` and T.name like ?`;
    data.push(`%${searchVal}%`);
  }

  if (propIds && typeof propIds === 'string') {
    //Property Filter
    let propArr: any = [];
    if (propIds && typeof propIds === 'string') {
      propArr = propIds.split(',').map((v: any) => v.trim()).filter(Boolean);
    }
    query += ` and O.propId in (${propArr.map(() => '?').join(',')})`;
    data.push(...propArr);
  }

  if (flatIds && typeof flatIds === 'string') {
    //Flat Filter
    let flatArr: any = [];
    // if (flatIds && typeof flatIds === 'string') {
    //   flatArr = flatArr.split(',').map((v: any) => v.trim()).filter(Boolean);
    // }
    // query += ` and O.flatId in (${flatArr.map(() => '?').join(',')})`;
    // data.push(...flatArr);
    query += ` and O.flatId = ?`;
    data.push(flatIds);
  }

  if (propertiesIds) {
    query += ` and O.propId in (${propertiesIds})`
  }

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return false;
};

occupancyDB.getDetailByTenantIdAndClientIdOrderByBedId = async ({ tenantId, clientId }: occupancyTypes) => {
  const query = "select * from Occupancies where tenantId = ? and clientId=? order by bedId asc";
  const data = [tenantId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getByClientIdTenantIdAndBedId = async ({ tenantId, clientId, bedId }: occupancyTypes) => {
  const query = "select * from Occupancies where tenantId = ? and clientId=? and bedId=?";
  const data = [tenantId, clientId, bedId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.deleteById = async ({ id }: occupancyTypes) => {
  const query = "delete from Occupancies where id=? limit 1";
  const data = [id];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

occupancyDB.updateBedId = async ({ id, bedId }: occupancyTypes) => {
  const query = "update Occupancies set bedId = ? where id = ? limit 1";
  const data = [bedId, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getTotalMonthlyRentByClientIdAndPropId = async ({ clientId, propId }: occupancyTypes) => {
  const query = "select SUM(rent/rentalType) as rent from Occupancies where clientId=? and propId = ? and status in (?, ?)";
  const data = [clientId, propId, CONSTANTS.OCCUPANCY_STATUS.OCCUPIED, CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].rent;
  else return 0;
};

occupancyDB.updateTallyStatus = async ({ id, tallyStatus }: occupancyTypes) => {
  const query = "update Occupancies set tallyStatus = ? where id = ? limit 1";
  const data = [tallyStatus, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.syncOccupancyTally = async ({ clientId }: occupancyTypes) => {
  const query = "update Occupancies set tallyStatus = ? where clientId = ? and tallyStatus = ?";
  const data = [
    CONSTANTS.TALLY_STATUS.RETRY,
    clientId,
    CONSTANTS.TALLY_STATUS.FAILED,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

occupancyDB.getMoveOutPendingCountForClient = async ({
  clientId,
}: occupancyTypes) => {
  const query = "Select COUNT(DISTINCT(tenantId)) as moveOutPending from Occupancies where clientId = ? and status = ? and DATE(moveOutDate) is not null and DATE(moveOutDate) <= CURDATE()";

  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveOutPending;
  else return 0;
};

occupancyDB.getMoveOutPendingCountForStaff = async ({
  clientId,
  propertiesIds,
}: occupancyTypes & { propertiesIds: any }) => {
  const query = `Select COUNT(DISTINCT(tenantId)) as moveOutPending from Occupancies where clientId = ? and propId in (${propertiesIds}) and status = ? and DATE(moveOutDate) is not null and DATE(moveOutDate) <= CURDATE()`;

  const data = [
    clientId,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].moveOutPending;
  else return 0;
};

occupancyDB.getCompleteHistoryByBedId = async ({ bedId }: occupancyTypes) => {
  const query = `
  select O.id, O.propId, O.stayType, O.roomId, O.moveInDate, O.moveOutDate, O.rentalCycle, O.noticePeriod, O.lockInPeriod, O.agreementPeriod, O.rent, O.security, O.agreementStartDate, O.status, O.kycStatus, O.createdAt, T.id as tenantId, T.name as tenantName, T.gender, T.mobile, 0 as isEvicted, (select value from Documents where tenantId = O.tenantId and clientId = O.clientId and type = ? and moveOut=0 limit 1) as profilePicture from Occupancies as O join Tenants as T on O.tenantId = T.id where O.bedId = ? and O.status not in (?)
  UNION
  select MO.id, MO.propId, MO.stayType, MO.roomId, MO.moveInDate, MO.moveOutDate, MO.rentalCycle, MO.noticePeriod, MO.lockInPeriod, MO.agreementPeriod, MO.rent, MO.security, MO.agreementStartDate, MO.status, MO.kycStatus, MO.createdAt, T.id as tenantId, T.name as tenantName, T.gender, T.mobile, 1 as isEvicted, (select value from Documents where tenantId = MO.tenantId and clientId = MO.clientId and type = ? and moveOut=1 limit 1) as profilePicture from MoveOut as MO join Tenants as T on MO.tenantId = T.id where MO.bedId = ? and MO.status = ?
  order by id desc
  `;
  const data = [
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    bedId,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.DOCUMENT_TYPES.SELFI,
    bedId,
    CONSTANTS.MOVE_OUT_STATUS.MOVEOUT
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getMovingOutCountByProp = async ({clientId}: occupancyTypes) => {
  const query = "select propId, count(distinct tenantId) as count from Occupancies where clientId = ? and status = ? group by propId";
  const data = [clientId, CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getCurMonthBookingCountByProp = async ({clientId}: occupancyTypes) => {
  const query = `Select propId, count(distinct tenantId) as count from Occupancies where clientId = ? and Month(moveInDate) = MONTH(CURDATE()) and Year(moveInDate) = YEAR(CURDATE()) and status not in (?, ?) group by propId`;
  const data = [
    clientId, 
    CONSTANTS.OCCUPANCY_STATUS.PENDING, 
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getTenantBookedCountByClientIdAndStaffId = async ({
  clientId,
  bookedBy,
  month,
  year,
}: occupancyTypes & { month: number; year: number }) => {
  const startDate = moment().year(year).month(month - 1).startOf("month").format("YYYY-MM-DD");
  const endDate = moment(startDate).add(1, "month").format("YYYY-MM-DD");

  // const query = "SELECT ((SELECT COUNT(*) FROM Occupancies WHERE clientId = ? AND bookedBy = ? AND status NOT IN (?, ?) AND moveInDate >= ? AND moveInDate < ?) + (SELECT COUNT(*) FROM MoveOut WHERE clientId = ? AND bookedBy = ? AND status != ? AND moveInDate >= ? AND moveInDate < ?)) AS count";

  // const data = [
  //   clientId,
  //   bookedBy,
  //   CONSTANTS.OCCUPANCY_STATUS.PENDING,
  //   CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
  //   startDate,
  //   endDate,
  //   clientId,
  //   bookedBy,
  //   1,
  //   startDate,
  //   endDate,
  // ];
  const query = "SELECT ((SELECT COUNT(*) FROM Occupancies WHERE clientId = ? AND bookedBy = ? AND status NOT IN (?, ?) AND date(createdAt) >= ? AND date(createdAt) < ?)) AS count";

  const data = [
    clientId,
    bookedBy,
    CONSTANTS.OCCUPANCY_STATUS.PENDING,
    CONSTANTS.OCCUPANCY_STATUS.REQUESTED,
    startDate,
    endDate,
  ];

  const [rows] = await DB.execute<RowDataPacket[]>(query, data);

  return rows?.[0]?.count || 0;
};

occupancyDB.getOccupancyByRoomId = async ({ roomId }: occupancyTypes) => {
  const query =
    "select * from Occupancies where roomId = ? and status in (?, ?, ?) order by id";
  const data = [
    roomId,
    CONSTANTS.OCCUPANCY_STATUS.OCCUPIED,
    CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT,
    CONSTANTS.OCCUPANCY_STATUS.RESERVED,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGetTenantAttendances = async ({ clientId, startDate, endDate }: any) => {
  const query =
    "SELECT O.propId, P.name AS propName, P.type AS propType, O.tenantId, T.name AS tenantName, R.floor, F.name as flat, R.roomNum, date(TA.attendanceDate) as attendanceDate, TA.attendance FROM (SELECT * FROM (SELECT O.*, ROW_NUMBER() OVER (PARTITION BY O.clientId, O.tenantId ORDER BY O.id DESC) AS rn FROM Occupancies AS O WHERE O.clientId = ? AND O.status = 3 AND O.moveInDate <= ?) AS O1 WHERE O1.rn = 1) AS O INNER JOIN Properties AS P ON P.id = O.propId INNER JOIN Tenants AS T ON T.id = O.tenantId INNER JOIN Rooms AS R ON R.id = O.roomId LEFT JOIN Flats as F ON F.id=R.flatId LEFT JOIN TenantAttendance AS TA ON TA.tenantId = O.tenantId AND TA.clientId = O.clientId AND TA.attendanceDate >= ? AND TA.attendanceDate <= ? and P.status = ?";
  const data = [
    clientId,
    startDate,
    startDate,
    endDate,
    CONSTANTS.PROPERTY_STATUS.ACTIVE
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

occupancyDB.getGetTenantAttendancesByPropId = async ({ propId, startDate, endDate }: any) => {
  const query =
    `SELECT O.propId, P.name AS propName, P.type AS propType, O.tenantId, T.name AS tenantName, R.floor, F.name as flat, R.roomNum, date(TA.attendanceDate) as attendanceDate, TA.attendance FROM (SELECT * FROM (SELECT O.*, ROW_NUMBER() OVER (PARTITION BY O.clientId, O.tenantId ORDER BY O.id DESC) AS rn FROM Occupancies AS O WHERE O.propId IN (${propId.map(() => '?').join(',')}) AND O.status = 3 AND O.moveInDate <= ?) AS O1 WHERE O1.rn = 1) AS O INNER JOIN Properties AS P ON P.id = O.propId INNER JOIN Tenants AS T ON T.id = O.tenantId INNER JOIN Rooms AS R ON R.id = O.roomId LEFT JOIN Flats as F ON F.id=R.flatId LEFT JOIN TenantAttendance AS TA ON TA.tenantId = O.tenantId AND TA.clientId = O.clientId AND TA.attendanceDate >= ? AND TA.attendanceDate <= ? and P.status = ?`;
  const data = [
    ...propId,
    startDate,
    startDate,
    endDate,
    CONSTANTS.PROPERTY_STATUS.ACTIVE
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

export default occupancyDB;
