import log from "../config/log";
import tenantDB from "../models/tenant.model";
import CONSTANTS from "../config/constants";
import occupancyDB from "../models/occupancy.model";
import propertyDB from "../models/property.model";
import roomDB from "../models/room.model";
import duesDB from "../models/dues.model";
import generateTransId from "./generateTransId";
import createReceiptMultipleDues from "./createReceiptMultipleDues";
import flatDB from "../models/flat.model";
import moment from "moment";
import getModeName from "./getModeName";
import transactionDB from "../models/transaction.model";
import sendNotification from "./sendNotification";
import sendSMS from "./sendSMS";
import clientDB from "../models/client.model";
import ledgerDB from "../models/ledger.model";
import getDueDescription from "./getDueDescription";
import settingsDB from "../models/settings.model";
import moveOutDB from "../models/moveOut.model";
import { setTransactionTallyBillRef, setTransactionTallyStatus } from "./setTallyStatus";
import { generateRentReciept } from "./generateRentReciept";

const addTransactions = async ({
  due,
  clientId,
  tenantId,
  amount,
  description,
  mode,
  recordedBy,
  duesStatsArr,
}: any) => {
  try {
    const transGId: string = await generateTransId();
    // const occupancy = await occupancyDB.getByTenantId({ tenantId });
    let occupancy = await occupancyDB.getByTenantIdAndClientId({
      clientId: clientId,
      tenantId: tenantId,
    });
    const property = await propertyDB.getById({ id: occupancy.propId });
    const room = await roomDB.getById({ id: occupancy.roomId });
    const client = await clientDB.getById({ id: occupancy.clientId });
    const tenant = await tenantDB.getById({ id: tenantId });

    let transId = await transactionDB.add({
      gId: transGId,
      clientId: occupancy.clientId,
      tenantId: occupancy.tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      amount: amount,
      name: description,
      type: CONSTANTS.TRANSACTION_TYPES.TENANT_PAID,
      transactionFor: due?.type || CONSTANTS.TRANSACTION_FOR.OTHER,
      status: CONSTANTS.TRANSACTION_STATUS.SUCCESS,
      dueDate: due?.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
      receipt: "",
      mode: mode,
      collectionDate: moment().format("YYYY-MM-DD HH:mm:ss"),
      propName: property.name,
      roomNum: room.roomNum,
      ledgerReferenceId: due?.ledgerReferenceId || null,
      recordedBy: recordedBy,
      title: due?.title || null,
      isFinanciallyApplicable: Number(mode) === CONSTANTS.TRANSACTION_MODES.ADJUSTED_FROM_SECURITY ? 0 : 1,
    });

    let settings = await settingsDB.getByClientIdAndPropId({
      clientId: client.id,
      propId: occupancy.propId,
    });

    let logo = settings?.logo 
      ? process.env.RS_LOGO_URI + client?.id + "/" + occupancy?.propId + "/" + settings?.logo
      : client?.logo
        ? process.env.RS_LOGO_URI + client?.id + "/" + client?.logo
        : String(process.env.RS_DEFAULT_LOGO_URI);

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

    let isGstEnabled = property?.isGstEnabled || 0;
    let invoiceNo = property?.invoiceNo || null;
    let invoiceNoPrefix = property?.invoiceNoPrefix || null;
    let gstNo = property?.gstNo || null;
    let businessName = property?.ownerName || ""
    let transactionInvoiceNo = ""
    let prefix = "";
    if(0 != isGstEnabled && 0 != invoiceNo) {
        let getGstTransactions = await transactionDB.getByGstNo ({ gstNo });
        if(false == getGstTransactions) {
          if(null != invoiceNoPrefix){
            prefix = invoiceNoPrefix;
          }
          transactionInvoiceNo = `${prefix}${invoiceNo}`;
        } else {
          invoiceNo = getGstTransactions?.invoiceNo;
          if(null != invoiceNoPrefix){
            prefix = invoiceNoPrefix;
            invoiceNo = invoiceNo.replace(prefix, "");
            transactionInvoiceNo = `${prefix}${String(Number(invoiceNo)+1)}`;
          } else {
            transactionInvoiceNo = String(Number(invoiceNo)+1);
          }
        } 
        businessName = property?.businessName || "";
    } else {
      isGstEnabled = 0;
    }

    // const receipt = await createReceiptMultipleDues({
    //   // title: transTitle,
    //   title: `${transId}_${transGId}`,
    //   roomNum: room.roomNum,
    //   propName: property.name,
    //   dueDate: moment(due?.dueDate).format("MMM, YYYY") || null,
    //   mode: getModeName(mode),
    //   transGId,
    //   paidDate: moment().format("DD MMM, YYYY"),
    //   month:
    //     moment(due?.dueDate).format("MMM, YYYY") ||
    //     moment().format("MMM, YYYY"),
    //   tenantName: tenant?.name || "",
    //   amount: Number(amount) || 0,
    //   address: `${property?.address}`,
    //   landlord: businessName || "",
    //   landlordNumber: property?.ownerMobile || "",
    //   logo: logo,
    //   "landlord-pan": "",
    //   occupancy,
    //   dueStats: duesStatsArr,
    //   flatName,
    //   propType: property.type,
    //   isGstEnabled,
    //   transactionInvoiceNo,
    //   gstNo,
    // });
    const receipt = await generateRentReciept({
      // title: transTitle,
      title: `${transId}_${transGId}`,
      roomNum: room.roomNum,
      propName: property.name,
      dueDate: moment(due?.dueDate).format("MMM, YYYY") || null,
      mode: getModeName(mode),
      transGId,
      paidDate: moment().format("DD MMM, YYYY HH:mm:ss"),
      month:
        moment(due?.dueDate).format("MMM, YYYY") ||
        moment().format("MMM, YYYY"),
      tenantName: tenant?.name || "",
      amount: Number(amount) || 0,
      address: `${property?.address}`,
      landlord: businessName || "",
      landlordNumber: property?.ownerMobile || "",
      logo: logo,
      "landlord-pan": "",
      occupancy,
      dueStats: duesStatsArr,
      flatName,
      propType: property.type,
      isGstEnabled,
      transactionInvoiceNo,
      gstNo,
      recordedBy
    });
    if(0 != isGstEnabled && 0 != invoiceNo) {
        await transactionDB.updateReceiptWithInvoice ({ id : transId, receipt, invoiceNo: transactionInvoiceNo, gstNo });
    } else {
      await transactionDB.updateReceipt({
        id: transId,
        receipt,
      });
    }

    await setTransactionTallyStatus(
      Number(clientId),
      transId,
      CONSTANTS.TALLY_STATUS.PENDING,
    );

    await setTransactionTallyBillRef(
      Number(clientId),
      transId,
      due?.tallyBillRef,
    );

    return transId;

  } catch (error: any) {
    log.info(`Error while adding Transaction ${error?.message || error}`);

    return `Error: ${error?.message || error}`;
  }
};

export const addTransactionsOnline = async ({
  due,
  clientId,
  tenantId,
  amount,
  description,
  mode,
  transGId,
  charges,
  gstAmount,
}: any) => {
  try {
    // const transGId: string = await generateTransId();
    // const occupancy = await occupancyDB.getByTenantId({ tenantId });
    let occupancy = await occupancyDB.getByTenantIdAndClientId({
      clientId: clientId,
      tenantId: tenantId,
    });
    const property = await propertyDB.getById({ id: occupancy.propId });
    const room = await roomDB.getById({ id: occupancy.roomId });
    const client = await clientDB.getById({ id: occupancy.clientId });
    const tenant = await tenantDB.getById({ id: tenantId });

    let transId = await transactionDB.addOnline({
      gId: transGId,
      bankId: property.bankId,
      clientId: occupancy.clientId,
      tenantId: occupancy.tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      amount: amount,
      name: description,
      type: CONSTANTS.TRANSACTION_TYPES.TENANT_PAID,
      transactionFor: due?.type || CONSTANTS.TRANSACTION_FOR.OTHER,
      status: CONSTANTS.TRANSACTION_STATUS.SUCCESS,
      dueDate: due?.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
      receipt: "",
      mode,
      collectionDate: moment().format("YYYY-MM-DD HH:mm:ss"),
      propName: property.name,
      roomNum: room.roomNum,
      ledgerReferenceId: due?.ledgerReferenceId || "",
      recordedBy: "Kipinn App",
      charges: charges,
      gstCharges: gstAmount,
      title: due?.title || null,
      isFinanciallyApplicable: 1,
    });

    // await setTransactionTallyStatus(
    //   Number(clientId),
    //   transId,
    //   CONSTANTS.TALLY_STATUS.PENDING,
    // );

    await setTransactionTallyBillRef(
      Number(clientId),
      transId,
      due?.tallyBillRef,
    );

    return transId;

  } catch (error: any) {
    log.info(`Error while adding Transaction ${error?.message || error}`);

    return `Error: ${error?.message || error}`;
  }
};

export const addTransactionsMoveOut = async ({
  due,
  clientId,
  tenantId,
  amount,
  description,
  mode,
  recordedBy,
  duesStatsArr,
}: any) => {
  try {
    const transGId: string = await generateTransId();
    // const occupancy = await occupancyDB.getByTenantId({ tenantId });
    let occupancy = await moveOutDB.getByTenantIdAndClientId({
      clientId: clientId,
      tenantId: tenantId,
    });
    const property = await propertyDB.getById({ id: occupancy.propId });
    const room = await roomDB.getById({ id: occupancy.roomId });
    const client = await clientDB.getById({ id: occupancy.clientId });
    const tenant = await tenantDB.getById({ id: tenantId });

    let transId = await transactionDB.add({
      gId: transGId,
      clientId: occupancy.clientId,
      tenantId: occupancy.tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      amount: amount,
      name: description,
      type: CONSTANTS.TRANSACTION_TYPES.TENANT_PAID,
      transactionFor: due?.type || CONSTANTS.TRANSACTION_FOR.OTHER,
      status: CONSTANTS.TRANSACTION_STATUS.SUCCESS,
      dueDate: due?.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
      receipt: "",
      mode: mode,
      collectionDate: moment().format("YYYY-MM-DD HH:mm:ss"),
      propName: property.name,
      roomNum: room.roomNum,
      ledgerReferenceId: due?.ledgerReferenceId || null,
      recordedBy: recordedBy,
      title: due?.title || null,
      isFinanciallyApplicable: Number(mode) === CONSTANTS.TRANSACTION_MODES.ADJUSTED_FROM_SECURITY ? 0 : 1,
    });

    let settings = await settingsDB.getByClientIdAndPropId({
      clientId: client.id,
      propId: occupancy.propId,
    });

    let logo = settings?.logo 
      ? process.env.RS_LOGO_URI + client?.id + "/" + occupancy?.propId + "/" + settings?.logo
      : client?.logo
        ? process.env.RS_LOGO_URI + client?.id + "/" + client?.logo
        : String(process.env.RS_DEFAULT_LOGO_URI);

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

    let isGstEnabled = property?.isGstEnabled || 0;
    let invoiceNo = property?.invoiceNo || null;
    let invoiceNoPrefix = property?.invoiceNoPrefix || null;
    let gstNo = property?.gstNo || null;
    let businessName = property?.ownerName || ""
    let transactionInvoiceNo = ""
    let prefix = "";
    if(0 != isGstEnabled && 0 != invoiceNo) {
        let getGstTransactions = await transactionDB.getByGstNo ({ gstNo });
        if(false == getGstTransactions) {
          if(null != invoiceNoPrefix){
            prefix = invoiceNoPrefix;
          }
          transactionInvoiceNo = `${prefix}${invoiceNo}`;
        } else {
          invoiceNo = getGstTransactions?.invoiceNo;
          if(null != invoiceNoPrefix){
            prefix = invoiceNoPrefix;
            invoiceNo = invoiceNo.replace(prefix, "");
            transactionInvoiceNo = `${prefix}${String(Number(invoiceNo)+1)}`;
          } else {
            transactionInvoiceNo = String(Number(invoiceNo)+1);
          }
        } 
        businessName = property?.businessName || "";
    } else {
      isGstEnabled = 0;
    }

    // const receipt = await createReceiptMultipleDues({
    //   // title: transTitle,
    //   title: `${transId}_${transGId}`,
    //   roomNum: room.roomNum,
    //   propName: property.name,
    //   dueDate: moment(due?.dueDate).format("MMM, YYYY") || null,
    //   mode: getModeName(mode),
    //   transGId,
    //   paidDate: moment().format("DD MMM, YYYY"),
    //   month:
    //     moment(due?.dueDate).format("MMM, YYYY") ||
    //     moment().format("MMM, YYYY"),
    //   tenantName: tenant?.name || "",
    //   amount: Number(amount) || 0,
    //   address: `${property?.address}`,
    //   landlord: businessName || "",
    //   landlordNumber: property?.ownerMobile || "",
    //   logo: logo,
    //   "landlord-pan": "",
    //   occupancy,
    //   dueStats: duesStatsArr,
    //   flatName,
    //   propType: property.type,
    //   isGstEnabled,
    //   transactionInvoiceNo,
    //   gstNo,
    // });
    const receipt = await generateRentReciept({
      // title: transTitle,
      title: `${transId}_${transGId}`,
      roomNum: room.roomNum,
      propName: property.name,
      dueDate: moment(due?.dueDate).format("MMM, YYYY") || null,
      mode: getModeName(mode),
      transGId,
      paidDate: moment().format("DD MMM, YYYY HH:mm:ss"),
      month:
        moment(due?.dueDate).format("MMM, YYYY") ||
        moment().format("MMM, YYYY"),
      tenantName: tenant?.name || "",
      amount: Number(amount) || 0,
      address: `${property?.address}`,
      landlord: businessName || "",
      landlordNumber: property?.ownerMobile || "",
      logo: logo,
      "landlord-pan": "",
      occupancy,
      dueStats: duesStatsArr,
      flatName,
      propType: property.type,
      isGstEnabled,
      transactionInvoiceNo,
      gstNo,
      recordedBy
    });
    if(0 != isGstEnabled && 0 != invoiceNo) {
        await transactionDB.updateReceiptWithInvoice ({ id : transId, receipt, invoiceNo: transactionInvoiceNo, gstNo });
    } else {
      await transactionDB.updateReceipt({
        id: transId,
        receipt,
      });
    }

    // await setTransactionTallyStatus(
    //   Number(clientId),
    //   transId,
    //   CONSTANTS.TALLY_STATUS.PENDING,
    // );

    await setTransactionTallyBillRef(
      Number(clientId),
      transId,
      due?.tallyBillRef,
    );

    return transId;

  } catch (error: any) {
    log.info(`Error while adding Transaction ${error?.message || error}`);

    return `Error: ${error?.message || error}`;
  }
};
export const addTransactionsOnlineMoveOut = async ({
  due,
  clientId,
  tenantId,
  amount,
  description,
  mode,
  transGId,
  charges,
  gstAmount,
}: any) => {
  try {
    // const transGId: string = await generateTransId();
    // const occupancy = await occupancyDB.getByTenantId({ tenantId });
    let occupancy = await moveOutDB.getByTenantIdAndClientId({
      clientId: clientId,
      tenantId: tenantId,
    });
    const property = await propertyDB.getById({ id: occupancy.propId });
    const room = await roomDB.getById({ id: occupancy.roomId });
    const client = await clientDB.getById({ id: occupancy.clientId });
    const tenant = await tenantDB.getById({ id: tenantId });

    let transId = await transactionDB.addOnline({
      gId: transGId,
      bankId: property.bankId,
      clientId: occupancy.clientId,
      tenantId: occupancy.tenantId,
      roomId: occupancy.roomId,
      propId: occupancy.propId,
      amount: amount,
      name: description,
      type: CONSTANTS.TRANSACTION_TYPES.TENANT_PAID,
      transactionFor: due?.type || CONSTANTS.TRANSACTION_FOR.OTHER,
      status: CONSTANTS.TRANSACTION_STATUS.SUCCESS,
      dueDate: due?.dueDate || moment().format("YYYY-MM-DD HH:mm:ss"),
      receipt: "",
      mode,
      collectionDate: moment().format("YYYY-MM-DD HH:mm:ss"),
      propName: property.name,
      roomNum: room.roomNum,
      ledgerReferenceId: "",
      recordedBy: "Kipinn App",
      charges: charges,
      gstCharges: gstAmount,
      title: due?.title || null,
      isFinanciallyApplicable: 1,
    });

    return transId;

  } catch (error: any) {
    log.info(`Error while adding Transaction ${error?.message || error}`);

    return `Error: ${error?.message || error}`;
  }
};

export default addTransactions;
