import moment from "moment";
import CONSTANTS from "../config/constants";
import duesDB from "../models/dues.model";
import occupancyDB from "../models/occupancy.model";
import log from "../config/log";
import ledgerDB from "../models/ledger.model";
import adjustExcessPayments, {
  adjustExcessPaymentsForMovedOutX,
} from "../utils/adjustExcessPayment";
import getDueDescription from "../utils/getDueDescription";
import moveOutDB from "../models/moveOut.model";
import moveOutDuesDB from "../models/moveOutDues.model";
import generateLedgerReferenceId from "./generateLedgerReferenceId";
import { setDueTallyStatus, setMoveOutDueTallyStatus } from "./setTallyStatus";

export const AddDues = async (
  tenantId: number,
  amount: number,
  type: number,
  occupancy: any,
  clientId: string,
  startDate: string,
  endDate: string,
  dueDate: string,
  rentDuration: number,
  description: string = "",
  title: string = "",
  dueDescription: string = "",
  referenceId: string = "",
  isAutoAdjustEnabled = 0,
) => {
  try {
    if (type === CONSTANTS.DUES_TYPES.OTHER) {
      dueDescription = title;
    } else if (type === CONSTANTS.DUES_TYPES.RENT && dueDescription.trim() === "") {
      dueDescription = `Advance Rent`;
    }

    let prevBalance = await ledgerDB.getPreviousBalance({
      tenantId,
      clientId,
    });

    if (type === CONSTANTS.DUES_TYPES.SECURITY) {
      const isSecurityAdded = await ledgerDB.getByTenantIdAndDueType({
        tenantId,
        clientId,
        type: CONSTANTS.DUES_TYPES.SECURITY,
      });

      if (!isSecurityAdded) {
        //security not added, adding security due
        const dueId = await duesDB.addWithStartEndDateX({
          tenantId,
          amount,
          occupancyId: occupancy.id,
          roomId: occupancy.roomId,
          propId: occupancy.propId,
          clientId,
          rentStartDate: null,
          rentEndDate: null,
          type: type,
          dueDate: dueDate,
          balance: amount,
          ledgerReferenceId: referenceId,
          description: description,
          title: title,
        });
        await ledgerDB.add({
          tenantId,
          roomId: occupancy.roomId,
          propId: occupancy.propId,
          clientId,
          amount,
          balance: amount,
          referenceId: referenceId,
          transactionId: null,
          type: type,
          rentStartDate: null,
          rentEndDate: null,
          dueDate: dueDate,
          description: `${dueDescription} for ${moment(dueDate).format("DD MMM, YY")}`,
          title: title,
        });

        await setDueTallyStatus(
          Number(clientId),
          dueId,
          CONSTANTS.TALLY_STATUS.PENDING
        );

        await occupancyDB.updateSecurity({
            tenantId,
            clientId,
            security: amount,
        });
      } else {
        //secuirty already added, changing exsiting records in dues and ledger
        const securityDue = await duesDB.getByTenantIdAndLedgerReferenceId({
          tenantId,
          ledgerReferenceId: isSecurityAdded.referenceId,
        });

        if (securityDue) {
          //security is partially paid or not paid
          await duesDB.updateAmount({
            id: securityDue[0].id,
            amount: securityDue[0].amount + amount,
          });
          await duesDB.updateBalance({ id: securityDue[0].id, balance: securityDue[0].balance + amount });
          await occupancyDB.updateSecurity({
            tenantId: securityDue[0].tenantId,
            clientId: clientId,
            security: securityDue[0].amount + amount,
          });
          await ledgerDB.updateAmount({
            tenantId: securityDue[0].tenantId,
            clientId: clientId,
            referenceId: securityDue[0].ledgerReferenceId,
            type: securityDue[0].type,
            amount: securityDue[0].amount + amount,
          });
          await ledgerDB.addBalance({
            tenantId: tenantId,
            clientId: clientId,
            referenceId: securityDue[0].ledgerReferenceId,
            type: securityDue[0].type,
            balance: amount,
          });
        } else if (!securityDue) {
          //security is fully paid
          const dueId = await duesDB.addWithStartEndDateX({
            tenantId,
            amount: Number(isSecurityAdded.amount) + amount,
            occupancyId: occupancy.id,
            roomId: occupancy.roomId,
            propId: occupancy.propId,
            clientId,
            rentStartDate: isSecurityAdded.rentStartDate,
            rentEndDate: isSecurityAdded.rentEndDate,
            type: type,
            dueDate: isSecurityAdded.dueDate,
            balance: amount,
            ledgerReferenceId: isSecurityAdded.referenceId,
            description: isSecurityAdded.description,
            title: title,
          });
          await ledgerDB.updateAmount({
            tenantId: isSecurityAdded.tenantId,
            clientId: clientId,
            referenceId: isSecurityAdded.referenceId,
            type: isSecurityAdded.type,
            amount: isSecurityAdded.amount + amount,
          });
          await ledgerDB.addBalance({
            tenantId: tenantId,
            clientId: clientId,
            referenceId: isSecurityAdded.referenceId,
            type: isSecurityAdded.type,
            balance: amount,
          });
          await occupancyDB.addSecurity({
            tenantId: tenantId,
            clientId: clientId,
            security: amount,
          });

          await setDueTallyStatus(
            Number(clientId),
            dueId,
            CONSTANTS.TALLY_STATUS.PENDING
          );

        } else {
          log.info(
            `[Due Handler], [AddDues], Client Id [${clientId}], Tenant Id [${tenantId}], Amount [${amount}], Something is wrong with security due`
          );
        }
      }
    } else {
      const dueId = await duesDB.addWithStartEndDateX({
        tenantId,
        amount,
        occupancyId: occupancy.id,
        roomId: occupancy.roomId,
        propId: occupancy.propId,
        clientId,
        rentStartDate: startDate || null,
        rentEndDate: endDate || null,
        type: type,
        dueDate: dueDate,
        balance: amount,
        ledgerReferenceId: referenceId,
        description: description,
        title: title,
      });
      await ledgerDB.add({
        tenantId,
        roomId: occupancy.roomId,
        propId: occupancy.propId,
        clientId,
        amount,
        balance: amount,
        referenceId: referenceId,
        transactionId: null,
        type: type,
        rentStartDate: startDate || null,
        rentEndDate: endDate || null,
        dueDate: dueDate,
        description: startDate && endDate 
          ? `${type === CONSTANTS.DUES_TYPES.FINE && description && description.trim() !== "" && description !== "null" ? description : dueDescription} for ${moment(startDate).format("DD MMM YY")} to ${moment(endDate).format("DD MMM YY")}`
          : `${type === CONSTANTS.DUES_TYPES.FINE && description && description.trim() !== "" && description !== "null" ? description : dueDescription} for ${moment(dueDate).format("DD MMM, YY")}`,
        title: title,
      });

      await setDueTallyStatus(
        Number(clientId),
        dueId,
        CONSTANTS.TALLY_STATUS.PENDING
      );
    }

    if (occupancy.status === CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT) {
      await moveOutDB.updateTenantDue({
        tenantId,
        roomId: occupancy.roomId,
        propId: occupancy.propId,
        tenantDues: amount,
      });
    }

    if (type === CONSTANTS.DUES_TYPES.RENT) {
      await occupancyDB.updateRentalMonths({
        tenantId,
        clientId,
        rentalMonths: Number(rentDuration),
      });
    }

    if (prevBalance && prevBalance < 0) {
      if ((occupancy.status === CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT) && Number(isAutoAdjustEnabled) === 0) {
        const securityAdjustEntry = await ledgerDB.getLastEntry({
          tenantId,
          clientId,
        });

        if (securityAdjustEntry !== false) {
          await ledgerDB.removeById({
            id: securityAdjustEntry.id,
          });

          //creating new security entry after deleting previous
          await ledgerDB.add({
            tenantId: securityAdjustEntry.tenantId,
            roomId: securityAdjustEntry.roomId,
            propId: securityAdjustEntry.propId,
            clientId: clientId,
            amount: securityAdjustEntry.amount,
            balance: securityAdjustEntry.balance,
            referenceId: securityAdjustEntry.referenceId,
            transactionId: securityAdjustEntry.transactionId,
            type: securityAdjustEntry.type,
            rentStartDate: securityAdjustEntry.rentStartDate,
            rentEndDate: securityAdjustEntry.rentEndDate,
            description: securityAdjustEntry.description,
            dueDate: securityAdjustEntry.dueDate,
          });
        }
      } else {
        log.info(`Adjust Excess Payment Calling below`);
        await adjustExcessPayments({
          tenantId: tenantId,
          clientId: clientId,
          amountPaid: Math.abs(Number(prevBalance)),
          ledgerReferenceId: referenceId,
        });
      }
    }
  } catch (error: any) {
    log.info(`[Due Handler], [AddDues], Error: ${error?.message || error}`);

    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    };
  }
};

export const AddMovedOutDues = async (
  tenantId: number,
  amount: number,
  type: number,
  occupancy: any,
  clientId: string,
  startDate: string,
  endDate: string,
  dueDate: string,
  rentDuration: number,
  description: string = "",
  title: string = "",
  dueDescription: string = "",
  referenceId: string = "",
  recordedBy: string = "",
) => {
  try {
    if (type === CONSTANTS.DUES_TYPES.OTHER) {
      dueDescription = title;
    } else if (type === CONSTANTS.DUES_TYPES.RENT) {
      dueDescription = `Advance Rent`;
    }

    let prevBalance = await ledgerDB.getPreviousBalance({
      tenantId,
      clientId,
    });

    const dueId = await moveOutDuesDB.add({
      moveOutId: occupancy.id,
      tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      clientId,
      amount,
      balance: amount,
      ledgerReferenceId: referenceId,
      dueDate: dueDate,
      type: type,
      rentStartDate: startDate,
      rentEndDate: endDate,
      description: description,
      title: title,
    });
    await ledgerDB.add({
      tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      clientId,
      amount,
      balance: amount,
      referenceId: referenceId,
      transactionId: null,
      type: type,
      rentStartDate: startDate,
      rentEndDate: endDate,
      dueDate: dueDate,
      description: `${type === CONSTANTS.DUES_TYPES.FINE && description && description.trim() !== "" && description !== "null" ? description : dueDescription} for ${moment(startDate).format(
        "DD MMM YY"
      )} to ${moment(endDate).format("DD MMM YY")}`,
      title: title,
    });

    await setMoveOutDueTallyStatus(
      Number(clientId),
      dueId,
      CONSTANTS.TALLY_STATUS.PENDING
    );

    await moveOutDB.updateTenantDue({
      tenantId,
      tenantDues: amount,
      propId: occupancy.propId,
      roomId: occupancy.roomId,
    });

    if (prevBalance && prevBalance < 0) {
      await adjustExcessPaymentsForMovedOutX({
        tenantId: tenantId,
        clientId: clientId,
        amountPaid: Math.abs(Number(prevBalance)),
        ledgerReferenceId: referenceId,
        markedFromSecurity: 1,
        recordedBy: recordedBy,
      });
    }
  } catch (error: any) {
    log.info(`[Due Handler], [AddDues], Error: ${error?.message || error}`);

    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    };
  }
};

export const AddMovedOutDuesWithoutAdjust = async (
  tenantId: number,
  amount: number,
  type: number,
  occupancy: any,
  clientId: string,
  startDate: string,
  endDate: string,
  dueDate: string,
  rentDuration: number,
  description: string = "",
  title: string = "",
  dueDescription: string = "",
  referenceId: string = ""
) => {
  try {
    if (type === CONSTANTS.DUES_TYPES.OTHER) {
      dueDescription = title;
    } else if (type === CONSTANTS.DUES_TYPES.RENT) {
      dueDescription = `Advance Rent`;
    }

    const dueId = await moveOutDuesDB.add({
      moveOutId: occupancy.id,
      tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      clientId,
      amount,
      balance: amount,
      ledgerReferenceId: referenceId,
      dueDate: dueDate,
      type: type,
      rentStartDate: startDate,
      rentEndDate: endDate,
      description: description,
      title: title,
    });
    await ledgerDB.add({
      tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      clientId,
      amount,
      balance: amount,
      referenceId: referenceId,
      transactionId: null,
      type: type,
      rentStartDate: startDate,
      rentEndDate: endDate,
      dueDate: dueDate,
      description: `${type === CONSTANTS.DUES_TYPES.FINE && description && description.trim() !== "" && description !== "null" ? description : dueDescription} for ${moment(startDate).format(
        "DD MMM YY"
      )} to ${moment(endDate).format("DD MMM YY")}`,
      title: title,
    });

    await setMoveOutDueTallyStatus(
      Number(clientId),
      dueId,
      CONSTANTS.TALLY_STATUS.PENDING
    );

    await moveOutDB.updateTenantDue({
      tenantId,
      tenantDues: amount,
      propId: occupancy.propId,
      roomId: occupancy.roomId,
    });

    const securityAdjustEntry = await ledgerDB.getLastEntry({
      tenantId,
      clientId,
    });

    if (securityAdjustEntry !== false) {
      await ledgerDB.removeById({
        id: securityAdjustEntry.id,
      });

      //creating new security entry after deleting previous
      await ledgerDB.add({
        tenantId: securityAdjustEntry.tenantId,
        roomId: securityAdjustEntry.roomId,
        propId: securityAdjustEntry.propId,
        clientId: clientId,
        amount: securityAdjustEntry.amount,
        balance: securityAdjustEntry.balance,
        referenceId: securityAdjustEntry.referenceId,
        transactionId: securityAdjustEntry.transactionId,
        type: securityAdjustEntry.type,
        rentStartDate: securityAdjustEntry.rentStartDate,
        rentEndDate: securityAdjustEntry.rentEndDate,
        description: securityAdjustEntry.description,
        dueDate: securityAdjustEntry.dueDate,
      });
    }
  } catch (error: any) {
    log.info(`[Due Handler], [AddDues], Error: ${error?.message || error}`);

    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    };
  }
};

export const MarkPaid = async (
  tenantId: number,
  amtPaid: number,
  allDues: any,
  occupancy: any,
  ledgerReferenceId: string,
  transId: string,
  markedFromSecurity: number,
) => {
  try {
    const U = "Due Handler";
    const F = "MarkPaid";

    let count = 1;
    let lengthOfDues = allDues.length;
    let duesStatsArr = [];
    let dueStats = {};
    let receiptDescription = "";
    let totalAmount = amtPaid;

    if (amtPaid != 0) {
      for (const due of allDues) {
        if (amtPaid == 0) break;

        let securityAdjustEntry = await ledgerDB.getLastEntryX({
          tenantId,
          clientId: due.clientId,
          createdAt: occupancy?.moveInDate,
        });

        let dueDescription = "";

        if (due.type === CONSTANTS.DUES_TYPES.OTHER) {
          dueDescription = due.title;
          if (dueDescription === null) {
            dueDescription = await getDueDescription(allDues[0].type);
          }
        } else if (
          due.title &&
          due.title.toLowerCase().includes("advance rent")
        ) {
          dueDescription = "Advance Rent";
        } else if (Number(due.type) === CONSTANTS.DUES_TYPES.FINE && due.description && due.description.trim() !== "") {
          dueDescription = due.description;
        } else {
          dueDescription = await getDueDescription(due.type);
        }

        let addDiscountInReceipt = true;

        if (due.balance > amtPaid) {
          dueDescription = "Partial payment for " + dueDescription;
          addDiscountInReceipt = false;
        } else if (due.balance < due.amount) {
          dueDescription = "Final payment for " + dueDescription;
        }

        if (due.type === CONSTANTS.DUES_TYPES.RENT) {
          dueDescription =
            dueDescription +
            " for " +
            moment(due.rentStartDate).format("DD MMM, YY") +
            " to " +
            moment(due.rentEndDate).format("DD MMM, YY");
        } else {
          dueDescription =
            dueDescription + " for " + moment(due.dueDate).format("DD MMM, YY");
        }

        if (markedFromSecurity === 1) {
          dueDescription += ` (Adjusted from security)`
        }

        if (amtPaid <= due.balance) {
          await ledgerDB.add({
            tenantId,
            roomId: occupancy.roomId,
            propId: occupancy.propId,
            clientId: occupancy.clientId,
            amount: -amtPaid,
            balance: due.balance - amtPaid,
            referenceId: ledgerReferenceId,
            transactionId: transId,
            type: due.type,
            rentStartDate: due.rentStartDate,
            rentEndDate: due.rentEndDate,
            dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
            description: due.discount > 0 ? amtPaid === due.balance ? `${dueDescription}, Discount of ₹${due.discount} given for this due` : dueDescription : dueDescription,
            discount: due.discount,
            title: due?.title || null,
            subType: markedFromSecurity === 1 ? CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY : 0,
          });

          receiptDescription = dueDescription;

          if (amtPaid == due.balance) {
            await duesDB.removeDue({ id: due.id });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            log.info(
              `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Deleted]`
            );
          } else {
            await duesDB.updateBalance({
              id: due.id,
              balance: due.balance - amtPaid,
            });
            dueStats = { title: dueDescription, amount: amtPaid };
            duesStatsArr.push(dueStats);
            log.info(
              `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Updated]`
            );
          }
          amtPaid = 0;
        } else {
          if (count == lengthOfDues) {
            amtPaid -= due.balance;
            await ledgerDB.add({
              tenantId,
              roomId: occupancy.roomId,
              propId: occupancy.propId,
              clientId: occupancy.clientId,
              amount: -due.balance,
              balance: -amtPaid,
              referenceId: ledgerReferenceId,
              transactionId: transId,
              type: due.type,
              rentStartDate: null,
              rentEndDate: null,
              dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
              description: due.discount > 0 ? `${dueDescription}, Discount of ₹${due.discount} given for this due` : dueDescription,
              discount: due.discount,
              title: due?.title || null,
              subType: markedFromSecurity === 1 ? CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY : 0,
            });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            receiptDescription = dueDescription;
            // receiptDescription =
            //   dueDescription + " for " + moment(due.dueDate).format("MMM YYYY");
            //break;
          } else {
            await ledgerDB.add({
              tenantId,
              roomId: occupancy.roomId,
              propId: occupancy.propId,
              clientId: occupancy.clientId,
              amount: -due.balance,
              balance: 0,
              referenceId: ledgerReferenceId,
              transactionId: transId,
              type: due.type,
              rentStartDate: null,
              rentEndDate: null,
              dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
              description: due.discount > 0 ? `${dueDescription}, Discount of ₹${due.discount} given for this due` : dueDescription,
              discount: due.discount,
              title: due?.title || null,
              subType: markedFromSecurity === 1 ? CONSTANTS.LEDGER_SUBTYPES.MARKED_FROM_SECURITY : 0,
            });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            receiptDescription = dueDescription;
            // receiptDescription =
            //   dueDescription + " for " + moment(due.dueDate).format("MMM YYYY");
            amtPaid -= due.balance;
          }
          await duesDB.removeDue({ id: due.id });
          log.info(
            `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Deleted]`
          );
        }
        count++;
        if (due.discount > 0 && addDiscountInReceipt) {
          dueStats = { title: "Discount", amount: -due.discount };
          duesStatsArr.push(dueStats);
        }

        if (due.type === CONSTANTS.DUES_TYPES.SECURITY && occupancy.status === CONSTANTS.OCCUPANCY_STATUS.MOVING_OUT) {
          let securityAmt = totalAmount >= due.balance ? due.balance : totalAmount;
          const refundEntry = await ledgerDB.getLastEntry({
            tenantId, 
            clientId: occupancy.clientId,
          });

          if (securityAdjustEntry) {
            await ledgerDB.addBalance({
              tenantId,
              clientId: occupancy.clientId,
              balance: -securityAmt,
              type: securityAdjustEntry.type,
              referenceId: securityAdjustEntry.referenceId,
            });
            
            securityAdjustEntry = await ledgerDB.getLastEntryX({
              tenantId,
              clientId: due.clientId,
              createdAt: occupancy?.moveInDate,
            });

          } else {
            const referenceId = await generateLedgerReferenceId({ clientId: occupancy.clientId });
            ledgerDB.add({
              tenantId,
              roomId: occupancy.roomId,
              propId: occupancy.propId,
              clientId: occupancy.clientId,
              amount: 0,
              balance: -securityAmt,
              referenceId: referenceId,
              transactionId: null,
              type: CONSTANTS.DUES_TYPES.SECURITY,
              rentStartDate: null,
              rentEndDate: null,
              dueDate: occupancy.moveOutDate,
              description:
                "Security deposit and any excess amounts paid by tenant. Refund after eviction.",
            });
          }
        }

        if (securityAdjustEntry !== false) {
          await ledgerDB.removeById({
            id: securityAdjustEntry.id,
          });

          //creating new security entry after deleting previous
          await ledgerDB.add({
            tenantId: securityAdjustEntry.tenantId,
            roomId: securityAdjustEntry.roomId,
            propId: securityAdjustEntry.propId,
            clientId: due.clientId,
            amount: securityAdjustEntry.amount,
            balance: markedFromSecurity === 1 ? securityAdjustEntry.balance + totalAmount : securityAdjustEntry.balance,
            referenceId: securityAdjustEntry.referenceId,
            transactionId: securityAdjustEntry.transactionId,
            type: securityAdjustEntry.type,
            rentStartDate: securityAdjustEntry.rentStartDate,
            rentEndDate: securityAdjustEntry.rentEndDate,
            description: securityAdjustEntry.description,
            dueDate: securityAdjustEntry.dueDate,
          });
        }

        log.info(
          `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], Transaction has been recorded successfully`
        );
      }
    }

    return {
      dueStats,
      duesStatsArr,
      receiptDescription,
    };
  } catch (error: any) {
    log.info(`[Due Handler], [MarkPaid], Error: ${error?.message || error}`);
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    };
  }
};

export const MarkPaidForMovedOut = async (
  tenantId: number,
  amtPaid: number,
  allDues: any,
  occupancy: any,
  ledgerReferenceId: string,
  transId: string
) => {
  try {
    const U = "Due Handler";
    const F = "MarkPaid";

    let count = 1;
    let lengthOfDues = allDues.length;
    let duesStatsArr = [];
    let dueStats = {};
    let receiptDescription = "";

    if (amtPaid != 0) {
      for (const due of allDues) {
        if (amtPaid == 0) break;

        const securityAdjustEntry = await ledgerDB.getLastEntry({
          tenantId,
          clientId: due.clientId,
        });
        let dueDescription = "";

        if (due.type === CONSTANTS.DUES_TYPES.OTHER) {
          dueDescription = due.title;
          if (dueDescription === null) {
            dueDescription = await getDueDescription(allDues[0].type);
          }
        } else if (
          due.title &&
          due.title.toLowerCase().includes("advance rent")
        ) {
          dueDescription = "Advance Rent";
        } else if (due.type === CONSTANTS.DUES_TYPES.FINE && due.description && due.description.trim() !== "") {
          dueDescription = due.description;
        } else {
          dueDescription = await getDueDescription(due.type);
        }

        if (due.balance > amtPaid) {
          dueDescription = "Partial payment for " + dueDescription;
        } else if (due.balance < due.amount) {
          dueDescription = "Final payment for " + dueDescription;
        }

        if (due.type === CONSTANTS.DUES_TYPES.RENT) {
          dueDescription =
            dueDescription +
            " for " +
            moment(due.rentStartDate).format("DD MMM, YY") +
            " to " +
            moment(due.rentEndDate).format("DD MMM, YY");
        } else {
          dueDescription =
            dueDescription + " for " + moment(due.dueDate).format("DD MMM, YY");
        }

        if (amtPaid <= due.balance) {
          await ledgerDB.add({
            tenantId,
            roomId: occupancy.roomId,
            propId: occupancy.propId,
            clientId: occupancy.clientId,
            amount: -amtPaid,
            balance: due.balance - amtPaid,
            referenceId: ledgerReferenceId,
            transactionId: transId,
            type: due.type,
            rentStartDate: due.rentStartDate,
            rentEndDate: due.rentEndDate,
            dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
            description: due.discount > 0 
              ? amtPaid === due.balance
                ? `${dueDescription}, Discount of ₹${due.discount} given for this due` 
                : dueDescription
              : dueDescription,
            discount: due.discount,
            title: due?.title || null,
          });

          receiptDescription = dueDescription;

          if (amtPaid == due.balance) {
            await moveOutDuesDB.removeDue({ id: due.id });
            await moveOutDB.subtractTenantDue({
              clientId: occupancy.clientId,
              tenantId,
              tenantDues: due.balance,
              propId: occupancy.propId,
              roomId: occupancy.roomId,
            });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            log.info(
              `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Deleted]`
            );
          } else {
            await moveOutDuesDB.updateBalance({
              id: due.id,
              balance: due.balance - amtPaid,
            });
            await moveOutDB.subtractTenantDue({
              clientId: occupancy.clientId,
              tenantId,
              tenantDues: amtPaid,
              propId: occupancy.propId,
              roomId: occupancy.roomId,
            });
            dueStats = { title: dueDescription, amount: amtPaid };
            duesStatsArr.push(dueStats);
            log.info(
              `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Updated]`
            );
          }
          amtPaid = 0;
        } else {
          if (count == lengthOfDues) {
            amtPaid -= due.balance;
            await ledgerDB.add({
              tenantId,
              roomId: occupancy.roomId,
              propId: occupancy.propId,
              clientId: occupancy.clientId,
              amount: -due.balance,
              balance: -amtPaid,
              referenceId: ledgerReferenceId,
              transactionId: transId,
              type: due.type,
              rentStartDate: null,
              rentEndDate: null,
              dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
              description: due.discount > 0 ? `${dueDescription}, Discount of ₹${due.discount} given for this due` : dueDescription,
              discount: due.discount,
              title: due?.title || null,
            });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            receiptDescription = dueDescription;
            // receiptDescription =
            //   dueDescription + " for " + moment(due.dueDate).format("MMM YYYY");
            //break;
          } else {
            await ledgerDB.add({
              tenantId,
              roomId: occupancy.roomId,
              propId: occupancy.propId,
              clientId: occupancy.clientId,
              amount: -due.balance,
              balance: 0,
              referenceId: ledgerReferenceId,
              transactionId: transId,
              type: due.type,
              rentStartDate: null,
              rentEndDate: null,
              dueDate: due.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
              description: due.discount > 0 ? `${dueDescription}, Discount of ₹${due.discount} given for this due` : dueDescription,
              discount: due.discount,
              title: due?.title || null,
            });
            dueStats = { title: dueDescription, amount: due.balance + due.discount };
            duesStatsArr.push(dueStats);
            receiptDescription = dueDescription;
            // receiptDescription =
            //   dueDescription + " for " + moment(due.dueDate).format("MMM YYYY");
            amtPaid -= due.balance;
          }
          await moveOutDuesDB.removeDue({ id: due.id });
          await moveOutDB.subtractTenantDue({
            clientId: occupancy.clientId,
            tenantId,
            tenantDues: due.balance,
            propId: occupancy.propId,
            roomId: occupancy.roomId,
          });
          log.info(
            `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], [Due Deleted]`
          );
        }
        count++;

        if (securityAdjustEntry !== false) {
          await ledgerDB.removeById({
            id: securityAdjustEntry.id,
          });

          //creating new security entry after deleting previous
          await ledgerDB.add({
            tenantId: securityAdjustEntry.tenantId,
            roomId: securityAdjustEntry.roomId,
            propId: securityAdjustEntry.propId,
            clientId: due.clientId,
            amount: securityAdjustEntry.amount,
            balance: securityAdjustEntry.balance,
            referenceId: securityAdjustEntry.referenceId,
            transactionId: securityAdjustEntry.transactionId,
            type: securityAdjustEntry.type,
            rentStartDate: securityAdjustEntry.rentStartDate,
            rentEndDate: securityAdjustEntry.rentEndDate,
            description: securityAdjustEntry.description,
            dueDate: securityAdjustEntry.dueDate,
          });
        }
        log.info(
          `[${U}], [${F}], Tenant Id [${tenantId}], Ledger Reference Id [${ledgerReferenceId}], Due Id [${due.id}], Due Type [${due.type}], Transaction has been recorded successfully`
        );
      }
    }

    return {
      dueStats,
      duesStatsArr,
      receiptDescription,
    };
  } catch (error: any) {
    log.info(
      `[Due Handler], [MarkPaidForMovedOut], Error: ${error?.message || error}`
    );
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    };
  }
};
