import moment from "moment";
import CONSTANTS from "../config/constants";
import log from "../config/log";
import clientDB from "../models/client.model";
import eqaroPropertiesDB from "../models/eqaroProperties.model";
import occupancyDB from "../models/occupancy.model";
import tenantTypes from "../schemas/tenant.schema";
import eqaroLandlordsDB from "../models/eqaroLandlords.model";
import eqaroAPIs from "./eqaroAPIs";
import eqaroTenantsDB from "../models/eqaroTenants.model";
import fs from "fs";
import documentDB from "../models/document.model";
import tenantDB from "../models/tenant.model";
import eqaroCoApplicantsDB from "../models/eqaroCoApplicants.model";

export const eqaroStatus = async (tenant: tenantTypes) => {
  const U = "checkEqaroStatus";
  const F = "eqaroStatus";

  try {
    const mobile = tenant.mobile;
    let response = null;
    let eqaroTenant: {
      mobile: any;
      accessToken: any;
      eqaroUserId: any;
      bondId: any;
      tenantId: any;
    };

    const occupancy = await occupancyDB.getByTenantId({
      tenantId: tenant.id,
    });
    if (!occupancy) {
      log.info(`[${U}], [${F}], Mobile [${mobile}], Occupancy not found`);
      return false;
    }

    // const landlord = await clientDB.getById({
    //   id: occupancy.clientId,
    // });
    // if (!landlord) {
    //   log.info(
    //     `[${U}], [${F}], Mobile [${mobile}], Client Id [${occupancy.clientId}] Client not found`
    //   );
    //   return false;
    // }

    // const landlordMobile = landlord.mobile;

    let eqaroLandlord = await eqaroLandlordsDB.getByClientId({
      clientId: occupancy.clientId,
    });
    if (!eqaroLandlord) {
      log.info(
        `[${U}], [${F}], Client Id [${occupancy.clientId}], Landlord not found`
      );
      return false;
    }
    const landlordMobile = eqaroLandlord.mobile.slice(-10);

    const eqaroTokenExpiresAt = moment(
      eqaroLandlord.tokenExpiresAt,
      "YYYY-MM-DD HH:mm:ss"
    );
    const now = moment();

    if (eqaroTokenExpiresAt.isBefore(now)) {
      log.info(
        `[${U}], [${F}], Landlord Mobile [${landlordMobile}], Landlord token expired, Loginng in landlord`
      );

      const landlordLoginBody = {
        phone: landlordMobile,
        key: "YecbTaNUJpAdFSuUX1HPtNwY3LgJyQRP", // to be shifted to env
      };

      response = await eqaroAPIs.getTokenApi(
        landlordMobile,
        "users/token/landlord/phone",
        landlordLoginBody
      );

      if (response && response.message !== "Not Found") {
        log.info(
          `[${U}], [${F}], Landlord Mobile [${landlordMobile}], landlord login successful`
        );

        await eqaroLandlordsDB.updateAccessTokens({
          mobile: `91${landlordMobile}`,
          accessToken: response.access.token,
          tokenExpiresAt: moment(response.access.expires).format(
            "YYYY-MM-DD HH:mm:ss"
          ),
        });

        log.info(
          `[${U}], [${F}], Landlord Mobile [${landlordMobile}], Landlord token updated successfully, checking if user is registered with eqaro`
        );

        eqaroLandlord = await eqaroLandlordsDB.getByMobile({
          mobile: `91${landlordMobile}`,
        });
      } else {
        log.info(
          `[${U}], [${F}], Landlord Mobile [${landlordMobile}], landlord login failed`
        );
        return false;
      }
    } else {
      log.info(
        `[${U}], [${F}], Landlord Mobile [${landlordMobile}], Landlord token not expired, checking if user is registered with eqaro`
      );
    }

    const isUserRegisteredBody = {
      phone: `91${mobile}`,
    };

    response = await eqaroAPIs.isUserCheckpostApi(
      mobile,
      eqaroLandlord.accessToken,
      "users/userid",
      isUserRegisteredBody
    );

    if (response && response.data?.profileId) {
      log.info(
        `[${U}], [${F}], Mobile [${mobile}], Tenant found in eqaro database, checking if tenant is registered in Kipinn`
      );

      const loginBody = {
        phone: `91${mobile}`,
      };

      const loginresponse = await eqaroAPIs.getTokenApi(
        mobile,
        "users/getUserByPhoneOrEmail",
        loginBody
      );
      if (loginresponse && loginresponse.message !== "Not Found") {
        eqaroTenant = await eqaroTenantsDB.getByTenantId({
          tenantId: tenant?.id,
        });
        if (!eqaroTenant) {
          log.info(
            `[${U}], [${F}], Mobile [${mobile}], Tenant found in eqaro database, registering tenant in Kipinn`
          );
          await eqaroTenantsDB.create({
            tenantId: tenant.id,
            propId: occupancy?.propId || null,
            eqaroUserId: loginresponse?.user?.id || loginresponse?.user[0]?.id,
            eqaroProfileId:
              loginresponse?.user?.profileId ||
              loginresponse?.user[0]?.profileId,
            status: CONSTANTS.EQARO_TENANT_STATUS.REGISTERED,
            occupation: null,
            mobile: mobile,
            monthlyIncome:
              loginresponse?.user[0]?.employmentDetails.monthlyIncome || null,
            accessToken: loginresponse.tokens.access.token,
            refreshToken: loginresponse.tokens.refresh.token,
            accessTokenExpires: moment(
              loginresponse.tokens.access.expires
            ).format("YYYY-MM-DD HH:mm:ss"),
            refreshTokenExpires: moment(
              loginresponse.tokens.refresh.expires
            ).format("YYYY-MM-DD HH:mm:ss"),
          });
          eqaroTenant = await eqaroTenantsDB.getByTenantId({
            tenantId: tenant?.id,
          });
        }
      } else {
        log.info(
          `[${U}], [${F}], Tenant Mobile [${mobile}], Failure to log into tenant in eqaro`
        );
        return false;
      }

      const getTenantTokenBody = {
        tenantId: response?.data?.id,
      };

      response = await eqaroAPIs.postApi(
        mobile,
        eqaroLandlord.accessToken,
        "users/token/tenant",
        getTenantTokenBody
      );
      if (response && response.data?.access) {
        log.info(
          `[${U}], [${F}], Tenant Mobile [${mobile}], Tenant Token retrieved successfully`
        );

        await eqaroTenantsDB.updateTenantAccessToken({
          tenantId: tenant.id,
          accessToken: response.data.access.token,
          accessTokenExpires: moment(response.data.access.expires).format(
            "YYYY-MM-DD HH:mm:ss"
          ),
        });
      } else {
        log.info(
          `[${U}], [${F}], Tenant Mobile [${mobile}], Failure to get tenant token`
        );
        return false;
      }
    } else {
      eqaroTenant = await eqaroTenantsDB.getByTenantId({
        tenantId: tenant.id,
      });
      if (eqaroTenant) {
        log.info(
        `[${U}], [${F}], Mobile [${mobile}], Tenant not found in eqaro database, deleting tenant from Kipinn`
        );
        await eqaroTenantsDB.deleteTenant({
          tenantId: tenant.id,
        });
        await eqaroCoApplicantsDB.deleteByTenantId({
          tenantId: tenant.id,
        });
      }
      return false;
    }

    const updatedEqaroTenant = await eqaroTenantsDB.getByTenantId({
      tenantId: tenant.id,
    });

    const tenantStatusBody = {
      phone: `91${mobile}`,
    };

    const statusResponse = await eqaroAPIs.postApi(
      mobile,
      updatedEqaroTenant.accessToken,
      "users/tenant/status",
      tenantStatusBody
    );

    log.info(
      `[${U}], [${F}], Mobile [${mobile}], Status [${
        updatedEqaroTenant.status
      }], Eqaro Status [${statusResponse.data.status.toLowerCase()}] `
    );

    let status =
      statusResponse.data.status.toLowerCase() === "none"
        ? CONSTANTS.EQARO_TENANT_STATUS.REGISTERED
        : statusResponse.data.status.toLowerCase() === "basiceligible"
        ? CONSTANTS.EQARO_TENANT_STATUS.BASIC_ELIGIBILITY_VERIFICATION_DONE
        : statusResponse.data.status.toLowerCase() === "eligible"
        ? CONSTANTS.EQARO_TENANT_STATUS.MAIN_ELIGIBILITY_VERIFICATION_DONE
        : statusResponse.data.status.toLowerCase() === "bond"
        ? CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED
        : statusResponse.data.status.toLowerCase() === "incomplete"
        ? CONSTANTS.EQARO_TENANT_STATUS.REGISTERED
        : statusResponse.data.status.toLowerCase() === "ineligible"
        ? CONSTANTS.EQARO_TENANT_STATUS.INELIGIBLE
        : 0;

    await eqaroTenantsDB.updateStatus({
      tenantId: tenant.id,
      status: status,
    });

    if (status === CONSTANTS.EQARO_TENANT_STATUS.BOND_ISSUED) {
      log.info(
        `[${U}], [${F}], Mobile [${mobile}], Bond Already Issued, fetching bond details from Eqaro`
      );

      const response = await eqaroAPIs.paymentGetApi(
        eqaroTenant.mobile,
        eqaroTenant.accessToken,
        `bond/tenant/${eqaroTenant.eqaroUserId}`
      );

      await eqaroTenantsDB.updateBondDetails({
        tenantId: tenant.id,
        bondAmount: response.data.bondAmount,
        bondFee: response.data.bondFee,
        bondId: response.data.id,
        bondEffectiveDate: moment(response.data.bondEffectiveDate).format(
          "YYYY-MM-DD"
        ),
        bondExpiryDate: moment(response.data.bondExpiryDate)
          .add(1, "year")
          .format("YYYY-MM-DD"),
        orderId: response.data.eqaroOrderId,
      });

      if (response && response.data) {
        log.info(
          `[${U}], [${F}], Mobile [${eqaroTenantsDB.mobile}], Bond details fetched successfully`
        );
      } else {
        log.info(
          `[${U}], [${F}], Mobile [${eqaroTenantsDB.mobile}], Failure to fetch bond details`
        );
        return true;
      }

      eqaroTenant = await eqaroTenantsDB.getByTenantId({
        tenantId: tenant?.id,
      });

      (async () => {
        let apiTryCount = 1;
        const hitGenerateBond = async () => {
          const response = await eqaroAPIs.bondGetApi(
            eqaroTenant.mobile,
            eqaroTenant.accessToken,
            `generate/bond/pdf?bondId=${eqaroTenant.bondId}`
          );
          return response;
        };

        let response = await hitGenerateBond();
        while (!response || !response.data) {
          if (apiTryCount < 3) {
            log.info(
              `[${U}], [${F}], Mobile [${eqaroTenant.mobile}], Try Count [${apiTryCount}] Failure in generating PDF, Retrying...`
            );

            apiTryCount++;
            response = await hitGenerateBond();
          } else {
            log.info(
              `[${U}], [${F}], Mobile [${eqaroTenant.mobile}], Try Count [${apiTryCount}] Failure in generating PDF, Please try again after sometime.`
            );
            return true;
          }
        }
        const contentLength = response.headers["content-length"];
        if (parseInt(contentLength) > 0) {
          const folderName = `tenant_${occupancy.tenantId}`;
          const folderPath = `uploads/documents/client_${occupancy.clientId}/prop_${occupancy.propId}/room_${occupancy.roomId}_bed_${occupancy.bedId}/${folderName}`;
          const fileName = `${eqaroTenant?.tenantId}Bond.pdf`;
          const filePath = `${folderPath}/${fileName}`;

          if (!fs.existsSync(folderPath)) {
            fs.mkdirSync(folderPath, { recursive: true });
          }

          fs.writeFileSync(filePath, response.data);

          const url = `${process.env.UPLOAD_PATH}/documents/client_${occupancy.clientId}/prop_${occupancy.propId}/room_${occupancy.roomId}_bed_${occupancy.bedId}/${folderName}/${fileName}`;

          await eqaroTenantsDB.updateBondPdf({
            tenantId: eqaroTenant.tenantId,
            bondUrl: url,
          });

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

          log.info(
            `[${U}], [${F}], Mobile [${eqaroTenant.mobile}], Bond PDF generated successfully`
          );

          return true;
        } else {
          log.info(
            `[${U}], [${F}], PDF data is empty for bond ID [${eqaroTenant.bondId}]`
          );
          return true;
        }
      })();
    }
    return true;
  } catch (error: any) {
    log.info(`[${U}], [${F}], Error: ${error?.message || error}`);
    return {
      isSuccess: false,
      isServerError: true,
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
    };
  }
};
