import log from "../config/log";
import { Cashfree } from "cashfree-pg";
import CONSTANTS from "../config/constants";
import { Request, Response } from "express";
import moveOutDuesDB from "../models/moveOutDues.model";
import duesDB from "../models/dues.model";
import tenantDB from "../models/tenant.model";
import CustomRequest from "../types/requestType";
import occupancyDB from "../models/occupancy.model";
import moveOutDB from "../models/moveOut.model";
import clientDB from "../models/client.model";
import propertyDB from "../models/property.model";
import getDueDescription from "../utils/getDueDescription";
import crypto from "crypto";
import moment from "moment";
import axios from "axios";
import { cashfreeCreatePaymentLink } from "../utils/cashfreePaymentLink";
import clientConfigDB from "../models/clientConfig.model";
import { stringify } from "querystring";

const cashfree: any = {};

cashfree.CreateOrder = async (req: CustomRequest, res: Response) => {
  const C = "Cashfree Controller";
  const F = "CreateOrder";
  try {
    let { amount, customerDetails, dueId, ledgerReferenceId, charges = 0, mode = 2, gstAmount = 0, payingFor = CONSTANTS.PAYING_FOR.APP } = req.body;

    const tenantId = req.id;
    const email = 'kipinn.com@gmail.com';
    const clientId = req.clientId;
    let isEvicted = req.isEvicted;
    
    if(!Number(mode)) {
      if(mode === 'card') {
        mode = CONSTANTS.TRANSACTION_MODES.CARD;
      } else if(mode === 'netBanking') {
        mode = CONSTANTS.TRANSACTION_MODES.NET_BANKING;
      } else {
        mode = CONSTANTS.TRANSACTION_MODES.UPI;
      }
    }
    
    if (!amount || !customerDetails) {
      log.info(
        `[${C}], [${F}], Amount [${amount}], Customer Details [${customerDetails}], Invalid Request`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    log.info(
      `[${C}], [${F}], Amount [${amount}], Customer Id [${customerDetails.customer_id}], Customer Name [${customerDetails.customer_name}], Customer Mobile [${customerDetails.customer_phone}], Payment Device ${payingFor === CONSTANTS.PAYING_FOR.APP ? "[APP]" : "[WEB LINK]"},  Paying for [${payingFor === CONSTANTS.PAYING_FOR.WEB_BOOKING_LINK ? "Booking" : "Due Payment"}]`
    );

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Tenant Requesting....`
    );

    const tenant = await tenantDB.getById({ id: tenantId });
    if (!tenant) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], No Tenant Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    //let dueIds = dueId.join(",");
    let dueIdsArray = dueId.split(",");  // convert string → array
    let dueIds = dueIdsArray.join(",");  // ensure proper format

    let totalAmount = 0;
    let isSingleDuePayment = dueIdsArray.length === 1 ? true : false;
    let isSecurityPayment = false;
    if (dueIdsArray && dueIdsArray.length > 0) {
      for (let id of dueIdsArray) {
        let due;
        if (Number(isEvicted) === 1) {
          due = await moveOutDuesDB.getById({ id });
        } else {
          due = await duesDB.getById({ id });
        }
        //due = await duesDB.getById({ id });
        if (!due) {
          log.info(
            `[${C}], [${F}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], Mode [${mode}], No Due Found with this Id [${id}]`
          );
          return res
            .status(400)
            .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
        }
        if (isSingleDuePayment) {
          if (due.type === CONSTANTS.DUES_TYPES.SECURITY) {
            isSecurityPayment = true;
          }
        }
        totalAmount += due.balance;
      }
    }

    // const occupancy = await occupancyDB.getByTenantId({
    //   tenantId: tenantId,
    // });
    let occupancy = await occupancyDB.getByTenantIdAndClientId({
      tenantId: tenantId,
      clientId: clientId,
    });

    if (Number(isEvicted) === 1) {
      occupancy = await moveOutDB.getByTenantIdAndClientId({
        tenantId: tenantId,
        clientId: clientId,
      });
    }

    if (!occupancy) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], No Occupancy Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const client = await clientDB.getById({
      id: occupancy.clientId,
    });
    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], No Client Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const property = await propertyDB.getById({
      id: occupancy.propId,
    });
    if (!property) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Charges [${charges}], Mode [${mode}], No Property Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let vendorId = null;
    const propertyVendorId = await clientConfigDB.getClientConfigByPropId({
      clientId,
      propId: occupancy.propId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.VENDOR_ID,
    });

    if (propertyVendorId) {
      vendorId = propertyVendorId.value;
    } else {
      const clientVendorId = await clientConfigDB.getClientConfig({
        clientId,
        provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
        type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.VENDOR_ID,
      });
      if (clientVendorId) {
        vendorId = clientVendorId.value;
      } else {
        log.info(
          `[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], Prop Id [${occupancy?.propId}], Split API can't be initiated due to absence of Vendor Id`,
        );
      }
    }

    let xClientId = process.env.CASHFREE_CLIENTID;
    let xSecretKey = process.env.CASHFREE_SECRET;

    const isXClientId = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_CLIENT_ID,
    });
    const isXClientSecretKey = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_SECRET_KEY,
    });

    if(isXClientId && isXClientId.value && isXClientSecretKey && isXClientSecretKey.value) {
      xClientId = isXClientId.value;
      xSecretKey = isXClientSecretKey.value;
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], Prop Id [${occupancy?.propId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Client Gateway `);
    } else {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], Prop Id [${occupancy?.propId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Kipinn Gateway `);
    }
    
    // Cashfree.XClientId = process.env.CASHFREE_CLIENTID;
    // Cashfree.XClientSecret = process.env.CASHFREE_SECRET;
    Cashfree.XClientId = xClientId;
    Cashfree.XClientSecret = xSecretKey;
    Cashfree.XEnvironment = process.env.CASHFREE_ENVIRONMENT === 'PROD' ? Cashfree.Environment.PRODUCTION : Cashfree.Environment.SANDBOX;

    let baseUrl = process.env.WEB_PAY_URL;
    if (client?.paymentLinkBaseUrl && client?.paymentLinkBaseUrl.trim() !== "") {
          baseUrl = `${client?.paymentLinkBaseUrl.trim()}`;
    }
    //let return_url: any = `${baseUrl}/payment/{order_id}`;
    //let return_url: any = `https://stagingcallback.kipinn.com/payment/status/${clientId}/{order_id}`;
    //https://pay.kipinn.com/cashfree/payment
    let return_url: any = `${process.env.CASFREE_APP_WEB_PAYMENT_BASE_URL}/status/${clientId}/{order_id}`;
    if (client?.paymentLinkBaseUrl && client?.paymentLinkBaseUrl.trim() !== "") {
      return_url = `${client?.paymentLinkBaseUrl.trim()}/cashfree/payment/status/${clientId}/{order_id}`;
    }
    let udf1 = `${client.name}_${property.name}`;
    udf1 = udf1.trim();
    const udf2 = client.mobile;
    const udf3 = `${property.gId}_${tenantId}_${req.isEvicted}`;
    const udf4 = dueIds;
    let udf5 = `APP_${charges}_${gstAmount}`;
    let orderMeta:any = {
      "return_url": return_url,
      "payment_methods": "upi",
    }
    if (Number(payingFor) === CONSTANTS.PAYING_FOR.WEB_LINK) {
      udf5 = `PAYVIALINK_${charges}_${gstAmount}`;
      orderMeta = {
        "return_url": return_url,
        // "payment_methods": mode === 4 ? "cc,dc" : "upi",
        "payment_methods": mode === CONSTANTS.TRANSACTION_MODES.CARD ? "cc,dc" : mode === CONSTANTS.TRANSACTION_MODES.NET_BANKING ? "nb" : "upi",
      }
    } else if (Number(payingFor) === CONSTANTS.PAYING_FOR.WEB_BOOKING_LINK) {
      udf5 = `BOOKINGLINK_${charges}_${gstAmount}`;
      orderMeta = {
        "return_url": return_url,
        //"payment_methods": mode === 4 ? "cc,dc" : "upi",
        "payment_methods": mode === CONSTANTS.TRANSACTION_MODES.CARD ? "cc,dc" : mode === CONSTANTS.TRANSACTION_MODES.NET_BANKING ? "nb" : "upi",
      }
    } else if (Number(payingFor) === CONSTANTS.PAYING_FOR.APP_WEB_LINK) {
      udf5 = `PAYVIAAPPLINK_${charges}_${gstAmount}`;
      orderMeta = {
        "return_url": return_url,
        //"payment_methods": mode === 4 ? "cc,dc" : "upi",
        "payment_methods": mode === CONSTANTS.TRANSACTION_MODES.CARD ? "cc,dc" : mode === CONSTANTS.TRANSACTION_MODES.NET_BANKING ? "nb" : "upi",
      }
    }
    //"payment_methods": "cc,dc,nb,upi"
    let request: any = {
      "order_amount": Number(amount) + Number(charges) + Number(gstAmount),
      "order_currency": "INR",
      "customer_details": customerDetails,
      "order_note": "",
      "order_meta": orderMeta,
      "order_tags": {
        'udf1': udf1,
        'udf2': udf2,
        'udf3': udf3,
        'udf4': udf4,
        'udf5': udf5,
      },
    };
    // if (vendorId) {
    //   log.info(
    //     `[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${client.id}], Vendor Id [${vendorId}], No Hold Out Balance Remaining, Initiating Split Payment API`,
    //   );

    //   let orderSplits = [
    //     {
    //       vendor_id: vendorId,
    //       amount: Number(amount) + Number(gstAmount),
    //     },
    //   ];
    //   request['order_splits'] = orderSplits;
    // }
    log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${client.id}], Order Request [${JSON.stringify(request)}]`);
    //let version = process.env.CASHFREE_VERSION || "2023-08-01";
    
    Cashfree.PGCreateOrder('2023-08-01', request).then((response) => {
      let a = response.data;
      //log.info(`[${C}], [${F}], Data [${JSON.stringify(response.data)}]`);
      //let redirectLink = `https://stagingcallback.kipinn.com/pay?paymentSessionId=${response.data.payment_session_id}`;
      let redirectLink = `${process.env.CASFREE_APP_WEB_PAYMENT_BASE_URL}?paymentSessionId=${response.data.payment_session_id}`;
      if (client?.paymentLinkBaseUrl && client?.paymentLinkBaseUrl.trim() !== "") {
        redirectLink = `${client?.paymentLinkBaseUrl.trim()}/cashfree/payment?paymentSessionId=${response.data.payment_session_id}`;
      }
      log.info(`[${C}], [${F}], Session Id [${response.data.payment_session_id}], Order Id [${response.data.order_id}], Amount [${response.data.order_amount}], Order created successfully.`);

      log.info(`[${C}], [${F}], link [${redirectLink}]`);
      //after succesfull hashing of hash
      let respData: any = response.data
      respData.paymentLink = redirectLink;
      return res.status(200).json({
        msg: `Order created successfull`,
        data: respData,
        isSuccess: true,
      });
    })
      .catch((error) => {
        log.info(`[${C}], [${F}], Error [${JSON.stringify(error.response.data)}]`);
        return res.status(500).json({
          msg: CONSTANTS.MSG.ERROR_MESSAGE,
          data: false,
          isSuccess: false,
        });
      });

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

cashfree.CreateOrder_Old = async (req: Request, res: Response) => {
  const C = "Cashfree Controller";
  const F = "CreateOrder";
  try {
    const { amount, customerDetails } = req.body;

    if (!amount || !customerDetails) {
      log.info(
        `[${C}], [${F}], Amount [${amount}], Customer Details [${customerDetails}], Invalid Request`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    log.info(
      `[${C}], [${F}], Amount [${amount}], Customer Id [${customerDetails.customer_id}], Customer Name [${customerDetails.customer_name}], Customer Mobile [${customerDetails.customer_phone}]`
    );

    Cashfree.XClientId = process.env.CASHFREE_CLIENTID;
    Cashfree.XClientSecret = process.env.CASHFREE_SECRET;
    Cashfree.XEnvironment = process.env.CASHFREE_ENVIRONMENT === 'PROD' ? Cashfree.Environment.PRODUCTION : Cashfree.Environment.SANDBOX;

    var request = {
      "order_amount": amount,
      "order_currency": "INR",
      "customer_details": customerDetails,
      "order_note": ""
    };

    Cashfree.PGCreateOrder("2023-08-01", request).then((response) => {
      var a = response.data;
      log.info(`[${C}], [${F}], Session Id [${response.data.payment_session_id}], Order Id [${response.data.cf_order_id}], Amount [${response.data.order_amount}], Order created successfully.`);
      //after succesfull hashing of hash
      return res.status(200).json({
        msg: `Order created successfull`,
        data: response.data,
        isSuccess: true,
      });
    })
      .catch((error) => {
        log.info(`[${C}], [${F}], Error [${JSON.stringify(error.response.data)}]`);
        return res.status(500).json({
          msg: CONSTANTS.MSG.ERROR_MESSAGE,
          isSuccess: false,
        });
      });

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

cashfree.OrderStatus = async (req: CustomRequest, res: Response) => {
  const C = "Cashfree Controller";
  const F = "OrderStatus";
  try {
    const { orderId } = req.body;
    const clientId = req.clientId;
    const tenantId = req.id;

    if (!orderId) {
      log.info(
        `[${C}], [${F}], Order Id is missing, Invalid Request`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Order Id [${orderId}]`
    );

    let xClientId = process.env.CASHFREE_CLIENTID;
    let xSecretKey = process.env.CASHFREE_SECRET;

    const isXClientId = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_CLIENT_ID,
    });
    const isXClientSecretKey = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_SECRET_KEY,
    });

    if(isXClientId && isXClientId.value && isXClientSecretKey && isXClientSecretKey.value) {
      xClientId = isXClientId.value;
      xSecretKey = isXClientSecretKey.value;
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Client Gateway `);
    } else {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Kipinn Gateway `);
    }
    // Cashfree.XClientId = process.env.CASHFREE_CLIENTID;
    // Cashfree.XClientSecret = process.env.CASHFREE_SECRET;
    Cashfree.XClientId = xClientId;
    Cashfree.XClientSecret = xSecretKey;
    Cashfree.XEnvironment = process.env.CASHFREE_ENVIRONMENT === 'PROD' ? Cashfree.Environment.PRODUCTION : Cashfree.Environment.SANDBOX;

    Cashfree.PGFetchOrder("2023-08-01", orderId).then((response) => {
      log.info(`[${C}], [${F}], Session Id [${response.data.cf_order_id}], Order Id [${response.data.cf_order_id}], Amount [${response.data.order_amount}], Order fetched successfully.`);
      //after succesfull hashing of hash
      return res.status(200).json({
        msg: `Order Status shared successfull`,
        data: response.data,
        isSuccess: true,
      });
    })
      .catch((error) => {
        log.info(`[${C}], [${F}], Error [${JSON.stringify(error.response.data)}]`);
        return res.status(500).json({
          msg: CONSTANTS.MSG.ERROR_MESSAGE,
          isSuccess: false,
        });
      });

  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};
/*
This function is triggered when a payment is completed from the mobile app through the web payment link. The function is invoked via the Cashfree redirection URL after payment completion.

We created this as a separate function because the redirection URL does not contain the authentication token. Therefore, we are passing the clientId explicitly as a function argument to identify the client and process the payment verification correctly.
*/
cashfree.OrderStatusForAppWeb = async (req: CustomRequest, res: Response) => {
  const C = "Cashfree Controller";
  const F = "OrderStatusForAppWeb";
  try {
    const { orderId, clientId, tenantId } = req.body;
    //const clientId = req.clientId;
    if (!orderId) {
      log.info(
        `[${C}], [${F}], Order Id is missing, Invalid Request`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Order Id [${orderId}]`
    );

    let xClientId = process.env.CASHFREE_CLIENTID;
    let xSecretKey = process.env.CASHFREE_SECRET;

    const isXClientId = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_CLIENT_ID,
    });
    const isXClientSecretKey = await clientConfigDB.getClientConfig({
      clientId,
      provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.CASHFREE,
      type: CONSTANTS.CLIENT_CONFIG_TYPE.CASHFREE.X_SECRET_KEY,
    });

    if(isXClientId && isXClientId.value && isXClientSecretKey && isXClientSecretKey.value) {
      xClientId = isXClientId.value;
      xSecretKey = isXClientSecretKey.value;
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Client Gateway `);
    } else {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Client Id [${clientId}], X Client Id [${xClientId}], Secret Key [${xSecretKey}], Kipinn Gateway `);
    }
    // Cashfree.XClientId = process.env.CASHFREE_CLIENTID;
    // Cashfree.XClientSecret = process.env.CASHFREE_SECRET;
    Cashfree.XClientId = xClientId;
    Cashfree.XClientSecret = xSecretKey;
    Cashfree.XEnvironment = process.env.CASHFREE_ENVIRONMENT === 'PROD' ? Cashfree.Environment.PRODUCTION : Cashfree.Environment.SANDBOX;

    Cashfree.PGFetchOrder("2023-08-01", orderId).then((response) => {
      log.info(`[${C}], [${F}], Session Id [${response.data.cf_order_id}], Order Id [${response.data.cf_order_id}], Amount [${response.data.order_amount}], Order fetched successfully.`);
      //after succesfull hashing of hash
      return res.status(200).json({
        msg: `Order Status shared successfull`,
        data: response.data,
        isSuccess: true,
      });
    })
      .catch((error) => {
        log.info(`[${C}], [${F}], Error [${JSON.stringify(error.response.data)}]`);
        return res.status(500).json({
          msg: CONSTANTS.MSG.ERROR_MESSAGE,
          isSuccess: false,
        });
      });

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

//Currently Not being used
cashfree.WebPayment = async (req: CustomRequest, res: Response) => {
  const C = "Cashfree Controller";
  const F = "WebPayment";
  try {
    let { email = 'kipinn.com@gmail.com', amount, dueId, charges = 0, mode = 2, gstAmount = 0, isBookingPayment = false, } = req.body;
    // email = 'kipinn.com@gmail.com';
    if (!email || email.trim() === "") {
      email = 'kipinn.com@gmail.com';
    }
    const tenantId = req.id;
    const clientId = req.clientId;
    let transAmount = amount;
    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Is Evicted [${req.isEvicted}], Email [${email}], Due Id [${dueId}], Transaction Amount [${transAmount}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Is Booking Payment [${isBookingPayment}], Tenant Requesting....`
    );

    const tenant = await tenantDB.getById({ id: tenantId });
    if (!tenant) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Transaction Amount [${transAmount}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Is Booking Payment [${isBookingPayment}], No Tenant Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let dueIds = dueId.join(",");
    // let dueIdsArray = dueId.split(",");  // convert string → array
    // let dueIds = dueIdsArray.join(",");  // ensure proper format

    let totalAmount = transAmount;
    //Due type is fixed 
    let isSingleDuePayment = dueId.length === 1 ? true : false;
    let isSecurityPayment = false;
    let dueType = CONSTANTS.DUES_TYPES.RENT;
    if (dueId && dueId.length > 0) {
      for (let id of dueId) {
        let due = await duesDB.getById({ id });
        if (req.isEvicted) {
          due = await moveOutDuesDB.getById({ id });
        }

        if (!due) {
          log.info(
            `[${C}], [${F}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Charges [${charges}], Mode [${mode}], No Due Found with this Id [${id}]`
          );
          return res
            .status(400)
            .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
        }
        dueType = due.type;
        //totalAmount += due.balance;
        if (isSingleDuePayment) {
          if (due.type === CONSTANTS.DUES_TYPES.SECURITY) {
            isSecurityPayment = true;
          }
        }
      }
    }
    let occupancy = await occupancyDB.getByTenantIdAndClientId({
      tenantId: tenantId,
      clientId: clientId,
    });

    if (req.isEvicted) {
      occupancy = await moveOutDB.getByTenantIdAndClientId({
        tenantId: tenantId,
        clientId: clientId,
      });
    }

    if (!occupancy) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Transaction Amount [${totalAmount}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Is Booking Payment [${isBookingPayment}], No Occupancy Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const client = await clientDB.getById({
      id: occupancy.clientId,
    });
    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Transaction Amount [${totalAmount}], Is Booking Payment [${isBookingPayment}], No Client Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    const property = await propertyDB.getById({
      id: occupancy.propId,
    });
    if (!property) {
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Transaction Amount [${totalAmount}], Is Booking Payment [${isBookingPayment}], No Property Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }


    const surl = process.env.OXO_WEB_CHECKOUT_SUCCESS_URL;
    const furl = process.env.OXO_WEB_CHECKOUT_FAILURE_URL;
    let udf1 = `${client.name}_${property.name}`;
    udf1 = udf1.trim();
    const udf2 = client.mobile;
    const udf3 = `${property.gId}_${tenantId}_${req.isEvicted}`;
    const udf4 = dueIds;
    let udf5 = `${'PAYVIALINK'}_${charges}_${gstAmount}`;
    if (isBookingPayment) {
      udf5 = `${'BOOKINGLINK'}_${charges}_${gstAmount}`;
    }
    // const txnId = Date.now() + udf4;
    const txnId = Date.now() + tenant.id;
    let firstName = tenant.name;
    firstName = firstName.trim();
    const phone = tenant.mobile;
    const amountPay = totalAmount + Number(charges) + Number(gstAmount);
    let productInfo = `Payment for `;
    if (true == isBookingPayment) {
      productInfo += `Booking`;
    } else if (dueId && dueId.length == 1) {
      productInfo += `${getDueDescription(dueType)}`;
    } else {
      productInfo += `pending dues`;
    }

    const paymentMode = mode === CONSTANTS.TRANSACTION_MODES.UPI ? "UPI" : mode === CONSTANTS.TRANSACTION_MODES.NET_BANKING ? "NB" : "DC,CC";



    //const hashString = `${key}|${txnId}|${firstName}|${email}|${phone}|${amountPay}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}|${productInfo}|${salt}`;

    //const hash = crypto.createHash("sha512").update(hashString).digest("hex");

    log.info(
      `[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], UDF1(Client Name) [${udf1}], UDF2(Client Mobile) [${udf2}], UDF3(propertyGid_tenantId) [${udf3}], UDF4(Due Id) [${udf4}], UDF5(LedgerReferenceId_Charges) [${udf5}], Transaction Id [${txnId}], First Name [${firstName}], Mobile [${phone}], Amount [${amountPay}], Product Info [${productInfo}],  Charges [${charges}], GST Amount [${gstAmount}], Mode [${mode}], Is Security Payment [${isSecurityPayment}], Tenant Requesting....`
    );

    //show_payment_mode
    let payload = {
      link_id: `link_${tenantId}${moment().unix()}`,
      link_amount: amountPay,
      link_currency: "INR",
      link_purpose: productInfo,

      customer_details: {
        customer_name: firstName,
        customer_phone: phone,
        customer_email: email || ""
      },

      // 🔥 Your UDF replacement
      link_notes: {
        udf1: udf1,
        udf2: udf2,
        udf3: udf3,
        udf4: udf4,
        udf5: udf5,
      },

      link_meta: {
        return_url: surl,
        //notify_url: "https://yourapp.com/webhook",
        upi_intent: false
      },

      link_notify: {
        send_sms: false,
        send_email: false
      },

      link_auto_reminders: false
    };
    let x_client_id = process.env.CASHFREE_CLIENTID;
    let x_client_secret = process.env.CASHFREE_SECRET;
    let x_api_version = process.env.CASHFREE_VERSION;
    let url = `https://api.cashfree.com/pg/links`;
    const options = {
      method: 'POST',
      url: url,
      headers: {
        'Content-Type': 'application/json',
        "Accept": 'application/json',
        "x-client-id": x_client_id,
        "x-client-secret": x_client_secret,
        "x-api-version": '2023-08-01'
      },
      data: payload
    };
    log.info(`[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Request [${JSON.stringify(options)}]`);
    //const { data } = await axios.request(options);
    //log.info(`[${C}], [${F}], Status [${data?.status}], Payment Url [${data?.data?.link_url}], Payment url shared`);
    //after succesfull hashing of hash
    let response = await cashfreeCreatePaymentLink({
      tenantId: tenantId,
      amount,
      firstName,
      phone,
      email,
      productInfo,
      surl,
      udf1,
      udf2,
      udf3,
      udf4,
      udf5
    });
    log.info(`[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Request [${JSON.stringify(response)}]`);
    if (response.isSuccess) {
      log.info(`[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Payment Url [${response?.data?.link_url}]`);
      return res.status(200).json({
        msg: `Payment url generated successfully`,
        data: response.data,
        isSuccess: true,
      });
    } else {
      log.info(`[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Failed to create link`);
      return res.status(500).json({
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
      });
    }
    //return res.send(formHtml);
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

export default cashfree;
