import log from "../config/log";
import jsSHA from "jssha";
import CONSTANTS from "../config/constants";
import { Request, Response } from "express";
import axios from "axios";
import querystring from "querystring";
import crypto from "crypto";
import CustomRequest from "../types/requestType";
import tenantDB from "../models/tenant.model";
import duesDB from "../models/dues.model";
import getDueDescription from "../utils/getDueDescription";
import clientDB from "../models/client.model";
import occupancyDB from "../models/occupancy.model";
import propertyDB from "../models/property.model";
import moment from "moment";
import { isUserPartner } from "../utils/isUserPartner";
import staffDB from "../models/staff.model";
import landlordDB from "../models/landlord.model";
import landlordAccountDB from "../models/landlordAccount.model";
import moveOutDB from "../models/moveOut.model";
import moveOutDuesDB from "../models/moveOutDues.model";
import getClientEaseBuzzCredentials from "../utils/getClientEaseBuzzCredentials";
import clientConfigDB from "../models/clientConfig.model";

const easebuzz: any = {};

easebuzz.GenerateAccessKey = async (req: CustomRequest, res: Response) => {
  const C = "Easebuzz Controller";
  const F = "GenerateAccessKey";
  try {
    const { dueId, ledgerReferenceId, charges = 0, mode = 2, gstAmount = 0 } = req.body;
    const tenantId = req.id;
    const email = 'kipinn.com@gmail.com';
    const clientId = req.clientId;
    let isEvicted = req.isEvicted;

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

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

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

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

    // const occupancy = await occupancyDB.getByTenantId({
    //   tenantId: tenantId,
    // });
    let occupancy = await occupancyDB.getByTenantIdAndClientId({
      tenantId: tenantId,
      clientId: clientId,
    });
    
    if (Number(isEvicted) === 1) {
      occupancy = await moveOutDB.getByTenantIdAndClientId({
        tenantId: tenantId,
        clientId: clientId,
      });
    }

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

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

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

    // const key = process.env.EASEBUZZ_KEY;
    // const salt = process.env.EASEBUZZ_SALT;

    let key = process.env.EASEBUZZ_KEY;
    let salt = process.env.EASEBUZZ_SALT;
    let subMerchantId = null;

    const easebuzzCreds = await getClientEaseBuzzCredentials(
      Number(clientId),
      Number(property?.id),
    );
    if (easebuzzCreds) {
      key = easebuzzCreds.key;
      salt = easebuzzCreds.salt;
      subMerchantId = easebuzzCreds.subMerchant || '';
    }

    if(isSecurityPayment) {
      let clientEasebuzzSecuritySubAccount = await clientConfigDB.getClientConfig({
        clientId,
        provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.EASEBUZZ,
        type: CONSTANTS.CLIENT_CONFIG_TYPE.SECURITY_PAYMENT_ACCOUNT.EASEBUZZ_SUB_ACCOUNT
      });
      if(clientEasebuzzSecuritySubAccount) {
        subMerchantId = clientEasebuzzSecuritySubAccount ? `${clientEasebuzzSecuritySubAccount?.value}` : null;
      }
    }

    const surl = process.env.WEB_CHECKOUT_SUCCESS_URL;
    const furl = process.env.WEB_CHECKOUT_FAILURE_URL;
    let udf1 = `${client.name}_${property.name}`;
    udf1 = udf1.trim();
    const udf2 = client.mobile;
    const udf3 = `${property.gId}_${tenantId}_${req.isEvicted}_${subMerchantId}`;
    const udf4 = dueIds;
    const udf5 = `${'APP'}_${charges}_${gstAmount}`;
    // const txnId = Date.now() + udf4;
    const txnId = Date.now() + tenant.id;
    let firstName = tenant.name;
    firstName = firstName.trim();
    const phone = tenant.mobile;
    const amount = totalAmount + Number(charges) + Number(gstAmount);
    const productInfo = `Payment for ${getDueDescription(CONSTANTS.DUES_TYPES.RENT)}`;

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

    // const apiEndpoint = "https://test.easebuzz.in/_payment";
    // const PAYU_API_URL = "https://secure.easebuzz.in/_payment"; // Change for production

    //Step 1: Create Hash String
    const hashString = `${key}|${txnId}|${amount}|${productInfo}|${firstName}|${email}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}||||||${salt}`;
    const hash = crypto.createHash("sha512").update(hashString).digest("hex");

    log.info(
      `[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Email [${email}], Due Id [${dueId}], Ledger Reference Id [${ledgerReferenceId}], Hash String [${hashString}], UDF1(Client Name) [${udf1}], UDF2(Client Mobile) [${udf2}], UDF3(propertyGid_tenantId) [${udf3}], UDF4(Due Id) [${udf4}], UDF5(LedgerReferenceId_Charges) [${udf5}], Transaction Id [${txnId}], First Name [${firstName}], Mobile [${phone}], Amount [${amount}], Product Info [${productInfo}],  Charges [${charges}], GST Amount [${gstAmount}], Mode [${paymentMode}], Tenant Requesting....`
    );

    const encodedParams = new URLSearchParams();

    encodedParams.append('key', String(key));
    encodedParams.append('txnid', txnId);
    encodedParams.append('amount', String(amount));
    encodedParams.append('productinfo', productInfo);
    encodedParams.append('firstname', firstName);
    encodedParams.append('email', 'kipinn.com@gmail.com');
    encodedParams.append('phone', '91' + phone);
    encodedParams.append('surl', String(surl));
    encodedParams.append('furl', String(furl));
    encodedParams.append('hash', hash);
    encodedParams.append('show_payment_mode', paymentMode);
    encodedParams.append('udf1', udf1);
    encodedParams.append('udf2', udf2);
    encodedParams.append('udf3', udf3);
    encodedParams.append('udf4', udf4);
    encodedParams.append('udf5', udf5);
    //This will only be used for OxoTel.
    if (subMerchantId) encodedParams.append('sub_merchant_id', subMerchantId);
    log.info(`[${C}], [${F}], Encoded Params [${encodedParams.toString()}]`);
    const options = {
      method: 'POST',
      url: process.env.EASEBUZZ_API,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Accept: 'application/json'
      },
      data: encodedParams,
    };
    const { data } = await axios.request(options);
    
    log.info(`[${C}], [${F}], Status [${data?.status}], Access Key [${data?.data}], Access key successfully shared`);
    //after succesfull hashing of hash
    return res.status(200).json({
      msg: `Access key generated successfull`,
      data: data?.data,
      isSuccess: true,
    });
    //return res.send(formHtml);
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

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

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

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

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

    // if(Number(payableAmount) && Number(payableAmount) > 0) {
    //   totalAmount = payableAmount;
    // }

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

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

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

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

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

    let key = process.env.EASEBUZZ_KEY;
    let salt = process.env.EASEBUZZ_SALT;
    let subMerchantId = null;

    const easebuzzCreds = await getClientEaseBuzzCredentials(
      Number(clientId),
      Number(property?.id),
    );

    if (easebuzzCreds) {
      key = easebuzzCreds.key;
      salt = easebuzzCreds.salt;
      subMerchantId = easebuzzCreds.subMerchant;
    }
    if(isSecurityPayment) {
      let clientEasebuzzSecuritySubAccount = await clientConfigDB.getClientConfig({
        clientId,
        provider: CONSTANTS.CLIENT_CONFIG_PROVIDER.EASEBUZZ,
        type: CONSTANTS.CLIENT_CONFIG_TYPE.SECURITY_PAYMENT_ACCOUNT.EASEBUZZ_SUB_ACCOUNT
      });
      if(clientEasebuzzSecuritySubAccount) {
        let secSubMerchantId = clientEasebuzzSecuritySubAccount ? `${clientEasebuzzSecuritySubAccount?.value}` : null;
        if(secSubMerchantId) {
          subMerchantId = secSubMerchantId;
        }
      }
    }
    // const surl = process.env.OXO_WEB_CHECKOUT_SUCCESS_URL;
    // const furl = process.env.OXO_WEB_CHECKOUT_FAILURE_URL;
    let udf1 = `${client.name}_${property.name}`;
    udf1 = udf1.trim();
    const udf2 = client.mobile;
    const udf3 = `${property.gId}_${tenantId}_${req.isEvicted}_${subMerchantId}`;
    const udf4 = dueIds;
    let udf5 = `${'PAYVIALINK'}_${charges}_${gstAmount}`;
    if (isBookingPayment) {
      udf5 = `${'BOOKINGLINK'}_${charges}_${gstAmount}`;
    }
    // const txnId = Date.now() + udf4;
    const txnId = Date.now() + tenant.id;
    let firstName = tenant.name;
    firstName = firstName.trim();
    const phone = tenant.mobile;
    const amountPay = totalAmount + Number(charges) + Number(gstAmount);
    let productInfo = `Payment for `;
    if(true == isBookingPayment){
      productInfo += `Booking`;
    } else if(dueId && dueId.length == 1){
      productInfo += `${getDueDescription(dueType)}`;
    } else {
      productInfo += `pending dues`;
    }

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

    // const apiEndpoint = "https://test.easebuzz.in/_payment";
    // const PAYU_API_URL = "https://secure.easebuzz.in/_payment"; // Change for production

    //Step 1: Create Hash String
    // const hashString = `${key}|${txnId}|${amount}|${productInfo}|${firstName}|${email}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}||||||${salt}`;

    const hashString = `${key}|${txnId}|${firstName}|${email}|${phone}|${amountPay}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}|${productInfo}|${salt}`;
    //const hashString = `${key}|${txnId}|${firstName}|${phone}|${amount}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}|${productInfo}|${salt}`;
    const hash = crypto.createHash("sha512").update(hashString).digest("hex");

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

    //show_payment_mode
    const options = {
      method: 'POST',
      url: process.env.EASEBUZZ_WEB_CHECKOUT,
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      data: {
        merchant_txn: txnId,
        key: key,
        email: email,
        name: firstName,
        amount: amountPay,
        phone: phone,
        udf1: udf1,
        udf2: udf2,
        udf3: udf3,
        udf4: udf4,
        udf5: udf5,
        show_payment_mode: paymentMode,
        message: productInfo,
        expiry_date: moment().add(2, 'days').format('DD-MM-YYYY'),
        operation: [
          { type: 'sms', template: 'Default sms template' },
        ],
        hash: hash
      }
    };
    if (subMerchantId) (options.data as any).sub_merchant_id = subMerchantId;
    log.info(`[${C}], [${F}], Client Id [${client.id}], Tenant Id [${tenantId}], Request [${JSON.stringify(options)}]`);
    const { data } = await axios.request(options);
    log.info(`[${C}], [${F}], Status [${data?.status}], Payment Url [${data?.data?.payment_url}], Payment url shared`);
    //after succesfull hashing of hash
    return res.status(200).json({
      msg: `Payment url generated successfull`,
      data: data?.data,
      isSuccess: true,
    });
    //return res.send(formHtml);
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

export default easebuzz;
