import mysql, { ResultSetHeader, RowDataPacket } from "mysql2";
import DB from "../config/database/db";
import expensesTypes from "../schemas/expenses.schema";
import expensesPropertyTypes from "../schemas/expensesProperty.schema";
import CONSTANTS from "../config/constants";
import expense from "../controllers/expense.controller";
import log from "../config/log";
import landlordTransactionDB from "./landlordTransaction.model";

const expenseDB: any = {};

expenseDB.getById = async ({ id }: expensesTypes) => {
  const query =
    "Select E.id, E.expenseTitle, E.recurringExpenseId, E.dueDate, E.isPaid, E.type, E.amount, E.balance, E.supportDoc, E.paidDate, E.paidByUserType, E.paidBy, E.paidTo, E.paidToUserType, E.description, E.paymentMethod, E.createdAt, ET.name from Expenses as E inner join ExpenseTypes as ET on ET.id = E.type where E.id = ? order by id desc";
  const data = [id];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getUnpaidById = async ({ id }: expensesTypes) => {
  const query =
    "Select E.id, E.expenseTitle, E.dueDate, E.isPaid, E.type, E.amount, E.balance, E.supportDoc, E.paidDate, E.paidByUserType, E.paidBy, E.paidTo, E.paidToUserType, E.description, E.paymentMethod, E.createdAt, ET.name from Expenses as E inner join ExpenseTypes as ET on ET.id = E.type where E.id = ? and E.isPaid=? order by id desc";
  const data = [id, 0];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getByIds = async ({ ids }: any) => {

  if (!ids || (ids && ids.length < 1)) {
    return false;
  }
  
  const query =
    `Select E.id, E.expenseTitle, E.isPaid, E.dueDate, E.type, E.amount, E.balance, E.supportDoc, E.paidDate, E.paidByUserType, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name from Expenses as E inner join ExpenseTypes as ET on ET.id = E.type where E.id in (${ids.map(() => '?').join(',')}) order by id desc`;
  
  const data = [...ids];

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

expenseDB.getSearchResult = async ({
  clientId,
  limit,
  pageNum,
  searchVal,
}: expensesTypes & { pageNum: number; limit: number; searchVal: string }) => {
  const query =
    "Select * from (Select E.id, E.expenseTitle, E.expenseNature, E.dueDate, E.bankRefNum, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 ) as v where (v.amount like ? or v.paidByName like ? or v.paidToName like ? ) order by v.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getSearchResultForStaff = async ({
  clientId,
  limit,
  pageNum,
  searchVal,
  propertiesIds,
}: expensesTypes & {
  pageNum: number;
  limit: number;
  searchVal: string;
  propertiesIds: string;
}) => {
  const query =
    "Select * from (Select E.id, E.expenseTitle, E.dueDate, E.expenseNature, E.bankRefNum, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ") ) as v where (v.amount like ? or v.paidByName like ? or v.paidToName like ? ) order by v.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    //propertiesIds,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdForStaff = async ({
  clientId,
  limit,
  pageNum,
  month,
  propertiesIds,
}: expensesTypes & {
  pageNum: number;
  limit: number;
  month: string;
  propertiesIds: string;
}) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.bankRefNum, E.dueDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.paidByUserType, E.paidToUserType, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and EP.propId in (" +
    `${propertiesIds}` +
    ") and E.isPaid = 1 order by E.id desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    month,
    month,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndDateRangeForStaff = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & {
  pageNum: number;
  limit: number;
  startDate: string;
  endDate: string;
  propertiesIds: string;
}) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.dueDate, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.paidByUserType, E.paidToUserType, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (" +
    `${propertiesIds}` +
    ") and E.isPaid = 1 order by E.dueDate desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getTotalByClientIdForStaff = async ({
  clientId,
  month,
  propertiesIds,
}: expensesTypes & { month: string; propertiesIds: string }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ")";
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId, month, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByDueDateClientIdForStaff = async ({
  clientId,
  month,
  propertiesIds,
  sortBy,
}: expensesTypes & { month: string; propertiesIds: string; sortBy: string; }) => {
  let sortByFilter = "E.paidDate";
  if(sortBy === "DD") {
    sortByFilter = "E.dueDate";
  }
  const query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and MONTH(${sortByFilter}) = MONTH(?) and YEAR(${sortByFilter}) = YEAR(?) and E.isPaid = 1 and EP.propId in (${propertiesIds})`;
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId, month, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; propIds: any; propertiesIds: any }) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and DATE(E.dueDate) between ? and ? and E.isPaid = 1 and EP.propId in (${propertiesIds})`;
  const data = [clientId, startDate, endDate];

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

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

expenseDB.getTotalByClientIdAndDateRangeForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: expensesTypes & { propertiesIds: string; startDate: string; endDate: string }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and DATE(E.dueDate) BETWEEN ? and ? and E.isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ")";
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getByClientId = async ({
  clientId,
  limit,
  pageNum,
  month,
}: expensesTypes & { pageNum: number; limit: number; month: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.bankRefNum, E.dueDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1 order by E.id desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    month,
    month,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdandDateRange = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  sortBy,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; sortBy: string }) => {
  let query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.assetId, E.bankRefNum, E.dueDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 ";
  const offset: number = (pageNum - 1) * limit;
  let data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
  ];

  if (sortBy && sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ? order by E.paidDate desc`;
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc`;
  }

  data.push(startDate);
  data.push(endDate);

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

expenseDB.getByClientIdandDateRangeAndTypeFilter = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  typeFilter,
  sortBy,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; typeFilter: any; sortBy: string }) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.assetId, E.dueDate, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 `;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
  ];

  if(Array.isArray(typeFilter) && typeFilter.length > 0) {
    query += ` and E.type in (${typeFilter.map(() => '?').join(',')})`;
    data.push(...typeFilter);
  }
  
  if (sortBy && sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ? order by E.paidDate desc limit ?, ?`;
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc limit ?, ?`;
  }

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

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

expenseDB.getByClientIdandDateRangeForReport = async ({
  clientId,
  startDate,
  endDate,
  sortBy=null,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; sortBy: string | null; }) => {
  
  let sortByFilter = ` E.dueDate asc`;
  if (sortBy === "PD") {
    sortByFilter = ` E.paidDate asc`;
  }

  const query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, EP.propId, EP.flatId, E.paidDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId, EC.name as expenseCategoryName, ET.name as expenseTypeName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id left join Properties as P on EP.propId = P.id where E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by ${sortByFilter}`;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    // CONSTANTS.PROPERTY_STATUS.ACTIVE,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getTotalByClientId = async ({
  clientId,
  month,
}: expensesTypes & { month: string }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1";
  const data = [clientId, month, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByDueDateClientId = async ({
  clientId,
  month,
  sortBy,
}: expensesTypes & { month: string; sortBy: string; }) => {

  let sortByFilter = "E.paidDate";
  if(sortBy === "DD") {
    sortByFilter = "E.dueDate";
  }

  const query =
    `Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and MONTH(${sortByFilter}) = MONTH(?) and YEAR(${sortByFilter}) = YEAR(?) and E.isPaid = 1`;
  const data = [clientId, month, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndNatureForWeb = async ({
  clientId,
  expenseNature,
  propIds,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  // let query =
  //   "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1";
  let query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and DATE(E.dueDate) between ? and ? and E.isPaid = 1 and E.expenseNature = ?";
  const data = [clientId, startDate, endDate, expenseNature];

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

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

expenseDB.getTotalByClientIdAndNatureAndPaidDateForWeb = async ({
  clientId,
  expenseNature,
  propIds,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  let query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and DATE(E.paidDate) between ? and ? and E.isPaid = 1 and E.expenseNature = ?";
  const data = [clientId, startDate, endDate, expenseNature];

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

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

expenseDB.getLifetimeTotalByClientIdAndNatureForWeb = async ({
  clientId,
  expenseNature,
  propIds,
}: expensesTypes & { propIds: any }) => {
  // let query =
  //   "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1";
  let query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.isPaid = 1 and E.expenseNature = ?";
  const data = [clientId, expenseNature];

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

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

expenseDB.getTotalByClientIdAndDateRange = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?";
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndDateRangeDueDate = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string }) => {
  const query =
    "Select IFNULL(SUM(E.amount), 0) as total from Expenses as E where E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?";
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

// expenseDB.getByClientIdAndPropId = async ({
//   clientId,
//   propId,
//   limit,
//   pageNum,
//   month,
// }: expensesTypes &
//   expensesPropertyTypes & {
//     pageNum: number;
//     limit: number;
//     month: string;
//   }) => {
//   const query =
//     "Select E.id, E.type, E.dueDate, E.amount, E.balance, E.supportDoc, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, V.name as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type left join Vendors as V on V.id = E.paidTo where E.clientId = ? and EP.propId = ? and MONTH(E.dueDate) = MONTH(?) and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1 order by E.id desc  limit ?, ?";
//   const offset: number = (pageNum - 1) * limit;
//   const data = [
//     CONSTANTS.USER_TYPE.CLIENT,
//     clientId,
//     propId,
//     month,
//     month,
//     `${offset}`,
//     `${limit}`,
//   ];
//   const [rows] = await DB.execute<RowDataPacket[]>(query, data);
//   if (rows?.length > 0) return rows;
//   else return false;
// };

expenseDB.getTotalByClientIdAndPropId = async ({
  clientId,
  propId,
  month,
}: expensesTypes &
  expensesPropertyTypes & {
    month: string;
  }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and EP.propId = ? and  MONTH(E.dueDate) = MONTH(?)  and YEAR(E.dueDate) = YEAR(?) and E.isPaid = 1 order by E.id desc";
  const data = [clientId, propId, month, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getAllByClientIdAndPropId = async ({
  clientId,
  propId,
}: expensesTypes &
  expensesPropertyTypes & { pageNum: number; limit: number }) => {
  const query =
    "Select E.id, E.type, E.dueDate, E.expenseTitle, E.amount, E.balance, E.supportDoc, E.paidDate, E.paidByUserType, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name from Expenses as E inner join ExpensesProperty as EP on E.id = EP.expenseId inner join ExpenseTypes as ET on ET.id = E.type  where EP.clientId = ? and EP.propId = ? and E.isPaid = 1 order by E.id desc";
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPropId = async ({ propId }: expensesPropertyTypes) => {
  // const query =
  //   "Select E.id, E.type, E.amount,  E.paidDate, E.paidByUserType, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name from Expenses as E inner join ExpensesProperty as EP on E.id = EP.expenseId inner join ExpenseTypes as ET on ET.id = E.type  where EP.propId = ? order by E.id";
  // const data = [propId];
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.dueDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    propId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdForWeb = async ({ clientId }: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.assetId, E.bankRefNum, E.dueDate, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    clientId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getCurMonthExpense = async ({ clientId }: expensesPropertyTypes) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E where Month(E.dueDate)=Month(now()) and E.clientId = ? and E.isPaid = 1";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getCurMonthExpenseForStaff = async ({
  clientId,
  propertiesIds,
}: expensesPropertyTypes & { propertiesIds: string }) => {
  const query =
    "Select SUM(E.amount) as total from Expenses as E inner join ExpensesProperty as EP on EP.expenseId = E.id  where EP.propId in (" +
    `${propertiesIds}` +
    ") and Month(E.dueDate)=Month(now()) and E.clientId = ? and E.isPaid = 1";
  //const data = [propertiesIds, clientId];
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getExpenseCategories = async () => {
  const query =
    "Select EC.id, EC.name from ExpenseCategories as EC order by EC.priority desc";
  const [rows] = await DB.execute<RowDataPacket[]>(query);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getExpenseTypes = async ({ categoryId }: { categoryId: number }) => {
  const query =
    "Select EC.id, EC.name from ExpenseTypes as EC where EC.categoryId = ? order by EC.priority asc";
  const data = [categoryId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getProperties = async ({ expenseId }: expensesPropertyTypes) => {
  const query =
    "Select P.name, P.id  from ExpensesProperty as EP inner join Properties as P on P.id = EP.propId where EP.expenseId = ? order by EP.id desc";
  const data = [expenseId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getFlats = async ({ expenseId }: expensesPropertyTypes) => {
  const query =
    "Select F.name, F.id  from ExpensesProperty as EP inner join Flats as F on F.id = EP.flatId where EP.expenseId = ? order by EP.id desc";
  const data = [expenseId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPropAndType = async ({
  clientId,
  propId,
  type,
}: expensesPropertyTypes & expensesTypes) => {
  const query =
    "Select * from ExpensesProperty as EP inner join Expenses as E on E.id = EP.expenseId where EP.clientId = ? and EP.propId = ? and E.type = ?  order by EP.id desc limit 1";
  const data = [clientId, propId, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getLinkedProperties = async ({
  expenseId,
  clientId,
}: expensesPropertyTypes & expensesTypes) => {
  const query =
    "Select P.id, P.name, 1 as isLinked from ExpensesProperty as EP inner join Properties as P on P.id = EP.propId where EP.expenseId = ? and EP.clientId =? order by EP.id desc";
  const data = [expenseId, clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getLinkedChargesByPropIdandType = async ({
  propId,
  clientId,
  type,
}: expensesPropertyTypes & expensesTypes) => {
  const query =
    "Select P.id, P.name, 1 as isLinked from ExpensesProperty as EP inner join Properties as P on P.id = EP.propId inner join Expenses as E on E.id = EP.expenseId where EP.propId = ? and EP.clientId =? and E.type = ?  order by EP.id desc";
  const data = [propId, clientId, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.create = async ({
  type,
  amount,
  clientId,
  paidDate,
  paidByUserType,
  paidBy,
  paidTo,
  paidToUserType,
  description,
  paymentMethod,
  repetitionType,
  noOfMonths,
  dueDate,
  isPaid,
  bankRefNum = null,
  paymentAccountNo = null,
  paymentAccountName = null,
  assetId = null,
  expenseNature = CONSTANTS.EXPENSE_NATURE.OPERATING,
  expenseTitle=null,
}: expensesTypes) => {
  const query =
    "Insert into Expenses (type, amount, balance, clientId, paidDate, paidByUserType,  paidBy, paidTo, paidToUserType, description, paymentMethod, repetitionType, noOfMonths, dueDate, isPaid, bankRefNum, paymentAccountNo, paymentAccountName, assetId, expenseNature, expenseTitle) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)";
  const data = [
    type,
    amount,
    amount,
    clientId,
    paidDate,
    paidByUserType,
    paidBy,
    paidTo,
    paidToUserType,
    description,
    paymentMethod,
    repetitionType,
    noOfMonths,
    dueDate,
    isPaid,
    bankRefNum,
    paymentAccountNo,
    paymentAccountName,
    assetId,
    expenseNature,
    expenseTitle,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.update = async ({
  type,
  amount,
  balance,
  paidDate,
  paidByUserType,
  paidToUserType,
  paidBy,
  paidTo,
  description,
  paymentMethod,
  id,
  expenseTitle=null,
}: expensesTypes) => {
  const query =
    "Update Expenses set type = ?, amount = ?, balance = ?, paidDate = ?, paidByUserType = ?,  paidBy = ?, paidTo = ?, description = ?, paymentMethod = ?, paidToUserType = ?, expenseTitle = ? where id = ?";
  const data = [
    type,
    amount,
    balance,
    paidDate,
    paidByUserType,
    paidBy,
    paidTo,
    description,
    paymentMethod,
    paidToUserType,
    expenseTitle,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.updateExpenseNature = async ({
  expenseNature,
  id,
}: expensesTypes) => {
  const query =
    "Update Expenses set expenseNature = ? where id = ? limit 1";
  const data = [
    expenseNature,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};

expenseDB.addProperty = async ({
  clientId,
  propId,
  flatId=null,
  expenseId,
}: expensesPropertyTypes) => {
  const query =
    "Insert into ExpensesProperty (clientId, propId, flatId, expenseId) values (?,?,?,?)";
  const data = [clientId, propId, flatId, expenseId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.updateProperty = async ({
  clientId,
  propId,
  flatId=null,
  expenseId,
}: expensesPropertyTypes) => {
  const query =
    "Update ExpensesProperty set propId = ?,flatId = ? where clientId =? and expenseId = ?";
  const data = [propId, flatId, clientId, expenseId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.removeProperty = async ({
  clientId,
  propId,
  expenseId,
}: expensesPropertyTypes) => {
  const query =
    "Delete from ExpensesProperty where clientId = ? and propId = ? and expenseId = ?";
  const data = [clientId, propId, expenseId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.getMonthlyIncomeExpense = async ({ clientId, year, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 and YEAR(E.dueDate) = ? GROUP BY MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, 'income' AS type FROM  Transactions AS T WHERE T.clientId = ? AND status=? and YEAR(collectionDate) = ? GROUP BY MONTH(T.collectionDate)";
  const data = [clientId, year, clientId, status, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyIncomeExpenseWithoutSecurity = async ({ clientId, year, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 and YEAR(E.dueDate) = ? GROUP BY MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, 'income' AS type FROM Transactions AS T WHERE T.clientId = ? AND status=? and T.transactionFor != ? and amount > 0 and YEAR(collectionDate) = ? GROUP BY MONTH(T.collectionDate)";
  const data = [clientId, year, clientId, status, CONSTANTS.TRANSACTION_FOR.SECURITY, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyIncomeExpenseByDateRangeWithoutSecurity = async ({ clientId, startDate, endDate, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, YEAR(E.dueDate) as year, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? GROUP BY YEAR(E.dueDate), MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, YEAR(T.collectionDate) AS year, 'income' AS type FROM Transactions AS T WHERE T.clientId = ? AND status=? and T.transactionFor != ? and T.amount > 0 and DATE(T.collectionDate) BETWEEN ? and ? GROUP BY YEAR(T.collectionDate), MONTH(T.collectionDate)";
  const data = [clientId, startDate, endDate, clientId, status, CONSTANTS.TRANSACTION_FOR.SECURITY, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyIncomeExpenseByDateRangeWithoutSecurityForWeb = async ({ clientId, startDate, endDate, status, propIds, }: any) => {
  let query = "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, YEAR(E.dueDate) as year, 'expense' AS type FROM Expenses AS E left join ExpensesProperty as EP on EP.expenseId = E.id WHERE E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?" 

  const data = [clientId, startDate, endDate ];

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

  query += ` GROUP BY YEAR(E.dueDate), MONTH(E.dueDate)`
  
  query += " UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, YEAR(T.collectionDate) AS year, 'income' AS type FROM Transactions AS T WHERE T.clientId = ? AND status=? and T.transactionFor != ? and T.amount > 0 and DATE(T.collectionDate) BETWEEN ? and ? ";
  
  data.push(...[clientId, status, CONSTANTS.TRANSACTION_FOR.SECURITY, startDate, endDate]);

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

  query += ` GROUP BY YEAR(T.collectionDate), MONTH(T.collectionDate)`

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

expenseDB.getMonthlyIncomeExpenseByDateRange = async ({ clientId, startDate, endDate, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, YEAR(E.dueDate) as year, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? GROUP BY YEAR(E.dueDate), MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, YEAR(T.collectionDate) AS year, 'income' AS type FROM Transactions AS T WHERE T.clientId = ? AND status=? and T.amount > 0 and DATE(T.collectionDate) BETWEEN ? and ? GROUP BY YEAR(T.collectionDate), MONTH(T.collectionDate)";
  const data = [clientId, startDate, endDate, clientId, status, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyIncomeExpenseByDateRangeForProp = async ({ propId, startDate, endDate, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, YEAR(E.dueDate) as year, 'expense' AS type FROM Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? GROUP BY YEAR(E.dueDate), MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, YEAR(T.collectionDate) AS year, 'income' AS type FROM Transactions AS T WHERE T.propId = ? AND status=? and T.amount > 0 and DATE(T.collectionDate) BETWEEN ? and ? GROUP BY YEAR(T.collectionDate), MONTH(T.collectionDate)";
  const data = [propId, startDate, endDate, propId, status, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyIncomeExpenseForProp = async ({
  propId,
  year,
  status,
}: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, MONTH(E.dueDate) AS month, 'expense' AS type FROM Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? and E.isPaid = 1 and YEAR(E.dueDate) = ? GROUP BY MONTH(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, MONTH(T.collectionDate) AS month, 'income' AS type FROM  Transactions AS T WHERE T.propId = ? AND T.status=? and YEAR(T.collectionDate) = ? GROUP BY MONTH(T.collectionDate)";
  const data = [propId, year, propId, status, year];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getYearlyRentTransaction = async ({ clientId, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, YEAR(E.dueDate) AS year, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 GROUP BY YEAR(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, YEAR(T.createdAt) AS year, 'income' AS type FROM  Transactions AS T WHERE T.clientId = ? and status=? GROUP BY YEAR(T.createdAt);";
  const data = [clientId, clientId, status];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getYearlyRentTransactionWithoutSecurity = async ({ clientId, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, YEAR(E.dueDate) AS year, 'expense' AS type FROM Expenses AS E WHERE E.clientId = ? and E.isPaid = 1 GROUP BY YEAR(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, YEAR(T.createdAt) AS year, 'income' AS type FROM  Transactions AS T WHERE T.clientId = ? and status=? and T.transactionFor != ? and T.amount > 0 GROUP BY YEAR(T.createdAt);";
  const data = [clientId, clientId, status, CONSTANTS.TRANSACTION_FOR.SECURITY];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getYearlyRentTransactionWithoutSecurityForWeb = async ({ clientId, status, propIds, }: any) => {
  let query = "SELECT  SUM(E.amount) AS amount, YEAR(E.dueDate) AS year, 'expense' AS type FROM Expenses AS E left join ExpensesProperty as EP on EP.expenseId = E.id WHERE E.clientId = ? and E.isPaid = 1"

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

  query += ` GROUP BY YEAR(E.dueDate)`
  
  query += " UNION ALL SELECT SUM(T.amount) AS totalAmount, YEAR(T.createdAt) AS year, 'income' AS type FROM  Transactions AS T WHERE T.clientId = ? and status=? and T.transactionFor != ? and T.amount > 0 ";
  
  data.push(...[clientId, status, CONSTANTS.TRANSACTION_FOR.SECURITY]);

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

  query += ` GROUP BY YEAR(T.createdAt)`
  
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getYearlyRentTransactionForProp = async ({ propId, status }: any) => {
  const query =
    "SELECT  SUM(E.amount) AS amount, YEAR(E.dueDate) AS year, 'expense' AS type FROM Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? and E.isPaid = 1 GROUP BY YEAR(E.dueDate) UNION ALL SELECT SUM(T.amount) AS totalAmount, YEAR(T.collectionDate) AS year, 'income' AS type FROM  Transactions AS T WHERE T.propId = ? and T.status=? GROUP BY YEAR(T.collectionDate);";
  const data = [propId, propId, status];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.delete = async ({ clientId, expenseId }: expensesPropertyTypes) => {
  const query = "Delete from Expenses where clientId = ? and id = ? limit 1";
  const data = [clientId, expenseId];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.getSumForSpecificeExpensesByMonth = async ({
  clientId,
  year,
  month,
}: any) => {
  /*Building, Electricity, Salary*/
  const query =
    "SELECT (select if(sum(amount) is NULL, 0, sum(amount)) as amount from Expenses where type=1 and clientId=? and year(dueDate)=? and month(dueDate)=? and isPaid = 1) as buildingExpenses, (select if(sum(amount) is NULL, 0, sum(amount)) as amount from Expenses where type=2 and clientId=? and year(dueDate)=? and month(dueDate)=? and isPaid = 1) as electricityExpenses, (select if(sum(amount) is NULL, 0, sum(amount)) as amount from Expenses where type=14 and clientId=? and year(dueDate)=? and month(dueDate)=? and isPaid = 1) as salaryExpenses, (select if(sum(amount) is NULL, 0, sum(amount)) as amount from Expenses where clientId=? and year(dueDate)=? and month(dueDate)=? and isPaid = 1) as allExpenses";
  const data = [
    clientId,
    year,
    month,
    clientId,
    year,
    month,
    clientId,
    year,
    month,
    clientId,
    year,
    month,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getByPropIdandDateRange = async ({
  propId,
  startDate,
  endDate,
  sortBy,
}: expensesPropertyTypes & { startDate: string; endDate: string; sortBy: string }) => {
  let query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.assetId, E.bankRefNum, EP.propId, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId, EC.name as expenseCategoryName, ET.name as expenseTypeName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and E.isPaid = 1 ";
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
  ];

  if (sortBy && sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ? order by E.paidDate desc`;
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc`;
  }

  data.push(startDate);
  data.push(endDate);

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

expenseDB.getByPropIdandDateRangeAndTypeFilter = async ({
  propId,
  startDate,
  endDate,
  typeFilter,
  sortBy,
}: expensesPropertyTypes & { startDate: string; endDate: string; typeFilter: any; sortBy: string;}) => {
  let query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.assetId, E.bankRefNum, EP.propId, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId, EC.name as expenseCategoryName, ET.name as expenseTypeName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and E.isPaid = 1 ";
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
  ];

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

  if (sortBy && sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ? order by E.paidDate desc`;
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc`;
  }
  data.push(startDate);
  data.push(endDate);

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

expenseDB.getByPropIdandDateRangeDueDate = async ({
  propId,
  startDate,
  endDate,
  sortBy=null,
}: { propId: any; startDate: string; endDate: string; sortBy: string|null; }) => {
  let sortByFilter = `E.dueDate asc`;
  if (sortBy === "PD") {
    sortByFilter = `E.paidDate asc`;
  }
  const query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, EP.propId, EP.flatId, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId, EC.name as expenseCategoryName, ET.name as expenseTypeName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId in (${propId.map(() => '?').join(',')}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by ${sortByFilter}`;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    ...propId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getExpenseStatsForWeb = async ({ clientId, propId }: any) => {
  const query =
    "select if(totalExpenses is null, 0, totalExpenses) as totalExpenses, if(curMonthExpenses is null, 0, curMonthExpenses) as curMonthExpenses, if(todayExpenses is null, 0, todayExpenses) as todayExpenses, if(curMonthRentExpenses is null, 0, curMonthRentExpenses) as curMonthRentExpenses, if(curMonthSalaryExpenses is null, 0, curMonthSalaryExpenses) as curMonthSalaryExpenses, if(curMonthFoodExpenses is null, 0, curMonthFoodExpenses) as curMonthFoodExpenses from (select (select sum(amount) as totalExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and EP.propId = ?) as totalExpenses, (select sum(amount) as curMonthExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and EP.propId = ? and Month(E.dueDate) = Month(curdate())) as curMonthExpenses, (select sum(amount) as todayExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and EP.propId = ? and Date(E.dueDate) = Date(curdate())) as todayExpenses, (select sum(amount) as curMonthRentExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and EP.propId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthRentExpenses, (select sum(amount) as curMonthSalaryExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and EP.propId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthSalaryExpenses, (select sum(amount) as curMonthFoodExpenses from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and EP.propId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthFoodExpenses) as V";
  const data = [
    clientId,
    propId,
    clientId,
    propId,
    clientId,
    propId,
    clientId,
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    clientId,
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    clientId,
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getExpenseStatsByClientIdForWeb = async ({ clientId }: any) => {
  const query =
    "select if(totalExpenses is null, 0, totalExpenses) as totalExpenses, if(curMonthExpenses is null, 0, curMonthExpenses) as curMonthExpenses, if(todayExpenses is null, 0, todayExpenses) as todayExpenses, if(curMonthRentExpenses is null, 0, curMonthRentExpenses) as curMonthRentExpenses, if(curMonthSalaryExpenses is null, 0, curMonthSalaryExpenses) as curMonthSalaryExpenses, if(curMonthFoodExpenses is null, 0, curMonthFoodExpenses) as curMonthFoodExpenses from (select (select sum(amount) as totalExpenses from Expenses as E where E.clientId = ?) as totalExpenses, (select sum(amount) as curMonthExpenses from Expenses as E  where E.clientId = ? and Month(E.dueDate) = Month(curdate())) as curMonthExpenses, (select sum(amount) as todayExpenses from Expenses as E where E.clientId = ? and Date(E.dueDate) = Date(curdate())) as todayExpenses, (select sum(amount) as curMonthRentExpenses from Expenses as E join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthRentExpenses, (select sum(amount) as curMonthSalaryExpenses from Expenses as E join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthSalaryExpenses, (select sum(amount) as curMonthFoodExpenses from Expenses as E join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and ET.categoryId = ? and Month(E.dueDate) = Month(curdate())) as curMonthFoodExpenses) as V";
  const data = [
    clientId,
    clientId,
    clientId,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getExpenseStatsByClientIdAndDateRangeForWeb = async ({
  clientId,
  startDate,
  endDate,
  sortBy,
}: expensesTypes & {startDate: string; endDate: string; sortBy: string;}) => {

  let sortByFilter = "E.dueDate";
  if (sortBy === "PD") sortByFilter = "E.paidDate";

  const query = 
    `Select
    (Select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 1 and Date(${sortByFilter}) Between ? and ?) as totalExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and ET.categoryId = ? and Date(${sortByFilter}) Between ? and ? and E.type=1) as rentExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 1 and Date(${sortByFilter}) = curDate()) as todayExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 1 and E.type = ? and Date(${sortByFilter}) Between ? and ?) as dateRangeSecurityExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E  where E.clientId = ? and E.isPaid = 1 and E.type = ? and Date(${sortByFilter}) Between ? and ?) as staffSalaryExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 1 and E.type in (10, 11) and Date(${sortByFilter}) Between ? and ?) as emiExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 1 and E.paidToUserType = ? and Date(${sortByFilter}) Between ? and ? and E.type NOT IN (1, 43)) as vendorExpense`;
  
  const data = [
    clientId,
    startDate,
    endDate,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    startDate,
    endDate,
    clientId,
    clientId,
    43, //Building Security
    startDate,
    endDate,
    clientId,
    // CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    14, //Staff Salary
    startDate,
    endDate,
    clientId,
    startDate,
    endDate,
    clientId,
    CONSTANTS.USER_TYPE.VENDOR,
    startDate,
    endDate,
  ];

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

expenseDB.getExpenseStatsByPropIdAndDateRangeForWeb = async ({
  propId,
  startDate,
  endDate,
  sortBy,
}: expensesTypes & { propId: number; startDate: string; endDate: string; sortBy: string}) => {
  
  let sortByFilter = "E.dueDate";
  if (sortBy === "PD") sortByFilter = "E.paidDate";

  const query = 
    `Select
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and Date(${sortByFilter}) Between ? and ?) as totalExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on ET.id = E.type where E.type=1 and E.isPaid=1 and EP.propId = ? and E.isPaid = 1 and ET.categoryId = ? and Date(${sortByFilter}) Between ? and ?) as rentExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and Date(E.dueDate) = curDate()) as todayExpense,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and E.type = ? and Date(${sortByFilter}) Between ? and ?) as dateRangeSecurityExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and E.type = ? and Date(${sortByFilter}) Between ? and ?) as staffSalaryExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and E.type in (10, 11) and Date(${sortByFilter}) Between ? and ?) as emiExpense,
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.isPaid = 1 and E.paidToUserType = ? and Date(${sortByFilter}) Between ? and ? and E.type NOT IN (1, 43)) as vendorExpense`;
  
  const data = [
    propId,
    startDate,
    endDate,
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    startDate,
    endDate,
    propId,
    propId,
    43, //Building Security
    startDate,
    endDate,
    propId,
    // CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    14, //Staff Salary
    startDate,
    endDate,
    propId,
    startDate,
    endDate,
    propId,
    CONSTANTS.USER_TYPE.VENDOR,
    startDate,
    endDate,
  ];

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

expenseDB.getByPropIdForCurMonth = async ({
  propId,
}: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.isPaid = 1 and Month(E.dueDate) = Month(curdate()) order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    propId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdForCurMonth = async ({
  clientId,
}: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and Month(E.dueDate) = Month(curdate()) order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    clientId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPropIdForToday = async ({ propId }: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.type, E.amount, E.balance, E.supportDoc, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.isPaid = 1 and Date(E.dueDate) = Date(curdate()) order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    propId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdForToday = async ({ clientId }: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.type, E.bankRefNum, E.amount, E.balance, E.supportDoc, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and Date(E.dueDate) = Date(curdate()) order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR, 
    CONSTANTS.USER_TYPE.STAFF, 
    CONSTANTS.USER_TYPE.LANDLORD, 
    CONSTANTS.USER_TYPE.CLIENT, 
    clientId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getRentByPropIdForCurMonth = async ({
  propId,
}: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.isPaid = 1 and Month(E.dueDate) = Month(curdate()) and type = ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    1,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getSalaryByPropIdForCurMonth = async ({
  propId,
}: expensesPropertyTypes) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.isPaid = 1 and Month(E.dueDate) = Month(curdate()) and type = ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    14,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidByName = async ({
  propId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.assetId, E.repetitionType, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) like ? order by E.id desc";

  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    CONSTANTS.USER_TYPE.CLIENT,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToName = async ({
  propId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.assetId, E.expenseNature, E.expenseTitle, E.isPaid, E.repetitionType, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END like ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidByNameByClientId = async ({
  clientId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) like ? order by E.id desc";

  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.CLIENT,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToNameByClientId = async ({
  clientId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END like ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaymentMethod = async ({
  propId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.assetId, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and E.paymentMethod like ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndPaymentMethod = async ({
  clientId,
  searchVal,
}: expensesPropertyTypes & { searchVal: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and E.isPaid = 1 and E.paymentMethod like ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.updateSupportDoc = async ({ id, supportDoc }: expensesTypes) => {
  const query = "Update Expenses set supportDoc = ? where id = ? limit 1";
  const data = [supportDoc, id];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.getDailyExpenseForClientYearMonth = async ({
  clientId,
  year,
  month,
}: expensesTypes & { year: any; month: any }) => {
  const query =
    "Select DATE_FORMAT(dueDate, '%Y-%m-%d') AS date, sum(amount) as amount from Expenses where clientId = ? and YEAR(dueDate) = ? and MONTH(dueDate) = ? and isPaid = 1 group by date";
  const data = [clientId, year, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

// Not being used anywhere --Abhinav(2025-11-14)
expenseDB.getDailyExpenseForClientYearMonthAndCategory = async ({
  clientId,
  year,
  month,
  category,
}: expensesTypes & { year: any; month: any; category: any }) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? and E.isPaid = 1 group by date";
  const data = [clientId, category, year, month];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getDailyExpenseForClientYearMonthByCategory = async ({
  clientId,
  year,
  month,
}: expensesTypes & { year: any; month: any }) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount, EC.name as category from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? and E.isPaid = 1 group by date, EC.name";
  const data = [
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES, 
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    year, 
    month,
  ];

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

expenseDB.getMonthlyExpenseForClient = async ({
  clientId,
}: expensesTypes) => {
  const query =
    "Select sum(amount) as amount, MONTH(dueDate) as month, YEAR(dueDate) as year from Expenses where clientId=? and isPaid = 1 and dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseForClientByCategory = async ({
  clientId,
}: expensesTypes) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year, EC.name as category from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId=? and EC.id not in (?, ?, ?) and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year, EC.name Order by year desc, month desc";
  const data = [
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES, 
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getDailyExpenseByPropIdYearMonth = async ({
  propId,
  year,
  month,
}: {
  propId: any;
  year: any;
  month: any;
}) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId = ? and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? and isPaid = 1 group by date";
  const data = [
    propId,
    year,
    month,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getDailyExpenseByPropIdYearMonthCategory = async ({
  propId,
  year,
  month,
}: {
  propId: any;
  year: any;
  month: any;
}) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount, EC.name as category from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? and isPaid = 1 group by date, EC.name";
  const data = [
    propId,
    year,
    month,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseByPropId = async ({
  propId,
}: {
  propId: any;
}) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId=? and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseByPropIdCategory = async ({
  propId,
}: {
  propId: any;
}) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year, EC.name as category from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId=? and EC.id not in (?, ?, ?) and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year, EC.name Order by year desc, month desc";
  const data = [
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getDailyExpenseForStaffYearMonth = async ({
  clientId,
  propertiesIds,
  year,
  month,
}: expensesTypes & {
  clientId: any;
  propertiesIds: string;
  year: any;
  month: any;
}) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ") and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? group by date";
  const data = [
    clientId,
    year,
    month,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getDailyExpenseForStaffYearMonthByCategory = async ({
  clientId,
  propertiesIds,
  year,
  month,
}: expensesTypes & {
  clientId: any;
  propertiesIds: string;
  year: any;
  month: any;
}) => {
  const query =
    "Select DATE_FORMAT(E.dueDate, '%Y-%m-%d') AS date, SUM(E.amount) as amount, EC.name as category from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and E.isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ") and YEAR(E.dueDate) = ? and MONTH(E.dueDate) = ? group by date, EC.name";
  const data = [
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES, 
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    year,
    month,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseForStaff = async ({
  clientId,
  propertiesIds,
}: expensesTypes & { clientId: any; propertiesIds: string }) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId=? and isPaid = 1 and EP.propId in (" +
    `${propertiesIds}` +
    ") and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getByTypeAndClientId = async ({
  clientId,
  type,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndOthers = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByTypeAndClientIdForStaff = async ({
  clientId,
  type,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propertiesIds: string }) => {
  const query =
    "Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and EP.propId in ("+`${propertiesIds}`+") and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndOthersForStaff = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propertiesIds: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseNature, E.expenseTitle, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and EP.propId in ("+`${propertiesIds}`+") and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidTo = async ({
  clientId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; month: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type INNER JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    paidTo,
    paidToUserType,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToWithoutClientId = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; month: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndDateRangeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndDateRangeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? AND E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndDateRangeAndTypeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
  type,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndDateRangeAndTypeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
  type,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getOtherExpenseByPaidToAndDateRangeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type not in (?, ?) and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    1, //Rent
    43, //Security
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getOtherExpenseByPaidToAndDateRangeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type not in (?, ?) and DATE(E.paidDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    1, //Rent
    43, //Security
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidByPaidToAndDateRangeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  // const query =
  //   "Select E.id, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  // const data = [
  //   CONSTANTS.USER_TYPE.VENDOR,
  //   CONSTANTS.USER_TYPE.STAFF,
  //   CONSTANTS.USER_TYPE.LANDLORD,
  //   CONSTANTS.USER_TYPE.CLIENT,
  //   CONSTANTS.USER_TYPE.CLIENT,
  //   paidTo,
  //   paidToUserType,
  //   startDate,
  //   endDate,
  //   `${offset}`,
  //   `${limit}`,
  // ];
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidByPaidToAndDateRangeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidByPaidToAndDateRangeAndTypeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
  type,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidByPaidToAndDateRangeAndTypeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
  type,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidOtherExpenseByPaidToAndDateRangeForLandlord = async ({
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and E.type not in (?, ?) and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    paidTo,
    paidToUserType,
    1, //Rent
    43, //Security
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnPaidOtherExpenseByPaidToAndDateRangeForLandlordAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, if(E.paidByUserType = ?, (select mobile from Clients where id = E.paidBy), (select mobile from Staffs where id = E.paidBy)) as paidByMobile from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0 and E.type not in (?, ?) and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    paidTo,
    paidToUserType,
    1, //Rent
    43, //Security
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToWeb = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes & { month: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type INNER JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    paidTo,
    paidToUserType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndDateRange = async ({
  clientId,
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type LEFT JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndSearchVal = async ({
  clientId,
  paidTo,
  paidToUserType,
  limit,
  pageNum,
  searchVal,
}: expensesTypes & { pageNum: number; limit: number; month: string; searchVal: any }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type INNER JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and P.name like ? and E.isPaid = 1 order by E.id desc  limit ?, ?";
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    paidTo,
    paidToUserType,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPaidToAndSearchValWeb = async ({
  clientId,
  paidTo,
  paidToUserType,
  searchVal,
}: expensesTypes & { month: string; searchVal: any }) => {
  const query =
    "Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propName, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type INNER JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and P.name like ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    paidTo,
    paidToUserType,
    `%${searchVal}%`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getMonthlyExpenseForClientAndCategory = async ({
  clientId,
  category,
}: expensesTypes & { category: number }) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId=? and EC.id = ? and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [
    clientId,
    category,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseByPropIdAndCategory = async ({
  propId,
  category,
}: expensesTypes & { category: number; propId: number }) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id  where EP.propId = ? and EC.id = ? and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [
    propId,
    category,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getMonthlyExpenseForClientAndCategoryForStaff = async ({
  clientId,
  category,
  propertiesIds,
}: expensesTypes & { category: number; propertiesIds: string; }) => {
  const query =
    "Select SUM(E.amount) as amount, MONTH(E.dueDate) as month, YEAR(E.dueDate) as year from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId=? and EC.id = ? and EP.propId in ("+`${propertiesIds}`+") and E.isPaid = 1 and E.dueDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) Group By month, year Order by year desc, month desc";
  const data = [
    clientId,
    category,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getInitialValuesForList = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & {startDate: string; endDate:string}) => {
  const query = 
    "Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND DATE(E.dueDate) BETWEEN ? AND ? THEN E.balance ELSE 0 END), 0) AS amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E right join ExpenseTypes as ET on E.type = ET.id right join ExpenseCategories as EC on ET.categoryId = EC.id group by EC.id, EC.name order by amount desc";
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getInitialValuesForListStaff = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & {startDate: string; endDate:string; propertiesIds: string}) => {
  const query = 
    "Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND DATE(E.dueDate) BETWEEN ? AND ? and EP.propId in ("+`${propertiesIds}`+") THEN E.balance ELSE 0 END), 0) as amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id group by EC.id, EC.name order by amount desc";
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getByPropIdAndTypeForCurMonth = async ({
  propId,
  categoryId,
}: expensesPropertyTypes & {categoryId: number}) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseNature, E.expenseTitle, E.bankRefNum, E.type, E.amount, E.balance, E.supportDoc, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where EP.propId = ? and Month(E.dueDate) = Month(curdate()) and ET.categoryId = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    categoryId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndTypeForCurMonth = async ({
  clientId,
  categoryId,
}: expensesPropertyTypes & {categoryId: number}) => {
  const query =
    "Select E.id, E.repetitionType, E.expenseNature, E.expenseTitle, E.type, E.bankRefNum, E.amount, E.balance, E.supportDoc, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type where E.clientId = ? and Month(E.dueDate) = Month(curdate()) and ET.categoryId = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    categoryId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getTotalByPaidTo = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes & { month: string }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc";
  const data = [
    clientId,
    paidTo,
    paidToUserType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalByPaidToAndDateRange = async ({
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.paidDate) BETWEEN ? and ?";
  const data = [
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getTotalByPaidToAndDateRangeByDueDate = async ({
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?";
  const data = [
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getTotalByPaidToAndTypeAndDateRange = async ({
  paidTo,
  paidToUserType,
  type,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  let query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.type = ? and E.paidToUserType = ? and E.isPaid = 1 ";
  const data: any = [
    paidTo,
    type,
    paidToUserType,
    // startDate,
    // endDate,
  ];

  if (startDate && endDate) {
    query += ` and DATE(E.paidDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

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


expenseDB.getPaidExpensesTotalByClientAndType = async ({
  clientId,
  paidTo,
  paidToUserType,
  type,
}: expensesTypes ) => {
  let query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.type = ? and E.paidToUserType = ? and E.isPaid = 1";
  const data: any = [
    clientId,
    paidTo,
    type,
    paidToUserType,
    // startDate,
    // endDate,
  ];

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


expenseDB.getTotalByPaidToAndTypeAndDateRangeDueDate = async ({
  paidTo,
  paidToUserType,
  type,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  let query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.type = ? and E.paidToUserType = ? and E.isPaid = 1 ";
  const data: any = [
    paidTo,
    type,
    paidToUserType,
    // startDate,
    // endDate,
  ];

  if (startDate && endDate) {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

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

expenseDB.getTotalUnpaidByPaidToAndTypeAndDateRange = async ({
  paidTo,
  paidToUserType,
  type,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.type = ? and E.paidToUserType = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ?";
  const data = [
    paidTo,
    type,
    paidToUserType,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getTotalUnpaidOtherDuesAndDateRange = async ({
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.paidTo = ? and E.type NOT IN (1, 43) and E.paidToUserType = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ?";
  const data = [
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getPropertyByExpenseId = async ({
  expenseId,
}: expensesPropertyTypes) => {
  const query = "Select * from ExpensesProperty where expenseId = ?";
  const data = [expenseId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getByClientIdAndDateRangeAndPropFilter = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propIds
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndDateRangeAndCategoryFilter = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  categories,
  type,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id in (${categories}) and E.isPaid = 1 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getVendorExpenseByClientIdAndDateRange = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string;}) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? and ET.id NOT IN (1, 43) order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.VENDOR,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getEMIExpenseByClientIdAndDateRange = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string;}) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.type in (?, ?) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    10, // EMI Type
    11, //Loan EMI type
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByPropIdAndDateRangeAndCategoryFilter = async ({
  propId,
  limit,
  pageNum,
  startDate,
  endDate,
  categories,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.bankRefNum, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and EC.id in (${categories}) and E.type=1 and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getVendorExpenseByPropIdAndDateRange = async ({
  propId,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? and ET.id NOT IN (1, 43) order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    CONSTANTS.USER_TYPE.VENDOR,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getEMIExpenseByPropIdAndDateRange = async ({
  propId,
  limit,
  pageNum,
  startDate,
  endDate,
}: expensesTypes & { propId: number; pageNum: number; limit: number; startDate: string; endDate: string; }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where EP.propId = ? and E.type in (?, ?) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    10, //EMI type
    11, // Loan EMI type
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.markPaid = async ({
  id,
  paidDate,
  paymentMethod,
  amount,
  paidBy,
  paidByUserType,
}: expensesTypes) => {
  const query = 
    `Update Expenses set amount = ?, balance = ?, paidDate = ?, paymentMethod = ?, paidBy = ?, paidByUserType = ?, isPaid = 1 where id = ? limit 1`;
  const data = [
    amount,
    amount,
    paidDate,
    paymentMethod,
    paidBy,
    paidByUserType,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.getByClientIdAndDateRangeAndPropFilterForStaff = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
  propIds
}: expensesTypes & {
  pageNum: number;
  limit: number;
  startDate: string;
  endDate: string;
  propertiesIds: string;
  propIds: any;
}) => {
  const query =
    `Select E.id, E.isPaid, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.paidByUserType, E.paidToUserType, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (${propIds}) and E.isPaid = 1 and EP.propId in (${propertiesIds}) order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndDateRangeAndCategoryFilterForStaff = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
  categories,
  type,
}: expensesTypes & {
  pageNum: number;
  limit: number;
  startDate: string;
  endDate: string;
  propertiesIds: string;
  categories: any;
}) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.paidByUserType, E.paidToUserType, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and DATE(E.dueDate) BETWEEN ? and ? and EC.id in (${categories}) and E.type = ? and E.isPaid = 1 and EP.propId in (${propertiesIds}) order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    //propertiesIds,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByTypeAndClientIdAndPropFilter = async ({
  clientId,
  type,
  limit,
  pageNum,
  startDate,
  endDate,
  propIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndOthersAndPropFilter = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByTypeAndClientIdAndPropFilterForStaff = async ({
  clientId,
  type,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
  propIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propertiesIds: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and EP.propId in (${propertiesIds}) and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getByClientIdAndOthersAndPropFilterForStaff = async ({
  clientId,
  limit,
  pageNum,
  startDate,
  endDate,
  propertiesIds,
  propIds
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propertiesIds: string; propIds: any; }) => {
  const query =
    `Select E.id, E.repetitionType, E.supportDoc, E.expenseTitle, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and EP.propId in (${propertiesIds}) and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientId = async ({
  clientId,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.assetId, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 order by E.dueDate asc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndDateFilter = async ({
  clientId,
  startDate,
  endDate,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.assetId, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? order by E.dueDate asc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndFilters = async ({
  clientId,
  limit,
  pageNum,
  typeFilter,
}: expensesTypes & { pageNum: number; limit: number; typeFilter: any; }) => {
  let query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseNature, E.expenseTitle, E.assetId, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 `;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
  ];

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

  query += ` order by E.dueDate 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;
};


expenseDB.getUnMarkedByClientIdBypaidByName = async ({
  clientId,
  searchVal,
}: expensesTypes & { searchVal: string;}) => {
  let query =`select * from (Select E.id, E.expenseNature, E.expenseTitle, E.assetId, E.isPaid, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0) as v where paidToName like ?  order by dueDate desc`;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `%${searchVal}%`
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdBypaidToMobile = async ({
  clientId,
  searchVal,
}: expensesTypes & { searchVal: string;}) => {
  let query =`select * from (Select E.id, E.expenseNature, E.expenseTitle, E.assetId, E.isPaid, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, CASE WHEN E.paidToUserType = ? THEN (select mobile from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select mobile from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select mobile from Landlords where id = E.paidTo) END as paidToMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0) as v where paidToMobile like ?  order by dueDate desc`;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `%${searchVal}%`
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndPropId = async ({
  clientId,
  propId,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categories: any; propId: any; }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.assetId, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndPropIdAndFilters = async ({
  clientId,
  propId,
  limit,
  pageNum,
  typeFilter,
}: expensesTypes & { pageNum: number; limit: number; typeFilter: any; propId: any; }) => {
  let query =
    `Select E.id, E.isPaid, E.expenseNature, E.assetId, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and E.isPaid = 0 `;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
  ];

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

  query += ` order by E.dueDate 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;
};

expenseDB.getCountUnMarkedByClientId = async ({
  clientId,
}: expensesTypes) => {
  const query =
    `Select count(*) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 order by E.dueDate desc`;
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getCountUnMarkedByClientIdAndPropId = async ({
  clientId,
  propId,
}: expensesTypes & {propId: any;}) => {
  const query =
    `Select count(*) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and E.isPaid = 0 order by E.dueDate desc`;
  const data = [
    clientId,
    propId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getCountUnMarkedByClientIdForLandlord = async ({
  clientId,
}: expensesTypes) => {
  const query =
    `Select count(*) as count from Expenses as E  where E.clientId = ? and E.isPaid = 0 and E.PaidToUserType=?`;
  const data = [
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].count;
  else return 0;
};

expenseDB.getUnMarkedByCategoryAndClientId = async ({
  clientId,
  startDate,
  endDate,
  categoryFilter,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categoryFilter: any }) => {
  let query =
    `Select E.id, E.isPaid, E.expenseNature, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? `;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
  ];

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

  query += ` order by E.dueDate 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;
};

expenseDB.getUnMarkedByCategoryAndClientIdForStaff = async ({
  clientId,
  categoryFilter,
  startDate,
  endDate,
  limit,
  pageNum,
  propertiesIds,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; categoryFilter: any; propertiesIds: any; }) => {
  let query =
    `Select E.id, E.isPaid, E.expenseNature, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (${propertiesIds}) `;
  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
  ];

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

  query += ` order by E.dueDate 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;
};

expenseDB.getUnMarkedByTypeAndClientId = async ({
  clientId,
  type,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByTypeAndClientIdAndPropId = async ({
  clientId,
  propId,
  type,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select E.id, E.isPaid E.repetitionType, E.supportDoc, E.type, E.expenseTitle, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and EC.id = ? and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
    type,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndOthers = async ({
  clientId,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndPropIdAndOthers = async ({
  clientId,
  propId,
  limit,
  pageNum,
}: expensesTypes & { pageNum: number; limit: number; startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and EC.id not in (?, ?, ?) and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getTotalByClientIdAndDateRangeAndPropFilter = async ({
  clientId,
  startDate,
  endDate,
  propIds,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propIds}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getInitialValuesForListPropFilter = async ({
  clientId,
  startDate,
  endDate,
  propIds,
}: expensesTypes & {startDate: string; endDate:string; propIds: any}) => {
  const query = 
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND EP.propId in (${propIds}) AND DATE(E.dueDate) BETWEEN ? AND ? THEN E.balance ELSE 0 END), 0) AS amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E right join ExpenseTypes as ET on E.type = ET.id right join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id group by EC.id, EC.name order by amount desc`;
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getTotalUnMarkedByClientId = async ({
  clientId,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and E.isPaid = 0`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalUnMarkedByClientIdAndTypeAndDateRange = async ({
  clientId,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    `Select IFNULL(SUM(E.amount), 0) as total from Expenses as E where E.clientId = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalUnMarkedByClientIdAndTypeAndDateRangeForWeb = async ({
  clientId,
  propIds,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any; }) => {
  let query =
    `Select IFNULL(SUM(E.amount), 0) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];

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

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

expenseDB.getTotalUnMarkedByPropIdAndTypeAndDateRange = async ({
  propId,
  startDate,
  endDate,
  type,
}: expensesTypes & { propId: number; startDate: string; endDate: string; }) => {
  const query =
    `Select IFNULL(SUM(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [propId, type, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalUnMarkedByClientIdAndPropId = async ({
  clientId,
  propId,
}: expensesTypes & { startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select IFNULL(SUM(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId = ? and E.isPaid = 0`;
  const data = [clientId, propId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getInitialValuesForListForUnMarked = async ({
  clientId,
}: expensesTypes) => {
  const query = 
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 0 THEN E.balance ELSE 0 END), 0) AS amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E right join ExpenseTypes as ET on E.type = ET.id right join ExpenseCategories as EC on ET.categoryId = EC.id group by EC.id, EC.name`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getUnMarkedByTypeAndClientIdForStaff = async ({
  clientId,
  type,
  limit,
  pageNum,
  propertiesIds,
}: expensesTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    type,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndOthersForStaff = async ({
  clientId,
  limit,
  pageNum,
  propertiesIds,
}: expensesTypes & { pageNum: number; limit: number; propertiesIds: string; }) => {
  const query =
    `Select E.id, E.repetitionType, E.expenseNature, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id not in (?, ?, ?) and EP.propId in (${propertiesIds}) and E.isPaid = 0 order by E.dueDate desc  limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.EXPENSE_CATEGORIES.RENT_UTILITIES,
    CONSTANTS.EXPENSE_CATEGORIES.FOOD_SUPPLIES,
    CONSTANTS.EXPENSE_CATEGORIES.STAFF_WAGES,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getUnMarkedByClientIdAndDateRangeAndPropFilterForStaff = async ({
  clientId,
  startDate,
  endDate,
  limit,
  pageNum,
  propertiesIds,
}: expensesTypes & {
  pageNum: number;
  limit: number;
  propertiesIds: string;
  startDate: string;
  endDate: string;
}) => {
  const query =
    `Select E.id, E.isPaid, E.expenseNature, E.expenseTitle, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.paidByUserType, E.paidToUserType, E.createdAt, ET.name, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (${propertiesIds}) order by E.dueDate desc limit ?, ?`;
  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
    `${offset}`,
    `${limit}`,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};


expenseDB.getCountUnMarkedByClientIdAndDateRangeAndPropFilterForStaff = async ({
  clientId,
  propertiesIds,
}: expensesTypes & {
  propertiesIds: string;
}) => {
  const query =
    `Select count(*) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and EP.propId in (${propertiesIds})`;
  const data = [
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getCountUnMarkedLandlordExpensePropFilterForStaff = async ({
  clientId,
  propertiesIds,
}: expensesTypes & {
  propertiesIds: string;
}) => {
  const query =
    `Select count(*) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 0 and EP.propId in (${propertiesIds}) and E.paidToUserType=?`;
  const data = [
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getTotalByClientIdAndDateRangeAndPropFilterForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
  propIds,
}: expensesTypes & { propertiesIds: string; startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (${propertiesIds}) and EP.propId in (${propIds})`;
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getUnMarkedTotalByClientIdForStaff = async ({
  clientId,
  propertiesIds,
}: expensesTypes & { propertiesIds: string; }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId where E.clientId = ? and EP.propId in (${propertiesIds})`;
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getInitialValuesForListStaffPropFilter = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
  propIds,
}: expensesTypes & {startDate: string; endDate:string; propertiesIds: string; propIds: any}) => {
  const query = 
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND DATE(E.dueDate) BETWEEN ? AND ? and EP.propId in (${propertiesIds}) and EP.propId in (${propIds}) THEN E.balance ELSE 0 END), 0) as amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id group by EC.id, EC.name order by amount desc`;
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getInitialValuesForListStaffUnMarked = async ({
  clientId,
  propertiesIds,
}: expensesTypes & {startDate: string; endDate:string; propertiesIds: string; propIds: any}) => {
  const query = 
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and EP.propId in (${propertiesIds}) THEN E.balance ELSE 0 END), 0) as amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E join ExpenseTypes as ET on E.type = ET.id join ExpenseCategories as EC on ET.categoryId = EC.id join ExpensesProperty as EP on EP.expenseId = E.id group by EC.id, EC.name`;
  const data = [clientId];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return [];
};

expenseDB.getTotalByClientIdAndDateRangeAndCategoryFilter = async ({
  clientId,
  startDate,
  endDate,
  categories,
}: expensesTypes & { startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EC.id in (${categories}) and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

//not being used --2025-12-01
expenseDB.getTotalByClientIdAndDateRangeAndCategoryFilterForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
  categories,
}: expensesTypes & { propertiesIds: string; startDate: string; endDate: string; categories: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and DATE(E.dueDate) BETWEEN ? and ? and EP.propId in (${propertiesIds}) and EC.id in (${categories}) and E.isPaid = 1`;
  //const data = [clientId, month, month, propertiesIds];
  const data = [clientId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.isUnPaidExistByClientId = async ({
  clientId,
}: expensesTypes) => {
  const query = 
    `Select * from Expenses where clientId = ? and isPaid = 0`;
  const data = [
    clientId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return true;
  else return false;  
};

expenseDB.isUnPaidExistByClientIdForStaff = async ({
  clientId,
  propertiesIds
}: expensesTypes & {propertiesIds: any}) => {
  const query = 
    `Select E.* from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.isPaid = 0 and EP.propId in (${propertiesIds})`;
  const data = [
    clientId
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return true;
  else return false;  
};

expenseDB.updateRecurringExpenseId = async ({
  id,
  recurringExpenseId,
}: expensesTypes) => {
  const query =
    "Update Expenses set recurringExpenseId = ? where id = ?";
  const data = [
    recurringExpenseId,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.isStaffSalaryAddedForToday = async ({
  paidTo,
}: expensesTypes & {propertiesIds: any}) => {
  const query = 
    `Select * from Expenses where type = 14 and paidTo = ? and DATE(createdAt) = CURDATE()`;
  const data = [
    paidTo,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return true;
  else return false;  
};

expenseDB.getTotalByClientIdAndDateRangeAndType = async ({
  clientId,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and E.type = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndDateRangeAndTypeForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propertiesIds: string }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.type = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndTypeForWeb = async ({
  clientId,
  propIds,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.type = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];

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

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

expenseDB.getTotalByClientIdAndTypeForWebStaff = async ({
  clientId,
  propIds,
  propertiesIds,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propertiesIds: string; propIds: any }) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.type = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, type, startDate, endDate];

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

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

expenseDB.getTotalByClientIdAndPropIdAndDateRangeAndType = async ({
  clientId,
  propId,
  startDate,
  endDate,
  type,
}: expensesTypes & { startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId = ? and E.type = ? and E.isPaid = 1 and DATE(E.dueDate) BETWEEN ? and ?`;
  const data = [clientId, propId, type, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getExpenseByDateRangeAndPropForClient = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & {startDate: any; endDate: any}) => {
  const query = `Select SUM(E.amount) as totalExpense, ET.propId as propId, P.name as propName from Expenses as E join ExpensesProperty as ET on E.id = ET.expenseId join Properties as P on P.id = ET.propId where E.isPaid = 1 and E.clientId = ? and Date(E.dueDate) Between ? and ? group by ET.propId`;
  const data = [
    clientId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getExpenseByMonthForProp = async ({
  clientId,
  propId,
  startDate,
  endDate,
}: expensesTypes & {startDate: any; endDate: any; propId: any}) => {
  const query = `Select SUM(E.amount) as totalExpense, Month(E.dueDate) as month, Year(E.dueDate) as year, EP.propId as propId, P.name as propName from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join Properties as P on P.id = EP.propId where E.clientId = ? and E.isPaid=1 and EP.propId = ? and Date(E.dueDate) Between ? and ? group by Month(E.dueDate), Year(E.dueDate), EP.propId, P.name order by Month(E.dueDate), Year(E.dueDate)`;
  const data = [
    clientId,
    propId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows;
  else return false;
};

expenseDB.getTotalByDateRangeForProp = async ({
  propId,
  startDate,
  endDate,
}: expensesTypes & {startDate: any; endDate: any; propId: any}) => {
  const query = `Select SUM(E.amount) as totalExpense from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join Properties as P on P.id = EP.propId where E.isPaid=1 and EP.propId = ? and Date(E.dueDate) Between ? and ?`;
  const data = [
    propId,
    startDate,
    endDate,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].totalExpense;
  else return 0;
};

expenseDB.getByClientIdandDateRangeAndFilters = async ({
  clientId,
  startDate,
  endDate,
  limit,
  pageNum,
  propIds,
  categories,
  types,
  staffs,
  sortBy,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  categories: any[];
  types: any[];
  propIds: any[];
  staffs: any[];
  sortBy: string;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 `;

  const offset: number = (pageNum - 1) * limit;
  const data: any = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
  ];

  if (sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ?`
    data.push(startDate);
    data.push(endDate);
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`
    data.push(startDate);
    data.push(endDate);
  }

  if (propIds && propIds.length > 0) {
    query += ` and EP.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }
  if (categories && categories.length > 0) {
    query += ` and EC.id in (${categories.map(() => '?').join(',')})`;
    data.push(...categories);
  }
  if (types && types.length > 0) {
    query += ` and E.type in (${types.map(() => '?').join(',')})`;
    data.push(...types);
  }
  if (staffs && staffs.length > 0) {
    query += ` and E.paidByUserType = ? and E.paidBy in (${staffs.map(() => '?').join(',')})`;
    data.push(CONSTANTS.USER_TYPE.STAFF, ...staffs);
  }

  if (sortBy === "PD") {
    query += ` order by E.paidDate desc limit ?, ?`
    data.push(`${offset}`);
    data.push(`${limit}`);
  } else {
    query += ` order by E.dueDate desc limit ?, ?`
    data.push(`${offset}`);
    data.push(`${limit}`);
  }

  //log.info(`Expense query [${mysql.format(query, data)}]`);


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

expenseDB.getTotalByClientIdandDateRangeAndFilters = async ({
  clientId,
  startDate,
  endDate,
  propIds,
  categories,
  types,
  staffs,
  sortBy,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  categories: any[];
  types: any[];
  propIds: any[];
  staffs: any[];
  sortBy: string;
}) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 `;

  const data: any = [
    clientId,
  ];

  if (sortBy === "PD") {
    query += ` and DATE(E.paidDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  } else {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate);
    data.push(endDate);
  }

  if (propIds && propIds.length > 0) {
    query += ` and EP.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }
  if (categories && categories.length > 0) {
    query += ` and EC.id in (${categories.map(() => '?').join(',')})`;
    data.push(...categories);
  }
  if (types && types.length > 0) {
    query += ` and E.type in (${types.map(() => '?').join(',')})`;
    data.push(...types);
  }
  if (staffs && staffs.length > 0) {
    query += ` and E.paidByUserType = ? and E.paidBy in (${staffs.map(() => '?').join(',')})`;
    data.push(CONSTANTS.USER_TYPE.STAFF, ...staffs);
  }

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

expenseDB.getInitialValuesByClientIdandDateRangeAndFilters = async ({
  clientId,
  startDate,
  endDate,
  propIds,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  propIds: any[];
}) => {
  let query =
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND DATE(E.dueDate) BETWEEN ? AND ?`;

  const data = [
    clientId,
    startDate,
    endDate,
  ];

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

  query += ` THEN E.balance ELSE 0 END), 0) AS amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id group by EC.id, EC.name order by amount desc`

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

expenseDB.getByClientIdandDateRangeAndFiltersForStaff = async ({
  clientId,
  startDate,
  endDate,
  limit,
  pageNum,
  propIds,
  categories,
  propertiesIds,
  types,
  staffs,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  categories: any[];
  propIds: any[];
  types: any[];
  staffs: any[];
  propertiesIds: any;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 and EP.propId in (${propertiesIds}) and DATE(E.dueDate) BETWEEN ? and ?`;

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    startDate,
    endDate,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and EP.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }
  if (categories && categories.length > 0) {
    query += ` and EC.id in (${categories.map(() => '?').join(',')})`;
    data.push(...categories);
  }
  if (types && types.length > 0) {
    query += ` and E.type in (${types.map(() => '?').join(',')})`;
    data.push(...types);
  }
  if (staffs && staffs.length > 0) {
    query += ` and E.paidByUserType = ? and E.paidBy in (${staffs.map(() => '?').join(',')})`;
    data.push(CONSTANTS.USER_TYPE.STAFF, ...staffs);
  }

  query += ` order by E.dueDate 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;
};

expenseDB.getTotalByClientIdandDateRangeAndFiltersForStaff = async ({
  clientId,
  startDate,
  endDate,
  propIds,
  categories,
  propertiesIds,
  types,
  staffs,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  categories: any[];
  propIds: any[];
  propertiesIds: any;
  types: any[];
  staffs: any[];
}) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.isPaid = 1 and EP.propId in (${propertiesIds}) and DATE(E.dueDate) BETWEEN ? and ?`;

  const data = [
    clientId,
    startDate,
    endDate,
  ];

  if (propIds && propIds.length > 0) {
    query += ` and EP.propId in (${propIds.map(() => '?').join(',')})`;
    data.push(...propIds);
  }
  if (categories && categories.length > 0) {
    query += ` and EC.id in (${categories.map(() => '?').join(',')})`;
    data.push(...categories);
  }
  if (types && types.length > 0) {
    query += ` and E.type in (${types.map(() => '?').join(',')})`;
    data.push(...types);
  }
  if (staffs && staffs.length > 0) {
    query += ` and E.paidByUserType = ? and E.paidBy in (${staffs.map(() => '?').join(',')})`;
    data.push(CONSTANTS.USER_TYPE.STAFF, ...staffs);
  }

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

expenseDB.getInitialValuesByClientIdandDateRangeAndFiltersForStaff = async ({
  clientId,
  startDate,
  endDate,
  propIds,
  propertiesIds,
}: expensesTypes & {
  startDate: string;
  endDate: string;
  limit: number;
  pageNum: number;
  propIds: any[];
  propertiesIds: any;
}) => {
  let query =
    `Select COALESCE(SUM(CASE WHEN E.clientId = ? and E.isPaid = 1 AND EP.propId in (${propertiesIds}) AND DATE(E.dueDate) BETWEEN ? AND ?`;

  const data = [
    clientId,
    startDate,
    endDate,
  ];

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

  query += ` THEN E.balance ELSE 0 END), 0) AS amount, EC.name as expenseCategoryName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id group by EC.id, EC.name order by amount desc`

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

expenseDB.markSecuityAsRefunded = async ({
  id,
  balance,
  description
}: expensesTypes) => {
  const query = `Update Expenses set balance = balance - ?, description = CONCAT(COALESCE(description, ''), ?) where id = ?`;
  const data = [
    balance,
    description,
    id
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return true;
};
//Not being used
expenseDB.getTotalByClientIdAndType = async ({
  clientId,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join Vendors as V on V.id = E.paidTo where E.clientId = ? and V.type = ? and E.type = ? and E.isPaid = 1`;
  const data = [clientId, CONSTANTS.VENDOR_TYPES.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};
//Not being used
expenseDB.getTotalByPropIdAndType = async ({
  propId,
  type,
}: expensesTypes & { startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseID join Vendors as V on V.id = E.paidTo where EP.propId = ? and V.type = ? and E.type = ? and E.isPaid = 1`;
  const data = [propId, CONSTANTS.VENDOR_TYPES.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};
//Not being used
expenseDB.getTotalByClientIdAndTypeForStaff = async ({
  clientId,
  type,
  propertiesIds,
}: expensesTypes & { propertiesIds: any; }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join Vendors as V on V.id = E.paidTo where E.clientId = ? and V.type = ? and E.type = ? and E.isPaid = 1 and EP.propId in (${propertiesIds})`;
  const data = [clientId, CONSTANTS.VENDOR_TYPES.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndTypeForLandlord = async ({
  clientId,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E where E.clientId = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1`;
  const data = [clientId, CONSTANTS.USER_TYPE.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndTypeAndLandlordForWeb = async ({
  clientId,
  propIds,
  type,
}: expensesTypes & { startDate: string; endDate: string; propIds: any }) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1`;
  const data = [clientId, CONSTANTS.USER_TYPE.LANDLORD, type];

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

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

expenseDB.getTotalByPropIdAndTypeForLandlord = async ({
  propId,
  type,
}: expensesTypes & { startDate: string; endDate: string; propId: any }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseID where EP.propId = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1`;
  const data = [propId, CONSTANTS.USER_TYPE.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndTypeForStaffForLandlord = async ({
  clientId,
  type,
  propertiesIds,
}: expensesTypes & { propertiesIds: any; }) => {
  const query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1 and EP.propId in (${propertiesIds})`;
  const data = [clientId, CONSTANTS.USER_TYPE.LANDLORD, type];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return Number(rows[0].total);
  else return 0;
};

expenseDB.getTotalByClientIdAndTypeAndLandlordForWebStaff = async ({
  clientId,
  propIds,
  type,
  propertiesIds,
}: expensesTypes & { propertiesIds: any; propIds: any }) => {
  let query =
    `Select SUM(E.amount) as total from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1 and EP.propId in (${propertiesIds})`;
  const data = [clientId, CONSTANTS.USER_TYPE.LANDLORD, type];

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

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

expenseDB.getSecurityExpensesByClientId = async ({
  clientId,
  limit,
  pageNum,
}: expensesTypes & {
  limit: number;
  pageNum: number;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.type = ? and E.isPaid = 1 order by E.dueDate desc  limit ?, ?`;

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    43, //Security Type
    `${offset}`,
    `${limit}`,
  ];

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

expenseDB.getSecurityExpensesByPropId = async ({
  clientId,
  propId,
  limit,
  pageNum,
}: expensesTypes & {
  limit: number;
  pageNum: number;
  propId: number;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.bankRefNum, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and E.type = ? and E.isPaid = 1 order by E.dueDate desc  limit ?, ?`;

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
    43, //Security Type
    `${offset}`,
    `${limit}`,
  ];

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

expenseDB.getSecurityExpensesForLandlordByPropId = async ({
  clientId,
  propId,
  limit,
  pageNum,
}: expensesTypes & {
  limit: number;
  pageNum: number;
  propId: number;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and EP.propId = ? and E.type = ? order by E.dueDate desc  limit ?, ?`;

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    propId,
    43, //Security Type
    `${offset}`,
    `${limit}`,
  ];

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

expenseDB.getSecurityExpensesByClientIdForStaff = async ({
  clientId,
  limit,
  pageNum,
  propertiesIds,
}: expensesTypes & {
  limit: number;
  pageNum: number;
  propertiesIds: string;
}) => {
  let query =
    `Select E.id, E.repetitionType, E.expenseTitle, E.expenseNature, E.supportDoc, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id where E.clientId = ? and E.type = ? and E.isPaid = 1 and EP.propId in (${propertiesIds}) order by E.dueDate desc  limit ?, ?`;

  const offset: number = (pageNum - 1) * limit;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    43, //Security Type
    `${offset}`,
    `${limit}`,
  ];

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

expenseDB.getUnMarkedLandlordExpenseByPropId = async ({
  propId,
  clientId,
}: expensesTypes & {propId: number}) => {
  const query = 
    `Select E.id, E.amount, E.type, E.dueDate from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on E.type = ET.id where EP.propId = ? and E.clientId = ? and E.isPaid = 0 and E.type IN (1,43) order by E.dueDate desc`;

  const data = [
    propId,
    clientId
  ];

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

expenseDB.updateExpenseOnPaid = async ({
  id,
  paidDate,
  paymentMethod
}: expensesTypes) => {
  const query = 
    `Update Expenses set paidDate = ?, paymentMethod = ?, isPaid = 1 where id = ? limit 1`;
  const data = [
    paidDate,
    paymentMethod,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};


expenseDB.updateExpenseBankRefNum = async ({
  id,
  bankRefNum
}: expensesTypes) => {
  const query = 
    `Update Expenses set bankRefNum = ?  where id = ? limit 1`;
  const data = [
    bankRefNum,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

expenseDB.updateAmount = async ({
  id,
  amount
}: expensesTypes) => {
  const query = 
    `Update Expenses set amount=?, balance=? where id = ? limit 1`;
  const data = [
    amount,
    amount,
    id,
  ];
  const [rows] = await DB.query<ResultSetHeader>(query, data);
  return rows.insertId;
};

// expenseDB.getByPaidToForLandlordTransactions = async ({
//   clientId,
//   paidTo,
//   paidToUserType,
// }: expensesTypes & { pageNum: number; limit: number; month: string }) => {
//   const query =
//     "Select E.id, E.repetitionType, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, P.name as propertyName, if(E.paidToUserType = ?, (select name from Vendors where id = E.paidTo), (select name from Staffs where id = E.paidTo)) as paidToName, (select L.name from Landlords as L join PropertyLease as PL on L.id = PL.id where PL.propId = P.id) as landlordName, (select L.mobile from Landlords as L join PropertyLease as PL on L.id = PL.id where PL.propId = P.id) as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type INNER JOIN Properties as P ON P.id = EP.propId where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc";
//   const data = [
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.USER_TYPE.CLIENT,
//     clientId,
//     paidTo,
//     paidToUserType,
//   ];

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

expenseDB.getByPaidToForLandlordTransactionByLandlordId = async ({
  clientId,
  landlordId,
}: expensesTypes & { landlordId: number; }) => {
  const query =
    //"select E.id, E.repetitionType, P.name as propertyName, E.supportDoc, E.type, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as paidToName, V.mobile as paidToMobile, V.name as landlordName, V.mobile as landlordMobile, E.paidDate, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER JOIN Vendors as V ON E.paidTo=V.id INNER  join ExpenseTypes as ET on ET.id = E.type INNER JOIN ExpensesProperty as EP ON EP.expenseId=E.id INNER JOIN Properties as P ON EP.propId=P.id where E.id In (select expenseId from ExpensesProperty where clientId=? and propId IN (select propId  from PropertyLease where landlordId =?)) and E.type IN (1, 43) and E.isPaid=1;";
    "select  P.name as propertyName, F.name as flatName, E.type, E.bankRefNum, E.supportDoc, E.amount, E.expenseTitle, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Flats as F on EP.flatId = F.id LEFT JOIN Properties as P ON EP.propId=P.id where E.clientId=? and E.paidTo=? and E.isPaid=1 order by E.id desc;";
  const data = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    landlordId,
  ];

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

expenseDB.getByPaidToForLandlordTransactionByLandlordIdAndSearch = async ({
  clientId,
  landlordId,
  searchVal,
  searchType,
}: expensesTypes & { landlordId: number; searchVal: string; searchType: number }) => {
  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    landlordId,
  ];

  let filterCondition = "";
  if(1 === Number(searchType)){
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND V.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(4 === Number(searchType)) {
    filterCondition = 'AND V.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }

  const query =
    `select  P.name as propertyName, E.expenseTitle, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id where E.clientId=? and E.paidTo=? and E.isPaid=1 ${filterCondition} order by E.id desc;`;

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

// expenseDB.getByPaidToForLandlordTransactionByClientId = async ({
//   clientId,
//   startDate,
//   endDate,
// }: expensesTypes & { startDate: string; endDate: string; }) => {
//   const query =
//     "select  P.name as propertyName, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and DATE(E.paidDate) BETWEEN ? and ? and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 order by E.id desc;";
//   const data = [
//     clientId,
//     startDate,
//     endDate,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//   ];

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

//Not being used
expenseDB.getByPaidToForLandlordTransactionByClientId = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "select  P.name as propertyName, E.expenseTitle, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and V.type = ? and DATE(E.dueDate) BETWEEN ? and ? and E.isPaid = 1 order by E.id desc;";
  const data = [
    clientId,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
    startDate,
    endDate
  ];

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

expenseDB.getByPaidToForLandlordTransactionByClientIdX = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; }) => {
  const query =
    "select  P.name as propertyName, E.expenseTitle, F.name as flatName, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.supportDoc, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId = E.id LEFT JOIN Properties as P ON EP.propId = P.id LEFT JOIN Flats as F on EP.flatId = F.id JOIN Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and DATE(E.paidDate) BETWEEN ? and ? and E.isPaid = 1 order by E.id desc;";
  const data = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    startDate,
    endDate
  ];

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


// expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearch = async ({
//   clientId,
//   searchVal,
//   searchType,
// }: expensesTypes & { searchVal: string; searchType: number; }) => {

//   const data: any = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//   ];

//   let filterCondition = "";
//   if (1 === Number(searchType)) {
//     filterCondition = 'AND E.bankRefNum LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(2 === Number(searchType)) {
//     filterCondition = 'AND E.amount = ?';
//     data.push(searchVal);
//   } else if(3 === Number(searchType)) {
//     filterCondition = 'AND V.name LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(4 === Number(searchType)) {
//     filterCondition = 'AND V.mobile LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(5 === Number(searchType)) {
//     filterCondition = 'AND P.name LIKE ?';
//     data.push(`%${searchVal}%`);
//   }
//   const query =
//     `select  P.name as propertyName, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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


//Not being used
expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearch = async ({
  clientId,
  searchVal,
  searchType,
}: expensesTypes & { searchVal: string; searchType: number; }) => {

  const data: any = [
    clientId,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
  ];

  let filterCondition = "";
  if (1 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND V.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(4 === Number(searchType)) {
    filterCondition = 'AND V.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }
  const query =
    `select  P.name as propertyName, E.type, E.expenseTitle, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? AND V.type = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearchX = async ({
  clientId,
  searchVal,
  searchType,
}: expensesTypes & { searchVal: string; searchType: number; }) => {

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  let filterCondition = "";
  if (6 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND L.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(1 === Number(searchType)) {
    filterCondition = 'AND L.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }
  const query =
    `select  P.name as propertyName, F.name as flatName, E.expenseTitle, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.supportDoc,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Flats as F on EP.flatId = F.id JOIN Landlords as L on L.id = E.paidTo where E.clientId = ? AND E.paidToUserType = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

expenseDB.getByPaidToForLandlordTransactionByPropId = async ({
  propId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; propId: number }) => {
  const query =
    "select  P.name as propertyName, E.type, E.expenseTitle, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where EP.propId = ? and DATE(E.dueDate) BETWEEN ? and ? and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 order by E.id desc;";
  const data = [
    propId,
    startDate,
    endDate,
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
  ];

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

expenseDB.getByPaidToForLandlordTransactionByPropIdX = async ({
  propId,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string; propId: number }) => {
  const query =
    "select  P.name as propertyName, F.name as flatName, E.type, E.expenseTitle, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.supportDoc, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Flats as F on EP.flatId = F.id JOIN Landlords as L on L.id = E.paidTo where EP.propId = ? and DATE(E.paidDate) BETWEEN ? and ? and E.paidToUserType = ? and E.isPaid = 1 order by E.id desc;";
  const data = [
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    startDate,
    endDate,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

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

expenseDB.getByPaidToForLandlordTransactionByPropIdAndSearch = async ({
  propId,
  searchVal,
  searchType,
}: expensesTypes & { searchVal: string; searchType: number; propId: number }) => {
  
  const data: any = [
    propId,
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
  ];

  let filterCondition = "";
  if (1 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND V.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(4 === Number(searchType)) {
    filterCondition = 'AND V.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }
  const query =
    `select  P.name as propertyName, E.type, E.bankRefNum, E.expenseTitle, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where EP.propId = ? and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

expenseDB.getByPaidToForLandlordTransactionByPropIdAndSearchX = async ({
  propId,
  searchVal,
  searchType,
}: expensesTypes & { searchVal: string; searchType: number; propId: number }) => {
  
  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    propId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  let filterCondition = "";
  if (6 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND L.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(1 === Number(searchType)) {
    filterCondition = 'AND L.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }
  const query =
    `select  P.name as propertyName, F.name as flatName, E.expenseTitle, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.supportDoc, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Flats as F on EP.flatId = F.id JOIN Landlords as L on L.id = E.paidTo where EP.propId = ? and E.paidToUserType = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

// expenseDB.getByPaidToForLandlordTransactionByClientIdForStaff = async ({
//   clientId,
//   startDate,
//   endDate,
//   propertiesIds,
// }: expensesTypes & { startDate: string; endDate: string; propertiesIds: string }) => {
//   const query =
//     `select  P.name as propertyName, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and DATE(E.paidDate) BETWEEN ? and ? and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 order by E.id desc;`;
//   const data = [
//     clientId,
//     startDate,
//     endDate,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//   ];

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

expenseDB.getByPaidToForLandlordTransactionByClientIdForStaff = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & { startDate: string; endDate: string; propertiesIds: string }) => {
  const query =
    `select  P.name as propertyName, E.type, E.bankRefNum, E.expenseTitle, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and V.type = ? and EP.propId in (${propertiesIds}) and DATE(E.dueDate) BETWEEN ? and ? and E.isPaid = 1 order by E.id desc;`;
  const data = [
    clientId,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
    startDate,
    endDate
  ];

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

expenseDB.getByPaidToForLandlordTransactionByClientIdForStaffX = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & { startDate: string; endDate: string; propertiesIds: string }) => {
  const query =
    `select  P.name as propertyName, F.name as flatName, E.type, E.expenseTitle, E.supportDoc, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Flats F ON F.id = EP.flatId JOIN Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and EP.propId in (${propertiesIds}) and DATE(E.paidDate) BETWEEN ? and ? and E.isPaid = 1 order by E.id desc;`;
  const data = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    startDate,
    endDate
  ];

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

// expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearchForStaff = async ({
//   clientId,
//   searchVal,
//   searchType,
//   propertiesIds,
// }: expensesTypes & { searchVal: string; searchType: string; propertiesIds: string }) => {

//   const data: any = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//   ];

//   let filterCondition = "";
//   if (1 === Number(searchType)) {
//     filterCondition = 'AND E.bankRefNum LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(2 === Number(searchType)) {
//     filterCondition = 'AND E.amount = ?';
//     data.push(searchVal);
//   } else if(3 === Number(searchType)) {
//     filterCondition = 'AND V.name LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(4 === Number(searchType)) {
//     filterCondition = 'AND V.mobile LIKE ?';
//     data.push(`%${searchVal}%`);
//   } else if(5 === Number(searchType)) {
//     filterCondition = 'AND P.name LIKE ?';
//     data.push(`%${searchVal}%`);
//   }

//   const query =
//     `select  P.name as propertyName, E.type, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id INNER JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and E.paidToUserType = ? and V.type = ? and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearchForStaff = async ({
  clientId,
  searchVal,
  searchType,
  propertiesIds,
}: expensesTypes & { searchVal: string; searchType: string; propertiesIds: string }) => {

  const data: any = [
    clientId,
    CONSTANTS.VENDOR_TYPES.LANDLORD,
  ];

  let filterCondition = "";
  if (1 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND V.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(4 === Number(searchType)) {
    filterCondition = 'AND V.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }

  const query =
    `select  P.name as propertyName, E.type, E.bankRefNum, E.expenseTitle, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, V.name as landlordName, V.mobile as landlordMobile from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Vendors as V on V.id = E.paidTo where E.clientId = ? and V.type = ? and EP.propId in (${propertiesIds}) and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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

expenseDB.getByPaidToForLandlordTransactionByClientIdAndSearchForStaffX = async ({
  clientId,
  searchVal,
  searchType,
  propertiesIds,
}: expensesTypes & { searchVal: string; searchType: string; propertiesIds: string }) => {

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  let filterCondition = "";
  if (1 === Number(searchType)) {
    filterCondition = 'AND E.bankRefNum LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(2 === Number(searchType)) {
    filterCondition = 'AND E.amount = ?';
    data.push(searchVal);
  } else if(3 === Number(searchType)) {
    filterCondition = 'AND L.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(4 === Number(searchType)) {
    filterCondition = 'AND L.mobile LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(5 === Number(searchType)) {
    filterCondition = 'AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }

  const query =
    `select  P.name as propertyName, F.name as flatName, E.expenseTitle, E.type, E.supportDoc, E.bankRefNum, E.amount, E.balance, E.paidDate, E.dueDate, E.paidBy, E.paidTo, E.description, E.paymentMethod,E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, L.name as landlordName, L.mobile as landlordMobile, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E INNER  join ExpenseTypes as ET on ET.id = E.type LEFT JOIN ExpensesProperty as EP ON EP.expenseId=E.id LEFT JOIN Properties as P ON EP.propId=P.id LEFT JOIN Flats F ON F.id = EP.flatId JOIN Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and EP.propId in (${propertiesIds}) and E.isPaid = 1 ${filterCondition} order by E.id desc;`;

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


expenseDB.getTotlRentAndSecurityPaidToLandlord = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes & { month: string }) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1";
  const data = [
    clientId,
    paidTo,
    paidToUserType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getByPropNameByClientId = async ({
  clientId,
  searchVal,
}: expensesTypes & { searchVal: string }) => {
  const query =
    `Select E.id, E.repetitionType, E.expenseNature, E.expenseTitle, E.supportDoc, E.bankRefNum, E.type, E.amount, E.balance, E.paidDate, E.paidBy, E.paidTo, E.description, E.paymentMethod, E.createdAt, ET.name, E.paidToUserType, E.paidByUserType, CASE WHEN E.paidToUserType = ? THEN (select name from Vendors where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Staffs where id = E.paidTo) WHEN E.paidToUserType = ? THEN (select name from Landlords where id = E.paidTo) END as paidToName, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName, EC.id as expenseCategoryId, P.name as propertyName from Expenses as E left join ExpensesProperty as EP on E.id = EP.expenseId left join ExpenseTypes as ET on ET.id = E.type join ExpenseCategories as EC on ET.categoryId = EC.id join Properties as P on P.id = EP.propId where E.clientId = ? and E.isPaid = 1 and P.name LIKE ? order by E.dueDate desc`;
  const data = [
    CONSTANTS.USER_TYPE.VENDOR,
    CONSTANTS.USER_TYPE.STAFF,
    CONSTANTS.USER_TYPE.LANDLORD,
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    `%${searchVal}%`,
  ];

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

// expenseDB.getSummaryByClientIdAndDateRange = async ({
//   clientId,
//   startDate,
//   endDate
// }: expensesTypes & {startDate: string; endDate: string}) => {
//   const query = 
//     `Select
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.paidToUserType = ? and V.type = ? and DATE(paidDate) BETWEEN ? and ?) as total,
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.paidToUserType = ? and V.type = ? and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalRent,
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.paidToUserType = ? and V.type = ? and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalSecurity`;

//   const data = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     startDate,
//     endDate,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     1, //Rent Type
//     startDate,
//     endDate,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     43, //Security Type
//     startDate,
//     endDate,
//   ];

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

expenseDB.getSummaryByClientIdAndDateRangeLandlord = async ({
  clientId,
  startDate,
  endDate
}: expensesTypes & {startDate: string; endDate: string}) => {
  const query = 
    `Select
    (Select IFNULL(SUM(amount), 0) from Expenses as E join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(paidDate) BETWEEN ? and ?) as total,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalRent,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalSecurity`;

  const data = [
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    startDate,
    endDate,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    1, //Rent Type
    startDate,
    endDate,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    43, //Security Type
    startDate,
    endDate,
  ];

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





// expenseDB.getSummaryByClientIdAndDateRangeForStaff = async ({
//   clientId,
//   startDate,
//   endDate,
//   propertiesIds,
// }: expensesTypes & {startDate: string; endDate: string; propertiesIds: string}) => {
//   const query = 
//     `Select
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and V.type = ? and DATE(dueDate) BETWEEN ? and ?) as total,
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and V.type = ? and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?) as totalRent,
//     (Select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and V.type = ? and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?) as totalSecurity`;

//   const data = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     startDate,
//     endDate,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     1, //Rent Type
//     startDate,
//     endDate,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     43, //Security Type
//     startDate,
//     endDate,
//   ];

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

expenseDB.getSummaryByClientIdAndDateRangeForStaffForLandlord = async ({
  clientId,
  startDate,
  endDate,
  propertiesIds,
}: expensesTypes & {startDate: string; endDate: string; propertiesIds: string}) => {
  const query = 
    `Select
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and DATE(paidDate) BETWEEN ? and ?) as total,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalRent,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId in (${propertiesIds}) and E.clientId = ? and E.paidToUserType = ? and E.isPaid = 1 and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalSecurity`;

  const data = [
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    startDate,
    endDate,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    1, //Rent Type
    startDate,
    endDate,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    43, //Security Type
    startDate,
    endDate,
  ];

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

expenseDB.getSummaryByPropIdAndDateRangeForLandlord = async ({
  propId,
  startDate,
  endDate
}: expensesTypes & {propId: string; startDate: string; endDate: string}) => {
  const query = 
    `Select
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId = ? and E.isPaid = 1 and E.paidToUserType = ? and DATE(paidDate) BETWEEN ? and ?) as total,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId = ? and E.isPaid = 1 and E.paidToUserType = ? and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalRent,
    (Select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where EP.propId = ? and E.isPaid = 1 and E.paidToUserType = ? and E.type = ? and DATE(E.paidDate) BETWEEN ? and ?) as totalSecurity`

  const data = [
    propId,
    CONSTANTS.USER_TYPE.LANDLORD,
    startDate,
    endDate,
    propId,
    CONSTANTS.USER_TYPE.LANDLORD,
    1, //Rent Type
    startDate,
    endDate,
    propId,
    CONSTANTS.USER_TYPE.LANDLORD,
    43, //Security Type
    startDate,
    endDate,
  ];

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

expenseDB.getUnPaidLandlordDuesByClientId = async ({
  clientId,
  startDate=null,
  endDate=null,
  typeFilter=null,
  locationId=null,
}: expensesTypes & {startDate: string | null; endDate: string | null; typeFilter: string[] | null; locationId: string | null}) => {
  //Using the balance in web dont change
  let query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId LEFT JOIN Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? `;

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  if (startDate && endDate) {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate, endDate);
  }

  if (typeFilter) {
    query += ` and E.type in (${typeFilter.map((item: string) => '?').join(',')})`;
    data.push(...typeFilter);
  }

  if (locationId) {
    query += ` and P.locationId = ?`
    data.push(locationId);
  }

  query += ` order by E.id desc`;

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

expenseDB.getUnPaidLandlordDuesByClientIdForApp = async ({
  clientId,
  startDate=null,
  endDate=null,
  typeFilter=null,
  locationId=null,
  pageNum=1,
  limit=10,
}: expensesTypes & {startDate: string | null; endDate: string | null; typeFilter: string[] | null; locationId: string | null; pageNum: number; limit: number}) => {
  //Using the balance in web dont change
  let query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId LEFT JOIN Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? `;

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  if (startDate && endDate) {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate, endDate);
  }

  if (typeFilter) {
    query += ` and E.type in (${typeFilter.map((item: string) => '?').join(',')})`;
    data.push(...typeFilter);
  }

  if (locationId) {
    query += ` and P.locationId = ?`
    data.push(locationId);
  }

  const offSet = (Number(pageNum) - 1) * Number(limit);

  query += ` order by E.id desc limit ?, ?`;
  data.push(`${offSet}`, `${limit}`);

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

expenseDB.getUnPaidLandlordDuesByClientIdAndSearch = async ({
  clientId,
  searchVal,
  searchType,
}: expensesTypes & {searchVal: string; searchType: string}) => {
  //Using the balance in web dont change
  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  let filterCondition = "";
  if(Number(searchType) === 1) {
    filterCondition = ' AND L.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(Number(searchType) === 2){
    filterCondition = ' AND L.mobile LIKE ?';
    data.push(`${searchVal}%`);
  } else if (Number(searchType) === 3) {
    filterCondition = ' AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }

  const query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? ${filterCondition} order by E.id desc`;

    log.info(`quwery [${mysql.format(query, data)}]`);

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

expenseDB.getUnPaidLandlordDuesByClientIdAndSearchApp = async ({
  clientId,
  searchVal,
  pageNum,
  limit,
}: expensesTypes & {searchVal: string; pageNum: number; limit: number}) => {
  //Using the balance in web dont change

  const query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? and (L.name LIKE ? OR L.mobile LIKE ? OR P.name LIKE ?) order by E.id desc limit ?, ?`;

    const offset = (Number(pageNum) - 1) * Number(limit);

    const data: any = [
      CONSTANTS.USER_TYPE.CLIENT,
      clientId,
      CONSTANTS.USER_TYPE.LANDLORD,
      `%${searchVal}%`,
      `%${searchVal}%`,
      `%${searchVal}%`,
      `${offset}`,
      `${limit}`,
    ];

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

expenseDB.getUnPaidLandlordDuesByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  startDate=null,
  endDate=null,
  typeFilter=null,
  locationId=null,
}: expensesTypes & {propertiesIds: string; startDate: string | null; endDate: string | null; typeFilter: string[] | null; locationId: string | null}) => {
  let query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ?`;

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  if(startDate && endDate) {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate, endDate);
  }

  if(typeFilter) {
    query += ` and E.type in (${typeFilter.map((item: string) => '?').join(',')})`;
    data.push(...typeFilter);
  }

  if (locationId) {
    query += ` and P.locationId = ?`
    data.push(locationId);
  }

  query += ` order by E.id desc`;

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

expenseDB.getUnPaidLandlordDuesByClientIdForStaffApp = async ({
  clientId,
  propertiesIds,
  startDate=null,
  endDate=null,
  typeFilter=null,
  locationId=null,
  pageNum=1,
  limit=10,
}: expensesTypes & {propertiesIds: string; startDate: string | null; endDate: string | null; typeFilter: string[] | null; locationId: string | null; pageNum: number; limit: number}) => {
  let query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ?`;

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  if(startDate && endDate) {
    query += ` and DATE(E.dueDate) BETWEEN ? and ?`;
    data.push(startDate, endDate);
  }

  if(typeFilter) {
    query += ` and E.type in (${typeFilter.map((item: string) => '?').join(',')})`;
    data.push(...typeFilter);
  }

  if (locationId) {
    query += ` and P.locationId = ?`
    data.push(locationId);
  }

  const offSet = (Number(pageNum) - 1) * Number(limit);

  query += ` order by E.id desc limit ?, ?`;
  data.push(`${offSet}`, `${limit}`);

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

expenseDB.getUnPaidLandlordDuesByClientIdAndSearchForStaff = async ({
  clientId,
  propertiesIds,
  searchVal,
  searchType,
}: expensesTypes & {propertiesIds: string; searchVal: string; searchType: string}) => {

  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

  let filterCondition = "";
  if(Number(searchType) === 1) {
    filterCondition = ' AND L.name LIKE ?';
    data.push(`%${searchVal}%`);
  } else if(Number(searchType) === 2){
    filterCondition = ' AND L.mobile LIKE ?';
    data.push(`${searchVal}%`);
  } else if (Number(searchType) === 3) {
    filterCondition = ' AND P.name LIKE ?';
    data.push(`%${searchVal}%`);
  }

  const query = 
    `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ? ${filterCondition} order by E.id desc`;


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

expenseDB.getUnPaidLandlordDuesByClientIdAndSearchForStaffApp = async ({
  clientId,
  propertiesIds,
  searchVal,
  pageNum,
  limit,
}: expensesTypes & {propertiesIds: string; searchVal: string; pageNum: number; limit: number}) => {  
  const query = 
  `Select E.id, E.amount as balance, E.expenseTitle, E.type, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, F.name as flatName, P.id as propId, F.id as flatId, L.id as landlordId, E.paidBy, E.paidByUserType, if(E.paidByUserType = ?, (select name from Clients where id = E.paidBy), (select name from Staffs where id = E.paidBy)) as paidByName from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ? and (L.name LIKE ? OR L.mobile LIKE ? OR P.name LIKE ?) order by E.id desc limit ?, ?`;
  
  const offset = (Number(pageNum) - 1) * Number(limit);
  const data: any = [
    CONSTANTS.USER_TYPE.CLIENT,
    clientId,
    CONSTANTS.USER_TYPE.LANDLORD,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `%${searchVal}%`,
    `${offset}`,
    `${limit}`,
  ];

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

// expenseDB.getLandlordDuesSummaryByClientId = async ({
//   clientId,
// }: expensesTypes) => {
//   const query =
//     `Select (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? and V.type = ?) as total, (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? and V.type = ? and E.type = ? and MONTH(E.dueDate)=MONTH(CURDATE()) and YEAR(E.dueDate)=YEAR(CURDATE()) ) as rent, (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id where E.clientId = ? and E.isPaid = 0 and E.paidToUserType = ? and V.type = ? and E.type = ?) as security`;

//   const data = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     1, //Rent Type
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     43, //Security Type
//   ];

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


expenseDB.getLandlordDuesSummaryByClientId = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & {startDate: string; endDate: string}) => {
  const query =
    `Select (select IFNULL(SUM(amount), 0) from Expenses as E  where E.clientId = ? and E.isPaid = 0) as total, (select IFNULL(SUM(amount), 0) from Expenses as E  where E.clientId = ? and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ?) as curMonthTotal, (select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 0 and E.type = ?) as rent, (select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?) as curMonthRent, (select IFNULL(SUM(amount), 0) from Expenses as E where E.clientId = ? and E.isPaid = 0 and E.type = ?) as security`;

  const data = [
    clientId,
    clientId,
    startDate,
    endDate,
    clientId,
    1, //Rent Type
    clientId,
    1, //Rent Type
    startDate,
    endDate,
    clientId,
    43, //Security Type
  ];

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

// expenseDB.getLandlordDuesSummaryByClientIdForStaff = async ({
//   clientId,
//   propertiesIds,
// }: expensesTypes & {propertiesIds: string}) => {
//   const query =
//     `Select 
//     (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ? and V.type = ?) as total, 
//     (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ? and V.type = ? and E.type = ?) as rent, 
//     (select IFNULL(SUM(amount), 0) from Expenses as E join Vendors as V on E.paidTo = V.id join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.paidToUserType = ? and V.type = ? and E.type = ?) as security
//     `;

//   const data = [
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     1, //Rent Type
//     clientId,
//     CONSTANTS.USER_TYPE.VENDOR,
//     CONSTANTS.VENDOR_TYPES.LANDLORD,
//     43, //Security Type
//   ];

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

expenseDB.getLandlordDuesSummaryByClientIdForStaff = async ({
  clientId,
  propertiesIds,
  startDate,
  endDate,
}: expensesTypes & {propertiesIds: string; startDate: string; endDate: string}) => {
  const query =
    `Select 
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0) as total, 
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and DATE(E.dueDate) BETWEEN ? and ?) as curMonthTotal,
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.type = ?) as rent, 
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.type = ? and DATE(E.dueDate) BETWEEN ? and ?) as rent, 
    (select IFNULL(SUM(amount), 0) from Expenses as E join ExpensesProperty as EP on EP.expenseId = E.id where E.clientId = ? and EP.propId in (${propertiesIds}) and E.isPaid = 0 and E.type = ?) as security
    `;

  const data = [
    clientId,
    clientId,
    startDate,
    endDate,
    clientId,
    1, //Rent Type
    clientId,
    1, //Rent Type
    startDate,
    endDate,
    clientId,
    43, //Security Type
  ];

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

expenseDB.getExpenseCategoryById = async ({
  id,
}: any) => {
  const query = `Select * from ExpenseCategories 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;
};

expenseDB.getExpenseTypeById = async ({
  id,
}: any) => {
  const query = `Select * from ExpenseTypes 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;
};

expenseDB.getExpensePropertyById = async ({
  id,
}: expensesTypes) => {
  const query = `Select * from ExpensesProperty where expenseId = ? limit 1`;
  const data = [id];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getTotalByPropIdAndDateRange = async ({
  propId,
  startDate,
  endDate,
}: {propId: number; startDate: string; endDate: string}) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and DATE(dueDate) BETWEEN ? and ?`;
  const data = [propId, startDate, endDate];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalUnPaidByPropIdAndPaidTo = async ({
  propId,
  paidTo,
  paidToUserType,
}: expensesTypes & {propId: number; }) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0`;
  const data = [propId, paidTo, paidToUserType];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalUnPaidByPropIdAndFlatIdAndPaidTo = async ({
  propId,
  flatId=null,
  paidTo,
  paidToUserType,
}: expensesTypes & {propId: number; flatId: any; }) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and (EP.flatId = ? or EP.flatId is null) and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0`;
  const data = [propId, flatId, paidTo, paidToUserType];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalByPropIdAndPaidTo = async ({
  propId,
  paidTo,
  paidToUserType,
}: expensesTypes & {propId: number; }) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 1`;
  const data = [propId, paidTo, paidToUserType];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalByPropIdAndPaidToAndType = async ({
  propId,
  paidTo,
  paidToUserType,
  type,
}: expensesTypes & {propId: number; }) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId where EP.propId = ? and E.paidTo = ? and E.paidToUserType = ? and E.type = ? and E.isPaid = 1`;
  const data = [
    propId, 
    paidTo, 
    paidToUserType, 
    type,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalUnPaidByClientIdAndPaidTo = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0`;
  const data = [clientId, paidTo, paidToUserType];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalByClientIdAndPaidTo = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid =1`;
  const data = [clientId, paidTo, paidToUserType];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getTotalByClientIdAndPaidToAndType = async ({
  clientId,
  paidTo,
  paidToUserType,
  type,
}: expensesTypes) => {
  const query = `Select IFNULL(Sum(E.amount), 0) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.type = ? and E.isPaid =1`;
  const data = [
    clientId, 
    paidTo, 
    paidToUserType, 
    type,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return false;
};

expenseDB.getSummaryByLandlordIdAndDateRange = async ({
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string}) => {
  const query = `Select IFNULL(SUM(E.amount), 0) AS total, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS rent, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS security, IFNULL(SUM(CASE WHEN E.type not in (?, ?) THEN E.amount ELSE 0 END), 0) AS other, (SELECT IFNULL(SUM(amount), 0) FROM Expenses WHERE paidTo = ? AND paidToUserType = ? AND type = ? AND isPaid = 1) AS lifetimeSecurity from Expenses AS E WHERE E.paidTo = ? AND E.paidToUserType = ? AND E.isPaid = 1 AND DATE(E.paidDate) BETWEEN ? AND ?`;
  const data = [
    1, //Rent,
    43, //Security,
    1, //Rent,
    43, //Security,
    paidTo,
    paidToUserType,
    43, //Security
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];

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

expenseDB.getSummaryByLandlordIdAndDateRangeAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { propId: number; startDate: string; endDate: string}) => {
  const query = `Select IFNULL(SUM(E.amount), 0) AS total, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS rent, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS security, IFNULL(SUM(CASE WHEN E.type not in (?, ?) THEN E.amount ELSE 0 END), 0) AS other, (SELECT IFNULL(SUM(E.amount), 0) FROM Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? AND E.paidTo = ? AND E.paidToUserType = ? AND E.type = ? AND E.isPaid = 1) AS lifetimeSecurity from Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? AND E.paidTo = ? AND E.paidToUserType = ? AND E.isPaid = 1 AND DATE(E.paidDate) BETWEEN ? AND ?`;
  const data = [
    1, //Rent,
    43, //Security,
    1, //Rent,
    43, //Security,
    propId,
    paidTo,
    paidToUserType,
    43, //Security
    propId,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];

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

expenseDB.getUnPaidSummaryByLandlordIdAndDateRange = async ({
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { startDate: string; endDate: string}) => {
  const query = `Select IFNULL(SUM(E.amount), 0) AS totalForDateRange, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS rent, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS security, IFNULL(SUM(CASE WHEN E.type not in (?, ?) THEN E.amount ELSE 0 END), 0) AS other, (SELECT IFNULL(SUM(amount), 0) FROM Expenses WHERE paidTo = ? AND paidToUserType = ? and isPaid = 0) AS lifetimeTotal from Expenses AS E WHERE E.paidTo = ? AND E.paidToUserType = ? AND E.isPaid = 0 AND DATE(E.dueDate) BETWEEN ? AND ?`;
  const data = [
    1, //Rent,
    43, //Security,
    1, //Rent,
    43, //Security,
    paidTo,
    paidToUserType,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];
  // const formattedQuery = DB.format(query, data);
  // log.info(`formattedQuery: ${formattedQuery}`);
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0];
  else return false;
};

expenseDB.getUnPaidSummaryByLandlordIdAndDateRangeAndPropId = async ({
  propId,
  paidTo,
  paidToUserType,
  startDate,
  endDate,
}: expensesTypes & { propId: number; startDate: string; endDate: string}) => {
  const query = `Select IFNULL(SUM(E.amount), 0) AS totalForDateRange, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS rent, IFNULL(SUM(CASE WHEN E.type = ? THEN E.amount ELSE 0 END), 0) AS security, IFNULL(SUM(CASE WHEN E.type not in (?, ?) THEN E.amount ELSE 0 END), 0) AS other, (SELECT IFNULL(SUM(E1.amount), 0) FROM Expenses AS E1 join ExpensesProperty as EP1 on E1.id = EP1.expenseId WHERE EP1.propId = ? AND E1.paidTo = ? AND E1.paidToUserType = ? and E1.isPaid = 0) AS lifetimeTotal from Expenses AS E join ExpensesProperty as EP on E.id = EP.expenseId WHERE EP.propId = ? AND E.paidTo = ? AND E.paidToUserType = ? AND E.isPaid = 0 AND DATE(E.dueDate) BETWEEN ? AND ?`;
  const data = [
    1, //Rent,
    43, //Security,
    1, //Rent,
    43, //Security,
    propId,
    paidTo,
    paidToUserType,
    propId,
    paidTo,
    paidToUserType,
    startDate,
    endDate,
  ];

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

expenseDB.getUnpaidExpensesTotalByClientAndLandlord = async ({
  clientId,
  paidTo,
  paidToUserType,
}: expensesTypes) => {
  const query =
    "Select if(sum(amount) is NULL, 0, sum(amount)) as total from Expenses as E where E.clientId = ? and E.paidTo = ? and E.paidToUserType = ? and E.isPaid = 0";
  const data = [
    clientId,
    paidTo,
    paidToUserType,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows?.length > 0) return rows[0].total;
  else return 0;
};

expenseDB.getUnpaidExpensesByClientAndLandlord = async ({
  clientId,
  paidTo
}: expensesTypes) => {
  //Using the balance in web dont change
  const query = 
    `Select E.id, E.amount as balance, E.type, E.expenseTitle, E.paidBy, E.paidByUserType, E.dueDate, E.description, L.name as landlordName, L.mobile as landlordMobile, P.name as propName, P.id as propId, F.name as flatName, F.id as flatId, L.id as landlordId from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId left join Flats as F on EP.flatId = F.id join Landlords as L on L.id = E.paidTo where E.clientId = ? and E.paidTo = ? and E.isPaid = 0 and E.paidToUserType = ? order by E.id desc`;

  const data = [
    clientId,
    paidTo,
    CONSTANTS.USER_TYPE.LANDLORD,
  ];

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

expenseDB.getStaffPayables = async ({
  staffId,
  clientId,
}: expensesTypes & {staffId: number}) => {
  const query = 
    `Select E.*, S.name as paidToName, E.expenseTitle, ET.name as expenseTypeName, EC.name as expenseCategoryName, P.name as propName, P.id as propId from Expenses as E left join ExpensesProperty as EP on EP.expenseId = E.id left join Properties as P on P.id = EP.propId left join ExpenseTypes as ET on E.type = ET.id left join ExpenseCategories as EC on EC.id = ET.categoryId left join Staffs as S on S.id = E.paidTo where E.clientId = ? and E.paidTo = ? and E.isPaid = 0 and E.paidToUserType = ? order by E.id desc`;

  const data = [
    clientId,
    staffId,
    CONSTANTS.USER_TYPE.STAFF,
  ];

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

expenseDB.deleteByRecurringExpenseId = async ({recurringExpenseId}: expensesTypes) => {
  const query = `Delete from Expenses where recurringExpenseId = ?`;

  const data = [
    recurringExpenseId,
  ];

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

expenseDB.updatePaidToForCommission = async ({recurringExpenseId, paidTo, type,}: expensesTypes) => {
  const query = `Update Expenses set paidTo = ? where recurringExpenseId = ? and type = ?`;

  const data = [
    paidTo,
    recurringExpenseId,
    type,
  ];

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

expenseDB.isCommissionPaid = async ({
  recurringExpenseId,
  type,
}: expensesTypes) => {
  const query = `Select * from Expenses where recurringExpenseId = ? and type = ? order by id desc`;
  const data = [
    recurringExpenseId,
    type,
  ];
  
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows && rows.length > 0) return rows[0];
  else return false;
};

expenseDB.getTotalByAssetId = async ({
  clientId,
  assetId,
}: expensesTypes) => {
  const query = `Select SUM(amount) as totalAmount from Expenses where clientId = ? and assetId = ? and isPaid = 1`;
  const data = [
    clientId,
    assetId,
  ];
  
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows && rows.length > 0) return rows[0].totalAmount;
  else return 0;
};

expenseDB.updateBankDetails = async ({
  id,
  paymentAccountNo,
  paymentAccountName,
}: expensesTypes) => {
  const query = `Update Expenses set paymentAccountNo = ?, paymentAccountName = ? where id = ?`;

  const data = [
    paymentAccountNo,
    paymentAccountName,
    id,
  ];

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

expenseDB.updateExpenseJournalTallyDetails = async ({
  id,
  tallyJournalStatus,
}: expensesTypes) => {
  const query = `Update Expenses set tallyJournalStatus = ? where id = ?`;

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

expenseDB.updateExpensePaymentTallyStatus = async ({
  id,
  tallyPaymentStatus,
}: expensesTypes) => {
  const query = `Update Expenses set tallyPaymentStatus = ? where id = ?`;

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

expenseDB.syncExpenseJournalTally = async ({
  clientId
}: expensesTypes) => {
  const query = `Update Expenses set tallyJournalStatus = ? where clientId = ? and tallyJournalStatus = ?`;

  const data = [
    CONSTANTS.TALLY_STATUS.RETRY,
    clientId,
    CONSTANTS.TALLY_STATUS.FAILED,
  ];
  const [rows] = await DB.execute<ResultSetHeader>(query, data);
  return true;
};

expenseDB.syncExpensePaymentTally = async ({
  clientId,
}: expensesTypes) => {
  const query = `Update Expenses set tallyPaymentStatus = ? where clientId = ? and tallyPaymentStatus = ? and tallyBillRef is not null`;

  const data = [
    CONSTANTS.TALLY_STATUS.RETRY,
    clientId,
    CONSTANTS.TALLY_STATUS.SYNCED,
  ];
  const [rows] = await DB.execute<ResultSetHeader>(query, data);
  return true;
};

expenseDB.getSumForReportByClientId = async ({
  clientId,
  startDate,
  endDate,
}: expensesTypes & {startDate: string; endDate: string;}) => {
  const query = `Select E.type, SUM(E.amount) as amount, ET.name, ET.expenseClassification from Expenses as E join ExpenseTypes as ET on E.type = ET.id where E.clientId = ? and DATE(E.paidDate) BETWEEN ? and ? and E.isPaid = 1 group by E.type`;

  const data = [
    clientId,
    startDate,
    endDate,
  ];

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

expenseDB.getSumForReportByPropIds = async ({
  clientId,
  propId,
  startDate,
  endDate,
}: expensesTypes & {startDate: string; endDate: string; propId: any[]}) => {
  const query = `Select E.type, SUM(E.amount) as amount, ET.name, ET.expenseClassification from Expenses as E join ExpensesProperty as EP on E.id = EP.expenseId join ExpenseTypes as ET on E.type = ET.id where E.clientId = ? and EP.propId in (${propId.map(() => '?').join(',')}) and DATE(E.paidDate) BETWEEN ? and ? and E.isPaid = 1 group by E.type`;

  const data = [
    clientId,
    ...propId,
    startDate,
    endDate,
  ];

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


expenseDB.getLastPaymentDoneToLandlord = async ({
  clientId,
}: expensesTypes) => {
  const query = `SELECT id, paidTo AS landlordId, paidDate, amount AS paidAmount, bankRefNum FROM (SELECT id, paidTo, paidDate, amount, bankRefNum, ROW_NUMBER() OVER (PARTITION BY paidTo ORDER BY paidDate DESC, id DESC) AS rn FROM Expenses WHERE paidToUserType = ? AND isPaid = ? AND clientId = ?) t WHERE rn = 1 ORDER BY landlordId`;

  const data = [
    CONSTANTS.USER_TYPE.LANDLORD,
    1,
    clientId,
  ];
  const [rows] = await DB.execute<RowDataPacket[]>(query, data);
  if (rows && rows.length > 0) return rows;
  else return [];
};


expenseDB.getLastPaymentDoneToUsers = async ({
  clientId,
}: expensesTypes) => {
  const query = `SELECT id, paidTo, paidToUserType, paidDate, amount AS paidAmount, bankRefNum FROM (SELECT id, paidTo, paidToUserType, paidDate, amount, bankRefNum, ROW_NUMBER() OVER (PARTITION BY paidTo, paidToUserType ORDER BY paidDate DESC, id DESC) AS rn FROM Expenses WHERE isPaid = ? AND clientId = ?) t WHERE rn = 1 ORDER BY paidToUserType, paidTo`;

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

export default expenseDB;
