import axios from "axios";
import CONSTANTS from "../../../config/constants";
import log from "../../../config/log";
import fsPromises from "fs/promises";
import documentDB from "../../../models/document.model";
import occupanciesTypes from "../../../schemas/occupancy.schema";
import occupancyDB from "../../../models/occupancy.model";
import documentsTypes from "../../../schemas/document.schema";
import tenantDB from "../../../models/tenant.model";
import moment from "moment";

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

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

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

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

    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 axiosHeaders = {
          headers: {
            "Content-Type": "application/json",
            Authorization: process.env.SIGNZY_API_ACCESS_TOKEN,
          },
        };

        const body: any = {
          frontUrl: oldFrontPath,
          backUrl: oldBackPath || "",
        };

        const { data: response } = await axios.post(
          process.env.SIGNZY_AADHAAR_OCR_API!,
          body,
          axiosHeaders
        );

        return response;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Signzy 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 Signzy `
      );

      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], Signzy Response [${JSON.stringify(
        response
      )}]`
    );

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

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
        isServerError: false,
      };
    } else if (!response?.result?.validBackAndFront) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Signzy 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,
        dob,
        yob,
        pincode,
        address,
        gender,
      } = response.result;

      if (!name && dob === "Not available on aadhaar") {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Did not get Name & DoB field from Signzy 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 (maskedFrontUrl) {
        const imageResponse = await axios.get(maskedFrontUrl, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = maskedFrontUrl.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer);
        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 (maskedBackUrl) {
        const imageResponse = await axios.get(maskedBackUrl, {
          responseType: "arraybuffer",
        });
        const buffer = Buffer.from(imageResponse.data, "utf-8");
        const splitUrl = maskedBackUrl.split(".");
        const ext = splitUrl[splitUrl.length - 1];
        const fileName = `Id_back_document.${ext}`;
        await fsPromises.writeFile(`${folderPath}/${fileName}`, buffer);
        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,
        dob,
        genderVal,
        address,
        name,
        result: response.result,
      };
    }
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
    };
  }
};

export const addAadhaarNumberToSignzy = async ({
  tenantId,
  IdNumber,
  maskedIdNumber,
  isExists,
}: addParamTypes) => {
  const C = "Tenant Controller";
  const F = "AddIDNumber";
  const U = "addAadhaarNumberToSignzy";
  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 axiosHeaders = {
          headers: {
            "Content-Type": "application/json",
            Authorization: process.env.SIGNZY_API_ACCESS_TOKEN,
          },
        };

        const body = {
          aadhaarNumber: IdNumber,
        };

        const { data: result } = await axios.post(
          process.env.SIGNZY_AADHAAR_GENERATE_OPT_API!,
          body,
          axiosHeaders
        );

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Signzy API 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);
        } else {
          return false;
        }
      }
    };

    result = await generateAadhaarOTP();

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

    if (result?.error) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], ID Number [${maskedIdNumber}], Error [${result?.error?.message}] `
      );

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

    requestId = result?.data.requestId;

    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 verifyOTPFromSignzy = async ({
  tenantId,
  requestId,
  otp,
  docId,
}: verifyParamTypes) => {
  const C = "Tenant Controller";
  const F = "VerifyIDNumber";
  const U = "verifyOTPFromSignzy";
  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 axiosHeaders = {
          headers: {
            "Content-Type": "application/json",
            Authorization: process.env.SIGNZY_API_ACCESS_TOKEN,
          },
        };

        const body = {
          requestId,
          otp,
        };

        const { data: result } = await axios.post(
          process.env.SIGNZY_AADHAAR_GET_DETAILS_API!,
          body,
          axiosHeaders
        );

        return result;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Signzy API 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], 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 Signzy `
      );

      return {
        msg: "Unable to verify your aadhaar number. Please try again later.",
        isSuccess: false,
        isServerError: false,
        isDown: true,
        isTimeout: false,
      };
    }

    if (result?.error) {
      log.info(
        `[${C}], [${F}], [${U}] Tenant Id [${tenantId}], Type [AADHAAR], Request Id [${requestId}], OTP [${otp}], Doc Id [${docId}], Error [${result?.error?.message}] `
      );

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE || "Something Went Wrong",
        isSuccess: false,
        isServerError: false,
        isDown: false,
        isTimeout: false,
      };
    }

    const { full_name, dob, gender, address, care_of, zip } = result?.data;

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

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

    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;
    }

    let addressVal = `${address?.house || ""} ${address?.street || ""} ${
      address?.landmark || ""
    } ${address?.vtc || ""} ${address?.dist || ""}, ${address?.state || ""}, ${
      address?.country || ""
    } ${zip || ""}`;

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

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

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

    return { isSuccess: true, photo: result?.data?.profile_image };
  } 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 uploadAadhaarToSignzyCoApplicant = async ({
  tenantId,
  oldFrontPath,
  oldBackPath,
}: uploadParamTypes) => {
  const C = "Tenant Controller";
  const F = "UploadID";
  const U = "uploadAadhaarToSignzy";
  try {
    let retryNo = 0;

    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 axiosHeaders = {
          headers: {
            "Content-Type": "application/json",
            Authorization: process.env.SIGNZY_API_ACCESS_TOKEN,
          },
        };

        const body: any = {
          frontUrl: oldFrontPath,
          backUrl: oldBackPath || "",
        };

        const { data: response } = await axios.post(
          process.env.SIGNZY_AADHAAR_OCR_API!,
          body,
          axiosHeaders
        );

        return response;
      } catch (error: any) {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Signzy 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 Signzy `
      );

      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], Signzy Response [${JSON.stringify(
        response
      )}]`
    );

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

      return {
        msg: CONSTANTS.MSG.ERROR_MESSAGE,
        isSuccess: false,
        isServerError: false,
      };
    } else if (!response?.result?.validBackAndFront) {
      log.info(
        `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Signzy 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,
        dob,
        yob,
        pincode,
        address,
        gender,
      } = response.result;

      if (!name && dob === "Not available on aadhaar") {
        log.info(
          `[${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Did not get Name & DoB field from Signzy 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,
        };
      }

      log.info(`
        [${C}], [${F}], [${U}], Tenant Id [${tenantId}], Type [AADHAAR], Co-Applicant adhaar processed 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,
        dob,
        genderVal,
        address,
        name,
        result: response.result,
      };
    }
  } catch (error: any) {
    return {
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      logMsg: `SERVER ERROR: ${error?.message || error}`,
      isSuccess: false,
      isServerError: true,
    };
  }
};
