import { number } from "zod";
import CONSTANTS from "../../config/constants";
import payoutBeneficiaryDB from "../../models/payoutBeneficiary.model";
import payoutTransactionDB from "../../models/payoutTransaction.model";
import cashfreePayout from "../../utils/cashfreePayout";
import generatePayOutTransId from "../../utils/generatePayoutTransId";
import { recordTransferInitiate } from "../../utils/walletHelper";
import { autopayLog } from "../serviceLog";
import autopayQueueDB from "./autopay.model";

async function makeTransactions() {
  const C = "Autopay Queue Worker";
  const F = "makeTransactions";

  try {
    const pendingTransactions = await autopayQueueDB.getPendingTransactions();

    // autopayLog.info(`[${C}], [${F}], Pending Transactions [${JSON.stringify(pendingTransactions)}]`);

    if (pendingTransactions && pendingTransactions.length > 0) {
      for (const transaction of pendingTransactions) {
        
        autopayLog.info(`[${C}], [${F}], Processing Transaction Id [${transaction.id}], Client Id [${transaction.clientId}], Autopay Id [${transaction.autopayId}], Transaction Amount [${transaction.amount}], Beneficiary Id [${transaction.beneficiaryId}], Due Date [${transaction.dueDate}], Current Status [${transaction.status}]`);
        
        const autopay = await autopayQueueDB.getAutopayById({
          id: transaction.autopayId,
        });        

        const clientWallet = await autopayQueueDB.getWalletByClientIdAndStaffId({
          clientId: autopay?.clientId,
          staffId: null,
        });

        const wallet = await autopayQueueDB.getWalletByClientIdAndStaffId({
          clientId: autopay?.clientId,
          staffId: autopay?.addedByUserType === CONSTANTS.USER_TYPE.STAFF ? autopay?.addedBy : null,
        });

        autopayLog.info(`[${C}], [${F}], ClientId [${autopay?.clientId}], User Type [${autopay?.addedByUserType}], Wallet Amount [${wallet?.amount}], Client Wallet Amount [${clientWallet?.amount}], Wallet Balance [${wallet?.balance}], Client Wallet Balance [${clientWallet?.balance}], Transaction Amount [${transaction?.amount}]`);

        if (Number(wallet?.balance) < Number(transaction.amount)) {
          autopayLog.info(
            `[${C}],[${F}], Client Id [${transaction?.clientId}], Autopay Id [${transaction?.autopayId}], Wallet Balance [${wallet?.balance}], Transfer Amount [${transaction?.amount}], Insufficient Balance`
          );

          await autopayQueueDB.updateQueueRecordStatus({
            id: transaction.id,
            status: CONSTANTS.AUTOPAY_QUEUE_STATUS.FAILED,
            description: "Insufficient Balance in wallet",
          });

          continue;
        }

        let transferId = await generatePayOutTransId();
        let transferMode = "neft";

        let accountDetails = await payoutBeneficiaryDB.getById({
          id: transaction.beneficiaryId,
        });
        const accountName = accountDetails?.holderName;
        const accountNumber = accountDetails?.accountNum;
        const ifsc = accountDetails?.ifsc;

        const payoutResp = await cashfreePayout.payoutToBeneficiary(
          C,
          F,
          transaction.clientId,
          transferId,
          transaction.amount,
          accountDetails?.cfBeneficiaryId, //beneficiaryId
          transferMode,
          "Auto pay transaction", //Remarks
        );

        autopayLog.info(`[${C}], [${F}], ClientId [${autopay?.clientId}], Payout Initiate Response [${JSON.stringify(payoutResp)}]`);

        if (payoutResp?.data?.status) {
          let autopayStatus = CONSTANTS.AUTOPAY_QUEUE_STATUS.IN_PROGRESS;
          let status = CONSTANTS.TRANSFER_STATUS.INITIATED;
          if ("FAILED" === payoutResp?.data?.status.toUpperCase()) {
            status = CONSTANTS.TRANSFER_STATUS.FAILED;
            autopayStatus = CONSTANTS.AUTOPAY_QUEUE_STATUS.FAILED;
          }
          else if ("REJECTED" === payoutResp?.data?.status.toUpperCase()) {
            status = CONSTANTS.TRANSFER_STATUS.REJECTED;
            autopayStatus = CONSTANTS.AUTOPAY_QUEUE_STATUS.FAILED;
          }
          const transId = await payoutTransactionDB.add({
            clientId: transaction.clientId,
            transId: transferId,
            cfTransferId: payoutResp?.data?.cf_transfer_id,
            amount: transaction.amount,
            vendorChargeDeducted: 0,
            charges: null,
            mode: CONSTANTS.PAYOUT_MODE.NEFT,
            payoutBeneficiaryId: accountDetails?.id,
            cfBeneficiaryId: accountDetails?.cfBeneficiaryId,
            expenseId: null,
            expenseType: Number(autopay.type) === CONSTANTS.AUTOPAY_TYPES.UNLIMITED_TRANSACTIONS ? Number(autopay.expenseType) : null,
            status,
            statusDescription: payoutResp?.data?.status_description,
            holderName: accountName,
            accountNum: accountNumber,
            ifsc: ifsc,
            remark: "",
            doneById: transaction.clientId,
            doneByType: CONSTANTS.USER_TYPE.CLIENT,
            beneficiaryMobile: accountDetails?.mobile,
            currentBalance: clientWallet?.amount,
            autopayQueueId: transaction.id,
          });

          if ("REJECTED" !== payoutResp?.data?.status.toUpperCase() && "FAILED" !== payoutResp?.data?.status.toUpperCase()) {
            await recordTransferInitiate({
              clientId: transaction.clientId,
              userType: autopay?.addedByUserType,
              staffId: autopay?.addedByUserType === CONSTANTS.USER_TYPE.STAFF ? autopay?.addedBy : null,
              transferAmount: Number(Number(transaction?.amount).toFixed(2)),
            });
            await payoutTransactionDB.updateIsWalletAdjusted({
              id: transId,
              isWalletAdjusted: 1,
            });
          }

          await autopayQueueDB.updateQueueRecordStatus({
            id: transaction.id,
            status: autopayStatus,
            description: payoutResp?.data?.status_description,
          });

          autopayLog.info(
            `[${C}], [${F}], Client Id [${transaction?.clientId}], Beneficiary Id [${transaction?.beneficiaryId}], Transfer initiated successfully`,
          );
        } else {
          await autopayQueueDB.updateQueueRecordStatus({
            id: transaction.id,
            status: CONSTANTS.AUTOPAY_QUEUE_STATUS.FAILED,
            description: payoutResp?.error?.message,
          });

          autopayLog.info(
            `[${C}], [${F}], Client Id [${transaction?.clientId}], Beneficiary Id [${transaction?.beneficiaryId}], Transfer Failed, Error [${payoutResp?.error?.message}]`,
          );
        }
      }
    }

    autopayLog.info(`[${C}], [${F}], Queue Worker Completed`);

    process.exit();
  } catch (error) {
    autopayLog.info(`[${C}], [${F}], Error [${error}]`);
    process.exit()
  }
};

makeTransactions();
