import axios from "axios";
import CONSTANTS from "../../../config/constants";
import log from "../../../config/log";
import documentDB from "../../../models/document.model";
import occupancyDB from "../../../models/occupancy.model";
import documentsTypes from "../../../schemas/document.schema";
import tenantDB from "../../../models/tenant.model";
import moment from "moment";
import occupanciesTypes from "../../../schemas/occupancy.schema";
import fsPromises from "fs/promises";
import FormData from "form-data";
import staffDB from "../../../models/staff.model";
import staffDocumentDB from "../../../models/staffDocument.model";
import { generateAadhaarCardBack, generateAadhaarCardFront } from "../../createAadhaar";
import getAadharAddressFromXml from "./getAadharAddressFromXml";
import { v4 as uuidv4 } from 'uuid';

type addParamTypes = {
  tenantId: number;
  IdNumber: string;
  maskedIdNumber: string;
  isExists: documentsTypes;
};

type addParamTypesX = {
  userId: number;
  userType: number;
  IdNumber: string;
  maskedIdNumber: string;
  isExists: documentsTypes;
};

type addPanParamTypes = {
  tenantId: number;
  IdNumber: string;
  maskedIdNumber: string;
  name: string;
};

type verifyParamTypes = {
  tenantId: number;
  otp: string;
  requestId: string;
  docId: number;
};

type verifyParamTypesX = {
  userId: number;
  userType: number;
  otp: string;
  requestId: string;
  docId: number;
};

type uploadParamTypes = {
  tenantId: number;
  oldFrontPath: string;
  oldBackPath: string;
  folderPath: string;
  urlBase: string;
  occupancy: occupanciesTypes;
};

type uploadParamTypesStaff = {
  staffId: number;
  oldFrontPath: string;
  oldBackPath: string;
  folderPath: string;
  urlBase: string;
};

export const addAadhaarNumberToCashfree = async ({
  tenantId,
  IdNumber,
  maskedIdNumber,
  isExists,
}: addParamTypes) => {
  const C = "Tenant Controller";
  const F = "AddIDNumber";
  const U = "addAadhaarNumberToCashfree";
  try {
    let requestId: string | null = null;
    let docId = null;
    let result = null;

    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await generateAadhaarOTP());
        }, delayedTime);
      });
    };

    const generateAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_GENERATE_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { aadhaar_number: IdNumber },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await generateAadhaarOTP();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to add your aadhaar number. Please try again later.",
        isDown: true,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${result?.message}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (
      result?.status === "SUCCESS" &&
      result?.message === "Aadhaar not linked to mobile number"
    ) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message,
        isDown: false,
      };
    }

    requestId = result?.ref_id;

    const occupancy = await occupancyDB.getByTenantId({
      tenantId,
    });

    if (isExists) {
      docId = isExists.id;
      await documentDB.updateDoc({
        tenantId,
        clientId: occupancy.clientId,
        propId: occupancy.propId,
        roomId: occupancy.roomId,
        type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
        value: maskedIdNumber,
        id: isExists.id,
      });

      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], 
      Id Number Upadated & OTP Generated Successfully `
      );
    } else {
      docId = await documentDB.addDoc({
        tenantId,
        clientId: occupancy.clientId,
        propId: occupancy.propId,
        roomId: occupancy.roomId,
        type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
        value: maskedIdNumber,
      });
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], 
      Id Number Added & OTP Generated Successfully `
      );
    }

    return { docId, requestId, isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const addAadhaarNumberToCashfreeX = async ({
  userId,
  userType,
  IdNumber,
  maskedIdNumber,
  isExists,
}: addParamTypesX) => {
  const U = "addAadhaarNumberToCashfreeX";
  try {
    let requestId: string | null = null;
    // let docId = null;
    let result = null;

    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await generateAadhaarOTP());
        }, delayedTime);
      });
    };

    const generateAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_GENERATE_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { aadhaar_number: IdNumber },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await generateAadhaarOTP();

    if (!result) {
      log.info(
        `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], ID Number [${maskedIdNumber}], No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to add your aadhaar number. Please try again later.",
        isDown: true,
      };
    } else if (result?.type) {
      log.info(
        `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.status === "INVALID") {
      log.info(
        `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${result?.message}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (
      result?.status === "SUCCESS" &&
      result?.message === "Aadhaar not linked to mobile number"
    ) {
      log.info(
        `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message,
        isDown: false,
      };
    }

    requestId = result?.ref_id;

    // const staff = staffDB.getById({
    //   id: staffId,
    // });

    // if (isExists) {
    //   docId = isExists.id;
    //   await staffDocumentDB.updateDoc({
    //     staffId,
    //     clientId: staff.clientId,
    //     type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
    //     value: maskedIdNumber,
    //     id: isExists.id,
    //   });

    //   log.info(
    //     `[${C}], [${F}], [${U}] Staff Id [${staffId}], Type [AADHAAR], ID Number [${maskedIdNumber}],
    //   Id Number Upadated & OTP Generated Successfully `
    //   );
    // } else {
    //   docId = await staffDocumentDB.add({
    //     staffId: staffId,
    //     clientId: staff.clientId,
    //     type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
    //     value: maskedIdNumber,
    //   });
    //   log.info(
    //     `[${C}], [${F}], [${U}] Staff Id [${staffId}], Type [AADHAAR], ID Number [${maskedIdNumber}],
    //   Id Number Added & OTP Generated Successfully `
    //   );
    // }

    log.info(
      `[${U}] User Id [${userId}], User Type [${userType}], Type [AADHAAR], ID Number [${maskedIdNumber}],
      Id Number Added & OTP Generated Successfully `
    );

    // return { docId, requestId, isSuccess: true };
    return { requestId, isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const verifyOTPFromCashfree = async ({
  tenantId,
  requestId,
  otp,
  docId,
}: verifyParamTypes) => {
  const C = "Tenant Controller";
  const F = "VerifyIDNumber";
  const U = "verifyOTPFromCashfree";
  try {
    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await verifyAadhaarOTP());
        }, delayedTime);
      });
    };

    const verifyAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_VERIFY_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { otp, ref_id: requestId },
        };

        const { data: result } = await axios.request(options);

        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Cashfree Response: ${JSON.stringify(result)}`
        );

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    const result: any = await verifyAadhaarOTP();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to verify your aadhaar number. Please try again later.",
        isSuccess: false,
        isServerError: false,
        isDown: true,
        isTimeout: false,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}] [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
        isTimeout: false,
      };
    }

    const { name, dob, gender, address, care_of, zip, photo_link } = result;

    if (!name && !dob) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Invalid Response from Cashfree`
      );

      return {
        msg: "Verification failed: Kindly re-add your aadhaar number",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: true,
      };
    }

    //Sukhbir - 20th Jan 2025 to make sure there should not be conflict with Eqaro Verification
    // let genderVal = 0;
    // if (gender && gender.toLowerCase() === "m") {
    //   genderVal = CONSTANTS.GENDER.MALE;
    // } else if (gender && gender.toLowerCase() === "f") {
    //   genderVal = CONSTANTS.GENDER.FEMALE;
    // } else {
    //   genderVal = CONSTANTS.GENDER.OTHER;
    // }

    // await tenantDB.updatePersonalInfo({
    //   name: name,
    //   fatherName: care_of?.slice(4) || "",
    //   dob: (dob && moment(dob, "DD-MM-YYYY").format("YYYY-MM-DD")) || null,
    //   gender: genderVal,
    //   address,
    //   id: tenantId,
    //   kycStatus: CONSTANTS.KYC_STATUS.ID_UPLOADED,
    // });

    // await documentDB.updateStatus({
    //   id: docId,
    //   status: CONSTANTS.DOCUMENT_STATUS.VERIFIED,
    // });

    const tenant = await tenantDB.getById({
      id: tenantId,
    });

    let genderVal = "Male";
    if (gender && gender.toLowerCase() === "m") {
      genderVal = "Male";
    } else if (gender && gender.toLowerCase() === "f") {
      genderVal = "Female";
    } else {
      genderVal = "Other";
    }

    const DOB = dob ? dob.replaceAll("-", "/") : "-";

    const aadharFront = await generateAadhaarCardFront(
      tenantId,
      "uploads/documents/defaults/aadhar-base-image.jpg",
      name,
      DOB,
      genderVal,
      tenant.aadharNumber,
      photo_link,
      0
    );

    let frontUrl = null;
    if (aadharFront?.isSuccess) {
      frontUrl = aadharFront.imageUrl;
    }

    const aadharBack = await generateAadhaarCardBack(
      tenantId,
      "uploads/documents/defaults/aadhar-back-base-image.jpg",
      address,
      care_of,
      tenant.aadharNumber,
      0
    );

    let backUrl = null;
    if (aadharBack?.isSuccess) {
      backUrl = aadharBack.imageUrl;
    }

    log.info(
      `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Verification Successfull`
    );

    return { isSuccess: true, photo: photo_link, result: result, frontUrl, backUrl };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
      isTimeout: false,
    };
  }
};

export const verifyOTPFromCashfreeX = async ({
  userId,
  userType,
  requestId,
  otp,
  docId,
}: verifyParamTypesX) => {
  const U = "verifyOTPFromCashfreeX";
  try {
    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await verifyAadhaarOTP());
        }, delayedTime);
      });
    };

    const verifyAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_VERIFY_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { otp, ref_id: requestId },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    const result: any = await verifyAadhaarOTP();

    if (!result) {
      log.info(
        `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to verify your aadhaar number. Please try again later.",
        isSuccess: false,
        isServerError: false,
        isDown: true,
        isTimeout: false,
      };
    } else if (result?.type) {
      log.info(
        `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
        isTimeout: false,
      };
    }

    const { name, dob, gender, address, care_of, zip, photo_link } = result;

    if (!name && !dob) {
      log.info(
        `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Invalid Response from Cashfree`
      );

      return {
        msg: "Verification failed: Kindly re-add your aadhaar number",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: true,
      };
    }

    log.info(
      `[${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Verification Successfull`
    );

    return { isSuccess: true, photo: photo_link, result: result };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
      isTimeout: false,
    };
  }
};

export const addPanNumberToCashfree = async ({
  tenantId,
  IdNumber,
  maskedIdNumber,
  name,
}: addPanParamTypes) => {
  const C = "Tenant Controller";
  const F = "AddPanNumber";
  const U = "addPanNumberToCashfree";
  try {
    let requestId: string | null = null;
    let result = null;

    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await generateAadhaarOTP());
        }, delayedTime);
      });
    };

    const generateAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_PAN_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { pan: IdNumber, name },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (
          error?.response?.data?.type === "validation_error" ||
          error?.response?.data?.type === "authentication_error"
        ) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await generateAadhaarOTP();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], ID Number [${maskedIdNumber}], No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to add your aadhaar number. Please try again later.",
        isDown: true,
      };
    } else if (
      result?.type === "validation_error" ||
      result?.type === "authentication_error"
    ) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.message === "Invalid PAN") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], ID Number [${maskedIdNumber}], Cashfree Response [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    }

    log.info(
      `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], ID Number [${maskedIdNumber}], Successfull Response: ${JSON.stringify(
        result
      )}`
    );

    requestId = result?.ref_id;

    const occupancy = await occupancyDB.getByTenantId({
      tenantId,
    });

    await documentDB.addDocWithStatus({
      tenantId,
      clientId: occupancy.clientId,
      propId: occupancy.propId,
      roomId: occupancy.roomId,
      type: CONSTANTS.DOCUMENT_TYPES.PAN,
      value: maskedIdNumber,
      status: CONSTANTS.DOCUMENT_STATUS.VERIFIED,
    });

    await tenantDB.updateKycStatus({
      kycStatus: CONSTANTS.KYC_STATUS.PAN_VERIFICATION_DONE,
      id: tenantId,
    });

    await occupancyDB.updateKycStatus({
      tenantId: tenantId,
      kycStatus: CONSTANTS.KYC_STATUS.PAN_VERIFICATION_DONE,
    });

    log.info(
      `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [PAN], ID Number [${maskedIdNumber}], 
      PAN Number Added Successfully `
    );

    return { isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const addAadhaarNumberToCashfreeForCoApplicant = async ({
  tenantId,
  IdNumber,
  maskedIdNumber,
}: addParamTypes) => {
  const C = "Tenant Controller";
  const F = "AddIDNumber";
  const U = "addAadhaarNumberToCashfreeForCoApplicant";
  try {
    let requestId: string | null = null;
    let docId = null;
    let result = null;

    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await generateAadhaarOTP());
        }, delayedTime);
      });
    };

    const generateAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_GENERATE_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { aadhaar_number: IdNumber },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await generateAadhaarOTP();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to add your aadhaar number. Please try again later.",
        isDown: true,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${result?.message}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (
      result?.status === "SUCCESS" &&
      result?.message === "Aadhaar not linked to mobile number"
    ) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message,
        isDown: false,
      };
    }

    requestId = result?.ref_id;

    const occupancy = await occupancyDB.getByTenantId({
      tenantId,
    });

    return { docId, requestId, isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const verifyOTPFromCashfreeForCoApplicant = async ({
  tenantId,
  requestId,
  otp,
}: verifyParamTypes) => {
  const C = "Tenant Controller";
  const F = "VerifyIDNumber";
  const U = "verifyOTPFromCashfreeForCoApplicant";
  try {
    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await verifyAadhaarOTP());
        }, delayedTime);
      });
    };

    const verifyAadhaarOTP = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_VERIFY_OPT_API,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { otp, ref_id: requestId },
        };

        const { data: result } = await axios.request(options);

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    const result: any = await verifyAadhaarOTP();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to verify your aadhaar number. Please try again later.",
        isSuccess: false,
        isServerError: false,
        isDown: true,
        isTimeout: false,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}] [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
        isTimeout: false,
      };
    }

    const { name, dob, gender, address, care_of, zip, photo_link } = result;
    log.info({ result });

    if (!name && !dob) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Invalid Response from Cashfree`
      );

      return {
        msg: "Verification failed: Kindly re-add your aadhaar number",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: true,
      };
    }

    log.info(
      `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Verification Successfull`
    );

    return { isSuccess: true, photo: photo_link, result: result };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
      isTimeout: false,
    };
  }
};

export const uploadAadhaarToCashfree = async ({
  tenantId,
  oldFrontPath,
  oldBackPath,
  folderPath,
  urlBase,
  occupancy,
}: uploadParamTypes) => {
  const C = "Tenant Controller";
  const F = "UploadID";
  const U = "uploadAadhaarToCashfree";

  try {
    let retryNo = 0;
    const tenant = await tenantDB.getById({
      id: tenantId,
    });

    const retry = async (
      count: number,
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve) => {
        setTimeout(async () => {
          resolve(await uploadToThirdParty(oldFrontPath, oldBackPath));
        }, delayedTime);
      });
    };

    const uploadToThirdParty = async (
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      try {
        const frontImage = await axios({
          url: oldFrontPath,
          responseType: "arraybuffer",
        });
        const frontImageBuffer = Buffer.from(frontImage.data);

        let backImage = null;
        let backImageBuffer = null;
        if (oldBackPath) {
          backImage = await axios({
            url: oldBackPath,
            responseType: "arraybuffer",
          });
          backImageBuffer = Buffer.from(backImage.data);
        }

        const verificationNumber =
          "aadhaar_" +
          moment().format("YYYYMMDD") +
          moment().format("mmss") +
          `_${tenant.mobile.slice(-5)}`;

        const form = new FormData();
        form.append("verification_id", verificationNumber);
        // form.append("document_type", "AADHAAR");
        // form.append("image", imageBuffer, "aadhaar.jpg");
        form.append("front_image", frontImageBuffer, "aadhaar_front.jpg");
        if (oldBackPath) {
          form.append("back_image", backImageBuffer, "aadhaar_back.jpg");
        }

        const options = {
          method: "POST",
          // url: "https://api.cashfree.com/verification/generic-ocr",
          // url: "https://api.cashfree.com/verification/document/aadhaar", in use below
          url: process.env.CASHFREE_AADHAAR_OCR_API,
          headers: {
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID!,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET!,
            "x-api-version": "2024-12-01",
            "Content-Type": "multipart/form-data",
          },
          data: form,
        };

        let { data: response } = await axios.request(options);

        return response;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree OCR Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo, oldFrontPath, oldBackPath);
        } else {
          return false;
        }
      }
    };

    const response: any = await uploadToThirdParty(oldFrontPath, oldBackPath);

    if (!response) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to upload your ID at the moment. Please try again later",
        isSuccess: false,
        isServerError: false,
      };
    }

    log.info(
      `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Response [${JSON.stringify(
        response
      )}], Status Code [${JSON.stringify(response?.status)}]`
    );

    if (response?.type) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree OCR Error [${response?.message}] `
      );

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
        isServerError: false,
      };
    } else if (response?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Response: Not a valid aadhaar document`
      );
      return {
        msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
        isSuccess: false,
        isServerError: false,
      };
    } else {
      const { maskedFrontUrl, maskedBackUrl, name, yob, address, gender, uid } =
        response;

      if (!name && yob === "Not available on aadhaar") {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Did not get Name & DoB field from Cashfree OCR, Not a valid aadhaar document`
        );
        return {
          msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
          isSuccess: false,
          isServerError: false,
        };
      }

      if (oldFrontPath) {
        const imageResponse = await axios.get(oldFrontPath, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = oldFrontPath.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer as Uint8Array);
        const url = `${urlBase}/${fileName}`;

        const isExists = await documentDB.getIDByType({
          tenantId,
          clientId: occupancy?.clientId,
          type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
          moveOut: 0,
        });

        if (isExists) {
          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], URL [${url}], Aadhaar Front document re-uploaded successfully`
          );

          await documentDB.updateDoc({
            tenantId,
            clientId: occupancy.clientId,
            propId: occupancy.propId,
            roomId: occupancy.roomId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
            value: url,
            id: isExists.id,
          });
        } else {
          await documentDB.addDocWithStatus({
            tenantId,
            clientId: occupancy.clientId,
            propId: occupancy.propId,
            roomId: occupancy.roomId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
            value: url,
            status: CONSTANTS.DOCUMENT_STATUS.VERIFIED,
          });

          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], URL [${url}], Aadhaar Front document uploaded successfully`
          );
        }
      }

      if (oldBackPath) {
        const imageResponse = await axios.get(oldBackPath, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = oldBackPath.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_back_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer as Uint8Array);
        const url = `${urlBase}/${fileName}`;

        const isExists = await documentDB.getIDByType({
          tenantId,
          clientId: occupancy?.clientId,
          type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
          moveOut: 0,
        });

        if (isExists) {
          await documentDB.updateDoc({
            tenantId,
            clientId: occupancy.clientId,
            propId: occupancy.propId,
            roomId: occupancy.roomId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
            value: url,
            id: isExists.id,
          });

          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], URL [${url}], Aadhaar Front document re-uploaded successfully`
          );
        } else {
          await documentDB.addDocWithStatus({
            tenantId,
            clientId: occupancy.clientId,
            propId: occupancy.propId,
            roomId: occupancy.roomId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
            value: url,
            status: CONSTANTS.DOCUMENT_STATUS.VERIFIED,
          });

          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], URL [${url}], Aadhaar Back document uploaded successfully`
          );
        }
      }

      let genderVal = 0;
      if (gender && gender.toLowerCase() === "male") {
        genderVal = CONSTANTS.GENDER.MALE;
      } else if (gender && gender.toLowerCase() === "female") {
        genderVal = CONSTANTS.GENDER.FEMALE;
      } else {
        genderVal = CONSTANTS.GENDER.OTHER;
      }

      return {
        isSuccess: true,
        yob,
        genderVal,
        address,
        name,
        uid,
        result: response,
      };
    }
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
    };
  }
};

export const uploadAadhaarToCashfreeCoApplicant = async ({
  tenantId,
  oldFrontPath,
  oldBackPath,
  folderPath,
  urlBase,
  occupancy,
}: uploadParamTypes) => {
  const C = "Eqaro Controller";
  const F = "uploadAadhaar";
  const U = "uploadAadhaarToCashfreeCoApplicant";

  try {
    let retryNo = 0;
    const tenant = await tenantDB.getById({
      id: tenantId,
    });

    const retry = async (
      count: number,
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve) => {
        setTimeout(async () => {
          resolve(await uploadToThirdParty(oldFrontPath, oldBackPath));
        }, delayedTime);
      });
    };

    const uploadToThirdParty = async (
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      try {
        const frontImage = await axios({
          url: oldFrontPath,
          responseType: "arraybuffer",
        });
        const frontImageBuffer = Buffer.from(frontImage.data);

        let backImage = null;
        let backImageBuffer = null;
        if (oldBackPath) {
          backImage = await axios({
            url: oldBackPath,
            responseType: "arraybuffer",
          });
          backImageBuffer = Buffer.from(backImage.data);
        }

        const verificationNumber =
          "aadhaar_" +
          moment().format("YYYYMMDD") +
          moment().format("mmss") +
          `_${tenant.mobile.slice(-5)}`;

        const form = new FormData();
        form.append("verification_id", verificationNumber);
        // form.append("document_type", "AADHAAR");
        // form.append("image", imageBuffer, "aadhaar.jpg");
        form.append("front_image", frontImageBuffer, "aadhaar_front.jpg");
        if (oldBackPath) {
          form.append("back_image", backImageBuffer, "aadhaar_back.jpg");
        }

        const options = {
          method: "POST",
          // url: "https://api.cashfree.com/verification/generic-ocr",
          // url: "https://api.cashfree.com/verification/document/aadhaar" in use below
          url: process.env.CASHFREE_AADHAAR_OCR_API,
          headers: {
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID!,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET!,
            "x-api-version": "2024-12-01",
            "Content-Type": "multipart/form-data",
          },
          data: form,
        };

        let { data: response } = await axios.request(options);

        return response;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree OCR Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo, oldFrontPath, oldBackPath);
        } else {
          return false;
        }
      }
    };

    const response: any = await uploadToThirdParty(oldFrontPath, oldBackPath);

    if (!response) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to upload your ID at the moment. Please try again later",
        isSuccess: false,
        isServerError: false,
      };
    }

    log.info(
      `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Response [${JSON.stringify(
        response
      )}], Status Code [${JSON.stringify(response?.status)}]`
    );

    if (response?.type) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree OCR Error [${response?.message}] `
      );

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
        isServerError: false,
      };
    } else if (response?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Response: Not a valid aadhaar document`
      );
      return {
        msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
        isSuccess: false,
        isServerError: false,
      };
    } else {
      const { maskedFrontUrl, maskedBackUrl, name, yob, address, gender } =
        response;

      if (!name && yob === "Not available on aadhaar") {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Did not get Name & DoB field from Cashfree OCR, Not a valid aadhaar document`
        );
        return {
          msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
          isSuccess: false,
          isServerError: false,
        };
      }

      let genderVal = 0;
      if (gender && gender.toLowerCase() === "male") {
        genderVal = CONSTANTS.GENDER.MALE;
      } else if (gender && gender.toLowerCase() === "female") {
        genderVal = CONSTANTS.GENDER.FEMALE;
      } else {
        genderVal = CONSTANTS.GENDER.OTHER;
      }

      return {
        isSuccess: true,
        yob,
        genderVal,
        address,
        name,
        result: response,
      };
    }
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
    };
  }
};

export const uploadAadhaarToCashfreeStaff = async ({
  staffId,
  oldFrontPath,
  oldBackPath,
  folderPath,
  urlBase,
}: uploadParamTypesStaff) => {
  const C = "Staff Controller";
  const F = "UploadAadhaar";
  const U = "uploadAadhaarToCashfreeStaff";

  try {
    let retryNo = 0;
    const staff = await staffDB.getById({
      id: staffId,
    });

    const retry = async (
      count: number,
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve) => {
        setTimeout(async () => {
          resolve(await uploadToThirdParty(oldFrontPath, oldBackPath));
        }, delayedTime);
      });
    };

    const uploadToThirdParty = async (
      oldFrontPath: string,
      oldBackPath: string
    ) => {
      try {
        const frontImage = await axios({
          url: oldFrontPath,
          responseType: "arraybuffer",
        });
        const frontImageBuffer = Buffer.from(frontImage.data);

        let backImage = null;
        let backImageBuffer = null;
        if (oldBackPath) {
          backImage = await axios({
            url: oldBackPath,
            responseType: "arraybuffer",
          });
          backImageBuffer = Buffer.from(backImage.data);
        }

        const verificationNumber =
          "aadhaar_" +
          moment().format("YYYYMMDD") +
          moment().format("mmss") +
          `_${staff.mobile.slice(-5)}`;

        const form = new FormData();
        form.append("verification_id", verificationNumber);
        // form.append("document_type", "AADHAAR");
        // form.append("image", imageBuffer, "aadhaar.jpg");
        form.append("front_image", frontImageBuffer, "aadhaar_front.jpg");
        if (oldBackPath) {
          form.append("back_image", backImageBuffer, "aadhaar_back.jpg");
        }

        const options = {
          method: "POST",
          // url: "https://api.cashfree.com/verification/generic-ocr",
          // url: "https://api.cashfree.com/verification/document/aadhaar", in use below
          url: process.env.CASHFREE_AADHAAR_OCR_API,
          headers: {
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID!,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET!,
            "x-api-version": "2024-12-01",
            "Content-Type": "multipart/form-data",
          },
          data: form,
        };

        let { data: response } = await axios.request(options);

        return response;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Cashfree OCR Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo, oldFrontPath, oldBackPath);
        } else {
          return false;
        }
      }
    };

    const response: any = await uploadToThirdParty(oldFrontPath, oldBackPath);

    if (!response) {
      log.info(
        `[${C}], [${F}], [${U}], Staff Id [${staffId}], No Response From Cashfree `
      );

      return {
        msg: "Unable to upload your ID at the moment. Please try again later",
        isSuccess: false,
        isServerError: false,
      };
    }

    log.info(
      `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Cashfree Response [${JSON.stringify(
        response
      )}], Status Code [${JSON.stringify(response?.status)}]`
    );

    if (response?.type) {
      log.info(
        `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Cashfree OCR Error [${response?.message}] `
      );

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
        isServerError: false,
      };
    } else if (response?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Cashfree Response: Not a valid aadhaar document`
      );
      return {
        msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
        isSuccess: false,
        isServerError: false,
      };
    } else {
      const { maskedFrontUrl, maskedBackUrl, name, yob, address, gender, uid } =
        response;

      if (!name && yob === "Not available on aadhaar") {
        log.info(
          `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], Did not get Name & DoB field from Cashfree OCR, Not a valid aadhaar document`
        );
        return {
          msg: "It's not a valid aadhaar document. Please try again with a clear image/document.",
          isSuccess: false,
          isServerError: false,
        };
      }

      if (oldFrontPath) {
        const imageResponse = await axios.get(oldFrontPath, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = oldFrontPath.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer as Uint8Array);
        const url = `${urlBase}/${fileName}`;

        const isExists = await staffDocumentDB.getByStaffIdAndType({
          staffId: staffId,
          clientId: staff?.clientId,
          type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
        });

        if (isExists) {
          log.info(
            `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], URL [${url}], Aadhaar Front document re-uploaded successfully`
          );

          await staffDocumentDB.updateDoc({
            staffId,
            clientId: staff.clientId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
            value: url,
            id: isExists.id,
          });
        } else {
          await staffDocumentDB.add({
            staffId: staffId,
            clientId: staff.clientId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR,
            value: url,
          });

          log.info(
            `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], URL [${url}], Aadhaar Front document uploaded successfully`
          );
        }
      }

      if (oldBackPath) {
        const imageResponse = await axios.get(oldBackPath, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = oldBackPath.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_back_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer as Uint8Array);
        const url = `${urlBase}/${fileName}`;

        const isExists = await staffDocumentDB.getByStaffIdAndType({
          staffId: staffId,
          clientId: staff?.clientId,
          type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
        });

        if (isExists) {
          await staffDocumentDB.updateDoc({
            staffId: staffId,
            clientId: staff.clientId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
            value: url,
            id: isExists.id,
          });

          log.info(
            `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], URL [${url}], Aadhaar Front document re-uploaded successfully`
          );
        } else {
          await staffDocumentDB.add({
            staffId: staffId,
            clientId: staff.clientId,
            type: CONSTANTS.DOCUMENT_TYPES.AADHAAR_BACK,
            value: url,
          });

          log.info(
            `[${C}], [${F}], [${U}], Staff Id [${staffId}], Type [AADHAAR], URL [${url}], Aadhaar Back document uploaded successfully`
          );
        }
      }

      let genderVal = 0;
      if (gender && gender.toLowerCase() === "male") {
        genderVal = CONSTANTS.GENDER.MALE;
      } else if (gender && gender.toLowerCase() === "female") {
        genderVal = CONSTANTS.GENDER.FEMALE;
      } else {
        genderVal = CONSTANTS.GENDER.OTHER;
      }

      return {
        isSuccess: true,
        yob,
        genderVal,
        address,
        name,
        uid,
        result: response,
      };
    }
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
    };
  }
};

export const createDigiLockerCashfreeLink = async ({
  C,
  F,
  tenantId,
  clientId
}: {C: string, F:string, tenantId:  number, clientId: number}) => {
  const U = "createDigiLockerCashfreeLink";
  try {
    let verificationId: string | null = null;
    let referenceId = null;
    let result = null;
    let uniqueString = `${tenantId}-`+uuidv4();


    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await createLink());
        }, delayedTime);
      });
    };

    const createLink = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { verification_id: uniqueString, document_requested: ['AADHAAR'], redirect_url: process.env.CASHFREE_DIGILOCKER_REDIRECTION_URL,
      },
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo})....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await createLink();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Client Id [${clientId}], Type [AADHAAR] No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to create aadhar link. Please try again later.",
        isDown: true,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Client Id [${clientId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Client Id [${clientId}], Type [AADHAAR], Cashfree Error [${result?.message}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    }
    log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Client Id [${clientId}], Type [AADHAAR], Cashfree Response [${JSON.stringify(
          result
        )}] `
    );
    verificationId = result?.verification_id;
    referenceId = result?.reference_id;

    //Pallav - Multi Tenant Senario
    //tenantDB.updateTenantDigiLockerIds({verificationId, referenceId, id:tenantId})
    occupancyDB.updateTenantDigiLockerIds({verificationId, referenceId, tenantId, clientId});
    

    return { url:result?.url, isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const createDigiLockerVerifyRequest = async ({
  C,
  F,
  verificationId,
  tenantId,
  referenceId,
  clientId
}: {C: string, F:string, verificationId:  string, tenantId:number,referenceId: number, clientId: number}) => {
  const U = "createDigiLockerVerifyRequest";
  try {

    let result = null;
    let status = null;
    
    log.info(
        `[${C}], [${F}], [${U}], Tenant ID [${tenantId}], Reference ID [${referenceId}] Verification Id [${verificationId}], Validating aadhar redirection`
    );
    let retryNo = 0;
    let retryDoc = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await varifyId());
        }, delayedTime);
      });
    };

    const varifyId = async () => {
      try {
        const options = {
          method: "GET",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          params: { verification_id: verificationId, reference_id:referenceId},
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await varifyId();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR] No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to create aadhar link. Please try again later.",
        isDown: true,
      };
    } else if (result?.status === "EXPIRED") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: "Link was expired. please try again",
        isDown: false,
      };
    } else if (result?.status != "AUTHENTICATED") {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    }
    log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Validation response [${JSON.stringify(
          result
        )}] `
    );

    // status = result?.status;

    const retryDocFetch = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await getDoc());
        }, delayedTime);
      });
    };

    const getDoc = async () => {
      try {
        const options = {
          method: "GET",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER+"/document/AADHAAR",
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          params: { verification_id: verificationId, reference_id:referenceId},
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryDoc++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Retrying doc fetch again (${retryDoc}).....`
          );

          await retryDocFetch(retryDoc);
        } else {
          return false;
        }
      }
    };

    result = await getDoc();

    log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Document response [${JSON.stringify(
          result
        )}] `
    );
    
    const { name, dob, gender, address, care_of, zip, photo_link, uid, xml_file } = result;

    if (!name && !dob) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Invalid Doc Response from Cashfree`
      );

      return {
        msg: "Verification failed: Kindly re-add your aadhaar number",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: true,
      };
    }
    let completeAddress = await getAadharAddressFromXml(xml_file);
    if (false == completeAddress) {
      completeAddress = address;
    }
    const tenant = await tenantDB.getById({
      id: tenantId,
    });
    let genderVal = "Male";
    if (gender && gender.toLowerCase() === "m") {
      genderVal = "Male";
    } else if (gender && gender.toLowerCase() === "f") {
      genderVal = "Female";
    } else {
      genderVal = "Other";
    }

    const DOB = dob ? dob.replaceAll("-", "/") : "-";
    const idNumberDB = "XXXX-XXXX-" + uid.slice(-4);
    const aadharFront = await generateAadhaarCardFront(
      tenantId,
      "uploads/documents/defaults/aadhar-base-image.jpg",
      name,
      DOB,
      genderVal,
      idNumberDB,
      photo_link,
      clientId
    );

    let frontUrl = null;
    if (aadharFront?.isSuccess) {
      frontUrl = aadharFront.imageUrl;
    }

    const aadharBack = await generateAadhaarCardBack(
      tenantId,
      "uploads/documents/defaults/aadhar-back-base-image.jpg",
      String(completeAddress),
      care_of,
      idNumberDB,
      clientId  
    );

    let backUrl = null;
    if (aadharBack?.isSuccess) {
      backUrl = aadharBack.imageUrl;
    }

    log.info(
      `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Aaadhar document fetched successfully`
    );

    return { isSuccess: true, photo: photo_link, uid, completeAddress, result: result, frontUrl, backUrl };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const createDigiLockerCashfreeLinkViaClient = async ({
  C,
  F,
  userType,
  userId,
  redirectionUrl,
  clientId
}: {C: string, F:string, userType:  number, userId:  number, redirectionUrl: string, clientId: number}) => {
  const U = "createDigiLockerCashfreeLinkViaClient";
  try {
    let verificationId: string | null = null;
    let referenceId = null;
    let result = null;
    let uniqueString = `${userId}-`+uuidv4();


    let retryNo = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await createLink());
        }, delayedTime);
      });
    };

    const createLink = async () => {
      try {
        const options = {
          method: "POST",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          data: { verification_id: uniqueString, document_requested: ['AADHAAR'], redirect_url: redirectionUrl,
      },
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Retrying again (${retryNo})....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await createLink();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR] No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to create aadhar link. Please try again later.",
        isDown: true,
      };
    } else if (result?.type) {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    } else if (result?.status === "INVALID") {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Cashfree Error [${result?.message}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    }
    log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User Id [${userId}], Type [AADHAAR], Cashfree Response [${JSON.stringify(
          result
        )}] `
    );
    verificationId = result?.verification_id;
    referenceId = result?.reference_id;
    if(CONSTANTS.USER_TYPE.TENANT === userType) {
      //Pallav - Multi Tenant Senario
      //tenantDB.updateTenantDigiLockerIds({verificationId, referenceId, id:userId})
      occupancyDB.updateTenantDigiLockerIds({verificationId, referenceId, tenantId:userId, clientId});
    } else if (CONSTANTS.USER_TYPE.STAFF === userType) {
      staffDB.updateDigiLockerIds({verificationId, referenceId, id:userId})
    }
    

    return { url:result?.url, isSuccess: true };
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

export const createDigiLockerVerifyRequestViaClient = async ({
  C,
  F,
  verificationId,
  userType,
  userId,
  referenceId,
  clientId,
}: {C: string, F:string, verificationId:  string, userType:number, userId:number,referenceId: number, clientId: number}) => {
  const U = "createDigiLockerVerifyRequestViaClient";
  try {

    let result = null;
    let status = null;
    
    log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Reference ID [${referenceId}] Verification Id [${verificationId}], Validating aadhar redirection`
    );
    let retryNo = 0;
    let retryDoc = 0;

    const retry = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await varifyId());
        }, delayedTime);
      });
    };

    const varifyId = async () => {
      try {
        const options = {
          method: "GET",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER,
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          params: { verification_id: verificationId, reference_id:referenceId},
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryNo++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Retrying again (${retryNo}).....`
          );

          await retry(retryNo);
        } else {
          return false;
        }
      }
    };

    result = await varifyId();

    if (!result) {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR] No Response From Cashfree `
      );
      return {
        isServerError: false,
        isSuccess: false,
        msg: "Unable to create aadhar link. Please try again later.",
        isDown: true,
      };
    } else if (result?.status === "EXPIRED") {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: "Link was expired. please try again",
        isDown: false,
      };
    } else if (result?.status != "AUTHENTICATED") {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Cashfree Error [${JSON.stringify(
          result
        )}] `
      );

      return {
        isServerError: false,
        isSuccess: false,
        msg: result?.message || CONSTANTS.MSG.ERROR_MESSAGE,
        isDown: false,
      };
    }
    log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Validation response [${JSON.stringify(
          result
        )}] `
    );

    // status = result?.status;

    const retryDocFetch = async (count: number) => {
      const delayedTime = count * CONSTANTS.TP_API_RETRY_DELAY;
      return new Promise((resolve, reject) => {
        setTimeout(async () => {
          resolve(await getDoc());
        }, delayedTime);
      });
    };

    const getDoc = async () => {
      try {
        const options = {
          method: "GET",
          url: process.env.CASHFREE_AADHAAR_DIGILOCKER+"/document/AADHAAR",
          headers: {
            accept: "application/json",
            "content-type": "application/json",
            "x-client-id": process.env.CASHFREE_API_CLIENT_ID,
            "x-client-secret": process.env.CASHFREE_API_CLIENT_SECRET,
          },
          params: { verification_id: verificationId, reference_id:referenceId},
        };

        const { data: data } = await axios.request(options);

        return data;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Cashfree API Error [${
            JSON.stringify(error?.response?.data) || error?.message || error
          }]`
        );

        if (error?.response?.data?.type) {
          return error?.response?.data;
        }

        retryDoc++;

        if (retryNo <= CONSTANTS.TP_API_RETRY_LIMIT) {
          log.info(
            `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Retrying doc fetch again (${retryDoc}).....`
          );

          await retryDocFetch(retryDoc);
        } else {
          return false;
        }
      }
    };

    result = await getDoc();

    log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Document response [${JSON.stringify(
          result
        )}] `
    );
    
    const { name, dob, gender, address, care_of, zip, photo_link, xml_file, uid } = result;

    if (!name) {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Invalid Doc Response from Cashfree`
      );

      return {
        msg: "Verification failed: Kindly re-add your aadhaar number",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: true,
      };
    }

    let completeAddress = await getAadharAddressFromXml(xml_file);
    if (false == completeAddress) {
      completeAddress = address;
    }

    if(CONSTANTS.USER_TYPE.TENANT === userType) {
      // const tenant = await tenantDB.getById({
      //   id: userId,
      // });
      let genderVal = "Male";
      if (gender && gender.toLowerCase() === "m") {
        genderVal = "Male";
      } else if (gender && gender.toLowerCase() === "f") {
        genderVal = "Female";
      } else {
        genderVal = "Other";
      }

      const DOB = dob ? dob.replaceAll("-", "/") : "-";
      const idNumberDB = "XXXX-XXXX-" + uid.slice(-4);
      const aadharFront = await generateAadhaarCardFront(
        userId,
        "uploads/documents/defaults/aadhar-base-image.jpg",
        name,
        DOB,
        genderVal,
        idNumberDB,
        photo_link,
        clientId
      );

      let frontUrl = null;
      if (aadharFront?.isSuccess) {
        frontUrl = aadharFront.imageUrl;
      }

      const aadharBack = await generateAadhaarCardBack(
        userId,
        "uploads/documents/defaults/aadhar-back-base-image.jpg",
        String(completeAddress),
        care_of,
        idNumberDB,
        clientId
      );

      let backUrl = null;
      if (aadharBack?.isSuccess) {
        backUrl = aadharBack.imageUrl;
      }

      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Tenant Aaadhar document fetched successfully`
      );
      return { isSuccess: true, photo: photo_link, uid, result: result, frontUrl, backUrl };

    } else if (CONSTANTS.USER_TYPE.STAFF === userType) {
      log.info(
        `[${C}], [${F}], [${U}], User Type [${userType}], User ID [${userId}], Type [AADHAAR], Staff Aaadhar document fetched successfully`
      );
      let frontUrl= null;
      let backUrl = null;
      return { isSuccess: true, photo: photo_link, uid, completeAddress, result: result, frontUrl, backUrl };
    } else {
      let frontUrl= null;
      let backUrl = null;
      return { isSuccess: true, photo: photo_link, uid, completeAddress, result: result, frontUrl, backUrl };
    }
    
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
      isDown: false,
    };
  }
};

