package com.payusdk;

import android.util.Log;

import androidx.annotation.NonNull;
import static com.payu.india.Payu.PayuConstants.VERSION_KEY;
import com.facebook.common.internal.ImmutableList;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.payu.india.Interfaces.CheckoutDetailsListener;
import com.payu.india.Interfaces.FetchOfferDetailsListener;
import com.payu.india.Interfaces.GetEmiAmountAccordingToInterestApiListener;
import com.payu.india.Interfaces.GetTransactionInfoApiListener;
import com.payu.india.Interfaces.HashCompletionListener;
import com.payu.india.Interfaces.HashGenerationListener;
import com.payu.india.Interfaces.PaymentRelatedDetailsListener;
import com.payu.india.Interfaces.ValidateOfferApiListener;
import com.payu.india.Interfaces.ValueAddedServiceApiListener;
import com.payu.india.Model.FetchOffer.FetchOfferApiRequest;
import com.payu.india.Model.MerchantWebService;
import com.payu.india.Model.PaymentDetailsForOffer;
import com.payu.india.Model.PaymentParams;
import com.payu.india.Model.PayuConfig;
import com.payu.india.Model.PayuResponse;
import com.payu.india.Model.UserDetailsForOffer;
import com.payu.india.Model.validateOffer.ValidateOfferRequest;
import com.payu.india.Payu.PayuConstants;
import com.payu.india.Payu.PayuErrors;
import com.payu.india.PostParams.MerchantWebServicePostParams;
import com.payu.india.Tasks.BinInfoTask;
import com.payu.india.Tasks.GetCardInformationTask;
import com.payu.india.Tasks.GetCheckoutDetailsTask;
import com.payu.india.Tasks.GetEmiAmountAccordingToInterestTask;
import com.payu.india.Tasks.GetPaymentRelatedDetailsTask;
import com.payu.india.Tasks.GetTransactionInfoTask;
import com.payu.india.Tasks.LookupTask;
import com.payu.india.Tasks.V2ApiTask;
import com.payu.india.Tasks.ValueAddedServiceTask;
import com.payu.india.Tasks.VerifyPaymentTask;
import com.payu.india.Tasks.GetConfigTask;
import com.payu.india.Tasks.CheckBalanceTask;
import com.payu.india.Tasks.EligibleBinsForEMITask;
import com.payu.india.Tasks.DeleteTokenisedCardTask;
import com.payu.india.Tasks.GetTokenisedCardDetailsTask;
import com.payu.india.Tasks.GetTokenisedCardTask;
import com.payu.india.Tasks.GetIbiboCodesTask;
import com.payu.india.Tasks.FetchIFSCDetailsTask;
import com.payu.paymentparamhelper.PaymentPostParams;
import com.payu.paymentparamhelper.PostData;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.lang.*;


@ReactModule(name = PayuSdkModule.NAME)
public class PayuSdkModule extends ReactContextBaseJavaModule implements HashGenerationListener {
  public static final String NAME = "PayUSdk";
  public static final String TAG = "PayUSdkTAG";
  private final Utils utils = new Utils();
  private ReactApplicationContext reactContext ;
  private Callback successCallback = null;
  private Callback errorCallback = null;

  HashMap<String, HashCompletionListener> listenermap = new HashMap<String, HashCompletionListener>();
  String commond = "";

  public PayuSdkModule(ReactApplicationContext reactContext) {

    super(reactContext);
    this.reactContext=reactContext;
  }

  @Override
  @NonNull
  public String getName() {
    return NAME;
  }

  @ReactMethod
  public void makePayment(ReadableMap data, Callback successCallback, Callback errorCallback) {
    this.successCallback = successCallback;
    this.errorCallback = errorCallback;

    PaymentParams paymentParams = new PaymentParams();
    paymentParams.setKey(data.getString(PayuConstantsCorePG.KEY));
    paymentParams.setAmount(data.getString(PayuConstantsCorePG.AMOUNT));
    paymentParams.setTxnId(data.getString(PayuConstantsCorePG.TXNID));
    paymentParams.setPhone(data.getString(PayuConstantsCorePG.PHONE));
    paymentParams.setProductInfo(data.getString(PayuConstantsCorePG.PRODUCT_INFO));
    paymentParams.setFirstName(data.getString(PayuConstantsCorePG.FIRST_NAME));
    paymentParams.setEmail(data.getString(PayuConstantsCorePG.EMAIL));
    paymentParams.setSurl(data.getString(PayuConstantsCorePG.SURL));
    paymentParams.setFurl(data.getString(PayuConstantsCorePG.FURL));
    paymentParams.setUserCredentials(data.getString(PayuConstantsCorePG.USER_CREDENTIAL));
    paymentParams.setHash(data.getString(PayuConstantsCorePG.HASH));
    paymentParams.setUdf1(data.getString(PayuConstantsCorePG.UDF1));
    paymentParams.setUdf2(data.getString(PayuConstantsCorePG.UDF2));
    paymentParams.setUdf3(data.getString(PayuConstantsCorePG.UDF3));
    paymentParams.setUdf4(data.getString(PayuConstantsCorePG.UDF4));
    paymentParams.setUdf5(data.getString(PayuConstantsCorePG.UDF5));
    ReadableMap offerParams = data.getMap(PayuConstantsCorePG.OFFER_PARAMS);
    if(offerParams!=null) {
      paymentParams.setOfferKey(offerParams.getString(PayuConstantsCorePG.OFFER_KEYS));
    } else {
      paymentParams.setOfferKey(data.getString(PayuConstantsCorePG.OFFER_KEYS));
    }
    if (data.getString(PayuConstantsCorePG.IS_PAYU_RETRY_ENABLED)!=null && utils.parseStringToBool(data.getString(PayuConstantsCorePG.IS_PAYU_RETRY_ENABLED)))
    paymentParams.setRetryCount(1);

    Log.v(PayuConstantsCorePG.PAYU,PayuConstantsCorePG.SDK_PATFORM_DATA+addAnalytics());
    paymentParams.setSdkPlatformData(addAnalytics());
    String paymentMode;

    if (data.getString(PayuConstantsCorePG.PAYMENT_TYPE) == null) {
      errorCallback.invoke(new HashMap<String, String>() {{
        put(PayuConstantsCorePG.ERROR, PayuConstantsCorePG.PAYMENT_TYPE_MISSING);
      }});
      return;
    }

      switch (data.getString(PayuConstantsCorePG.PAYMENT_TYPE)) {
        case PayuConstantsCorePG.CC_DC:
        case PayuConstantsCorePG.SAVED_CARDS:

            paymentParams.setCvv(data.getString(PayuConstantsCorePG.CVV));
            paymentParams.setBankCode(PayuConstants.CC);
            paymentParams.setNameOnCard(data.getString(PayuConstantsCorePG.NAME_ON_CARD));
            paymentParams.setCardToken(data.getString(PayuConstantsCorePG.CARD_TOKEN));
            paymentParams.setCardNumber(data.getString(PayuConstantsCorePG.CARD_NUMBER));
            paymentParams.setExpiryMonth(data.getString(PayuConstantsCorePG.EXPIRY_MONTH));
            paymentParams.setExpiryYear(data.getString(PayuConstantsCorePG.EXPIRY_YEAR));

            if (data.hasKey(PayuConstantsCorePG.STORE_CARD)) {
              int storeCard = data.getInt(PayuConstantsCorePG.STORE_CARD);
              paymentParams.setStoreCard(storeCard);
            } else if (data.hasKey(PayuConstantsCorePG.SHOULD_SAVE_CARD)) {
              boolean storeCard = data.getBoolean(PayuConstantsCorePG.SHOULD_SAVE_CARD);
              paymentParams.setStoreCard(storeCard ? 1 : 0);
            }


            String lookupId = data.getString(PayuConstantsCorePG.LOOKUP_ID);
            if (lookupId != null && lookupId.length() > 0) {
              paymentParams.setLookupId(lookupId);
            }
            paymentMode = PayuConstants.CC;
            break;

        case PayuConstantsCorePG.SODEXO:
          paymentParams.setBankCode(PayuConstants.SODEXO);
          paymentParams.setCardNumber(data.getString(PayuConstantsCorePG.CARD_NUMBER));
          paymentParams.setNameOnCard(data.getString(PayuConstantsCorePG.NAME_ON_CARD));
          paymentParams.setExpiryMonth(data.getString(PayuConstantsCorePG.EXPIRY_MONTH));
          paymentParams.setExpiryYear(data.getString(PayuConstantsCorePG.EXPIRY_YEAR));
          paymentParams.setCvv(data.getString(PayuConstantsCorePG.CVV));
          paymentMode = PayuConstants.SODEXO;
          break;

        case PayuConstantsCorePG.NETBANKING:
          paymentParams.setBankCode(data.getString(PayuConstantsCorePG.BANKCODE));
          paymentMode = PayuConstants.NB;
          break;

        case PayuConstantsCorePG.UPI_CONSTANT:
          if (data.getString(PayuConstantsCorePG.BANKCODE) != null && data.getString(PayuConstantsCorePG.BANKCODE).equalsIgnoreCase(PayuConstantsCorePG.TEZ)) {
            paymentMode = PayuConstants.TEZ;
          } else
          {
            paymentParams.setVpa(data.getString(PayuConstantsCorePG.VPA));
            paymentMode = PayuConstants.UPI;
          }
          break;

        case PayuConstantsCorePG.EMI:
          paymentParams.setCardNumber(data.getString(PayuConstantsCorePG.CARD_NUMBER));
          paymentParams.setExpiryMonth(data.getString(PayuConstantsCorePG.EXPIRY_MONTH));
          paymentParams.setExpiryYear(data.getString(PayuConstantsCorePG.EXPIRY_YEAR));
          paymentParams.setCvv(data.getString(PayuConstantsCorePG.CVV));
          paymentParams.setBankCode(data.getString(PayuConstantsCorePG.BANKCODE));
          paymentMode = PayuConstants.EMI;
          break;

        case PayuConstantsCorePG.NO_COST_EMI:
          paymentParams.setCardNumber(data.getString(PayuConstantsCorePG.CARD_NUMBER));
          paymentParams.setNameOnCard(data.getString(PayuConstantsCorePG.NAME_ON_CARD));
          paymentParams.setExpiryMonth(data.getString(PayuConstantsCorePG.EXPIRY_MONTH));
          paymentParams.setExpiryYear(data.getString(PayuConstantsCorePG.EXPIRY_YEAR));
          paymentParams.setCvv(data.getString(PayuConstantsCorePG.CVV));
          paymentParams.setBankCode(data.getString(PayuConstantsCorePG.BANKCODE));
          paymentParams.setSubventionAmount(data.getString(PayuConstantsCorePG.SI));
          paymentMode = PayuConstants.EMI;
          break;
        case PayuConstantsCorePG.CASH_CARD:
          paymentParams.setBankCode(data.getString(PayuConstantsCorePG.BANKCODE));
          paymentMode = PayuConstants.CASH;
          break;

        default:
          errorCallback.invoke(new HashMap<String, String>() {{
            put(PayuConstantsCorePG.ERROR, PayuConstantsCorePG.UNSUPPORTED_PAYMENT_METHOD);
          }});
          return;
      }
    proceedPayment(paymentParams, data, paymentMode);
  }

  private void proceedPayment(PaymentParams paymentParams, ReadableMap payUData, String paymentMode) {
    PaymentPostParams paymentPostParams = new PaymentPostParams(paymentParams, paymentMode);
    PostData postData = paymentPostParams.getPaymentPostParams();
    if (postData.getCode() == PayuErrors.NO_ERROR && postData.getStatus().equals(PayuConstants.SUCCESS)) {
      Map<String, String> arrayList = new HashMap<String, String>();
      try{
      arrayList.put(PayuConstantsCorePG.URL, (Integer.parseInt(payUData.getString(PayuConstantsCorePG.ENVIRONMENT))==0) ? PayuConstants.PRODUCTION_PAYMENT_URL : PayuConstants.TEST_PAYMENT_URL);
      }catch(NumberFormatException e){
        errorCallback.invoke(e.getMessage());
      }
      arrayList.put(PayuConstantsCorePG.DATA, postData.getResult());
      successCallback.invoke(new JSONObject(arrayList).toString());
    } else {
      System.out.print(postData.getResult());
      errorCallback.invoke(postData.getResult());
    }
  }

  @ReactMethod
  public void fetchPaymentOptions(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.HASH,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService webService = new MerchantWebService();
    webService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    webService.setCommand(PayuConstants.PAYMENT_RELATED_DETAILS_FOR_MOBILE_SDK);
    webService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    webService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(webService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetPaymentRelatedDetailsTask getPaymentRelatedDetailsTask = new GetPaymentRelatedDetailsTask(new PaymentRelatedDetailsListener() {
        @Override
        public void onPaymentRelatedDetailsResponse(PayuResponse payuResponse) {
          try {

            promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
          } catch (JSONException e) {
            promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
          }
        }
      });
      getPaymentRelatedDetailsTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }
  private String addAnalytics(){
    JSONArray jsonArray = new JSONArray();
    JSONObject jsonObject = new JSONObject();
    try {
      String NAME_KEY = PayuConstantsCorePG.NAME;
      String PLATFORM_KEY = PayuConstantsCorePG.PLATFORM;
      String PLATFORM_VALUE = PayuConstantsCorePG.ANDROID;

      jsonObject.put(NAME_KEY, PayuConstantsCorePG.REACT_CORE);
      jsonObject.put(PLATFORM_KEY, PLATFORM_VALUE);
      jsonObject.put(VERSION_KEY, PayuConstantsCorePG.VERSION_NUMBER);
      jsonArray.put(jsonObject);
    }catch (JSONException e){
    }
    return jsonArray.toString();
  }


  @ReactMethod
  public void vas(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService webService = new MerchantWebService();
    webService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    webService.setCommand(PayuConstants.VAS_FOR_MOBILE_SDK);
    webService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1) == null ? PayuConstants.DEFAULT : jsonObject.getString(PayuConstantsCorePG.VAR1));
    webService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(webService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      ValueAddedServiceTask payuTask = new ValueAddedServiceTask(new ValueAddedServiceApiListener() {
        @Override
        public void onValueAddedServiceApiResponse(PayuResponse payuResponse) {
          try {
            promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
          } catch (JSONException e) {
            promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
          }
        }
      });
      payuTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getEMIDetails(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService webService = new MerchantWebService();
    webService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    webService.setCommand(PayuConstants.API_GET_EMI_AMOUNT_ACCORDING_INTEREST);
    webService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    webService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(webService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetEmiAmountAccordingToInterestTask payuTask = new GetEmiAmountAccordingToInterestTask(new GetEmiAmountAccordingToInterestApiListener() {
        @Override
        public void onGetEmiAmountAccordingToInterestApiResponse(PayuResponse payuResponse) {
          try {
            promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
          } catch (JSONException e) {
            promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
          }
        }
      });
      payuTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getCheckoutDetails(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService webService = new MerchantWebService();
    webService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    webService.setCommand(PayuConstants.GET_CHECKOUT_DETAILS);
    webService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    webService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(webService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());

      GetCheckoutDetailsTask getCheckoutDetailsTask = new GetCheckoutDetailsTask(new CheckoutDetailsListener() {
        @Override
        public void onCheckoutDetailsResponse(PayuResponse payuResponse) {
          try {
            promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
          } catch (JSONException e) {
            promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
          }
        }
      });
      getCheckoutDetailsTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getTransactionInfo(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.VAR2,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService webService = new MerchantWebService();
    webService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    webService.setCommand(PayuConstants.GET_TRANSACTION_INFO);
    webService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    webService.setVar2(jsonObject.getString(PayuConstantsCorePG.VAR2));
    webService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(webService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());

      GetTransactionInfoTask getTransactionInfoTask = new GetTransactionInfoTask(new GetTransactionInfoApiListener() {
        @Override
        public void onGetTransactionApiListener(PayuResponse payuResponse) {
          try {
            promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
          } catch (JSONException e) {
            promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
          }
        }
      });
      getTransactionInfoTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void checkIsDomestic(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }
    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.CHECK_IS_DOMESTIC);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1) == null ? PayuConstants.DEFAULT : jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetCardInformationTask getCardInformationTask = new GetCardInformationTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      getCardInformationTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getBinInfo(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.VAR2,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }
    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.GET_BIN_INFO);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1) == null ? PayuConstants.DEFAULT : jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setVar2(jsonObject.getString(PayuConstantsCorePG.VAR2));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      BinInfoTask binInfoTask = new BinInfoTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      binInfoTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void verifyPayment(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.VERIFY_PAYMENT);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
      }
      payuConfig.setData(postData.getResult());
      VerifyPaymentTask verifyPaymentTask = new VerifyPaymentTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      verifyPaymentTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void lookupAPI(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }
    PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
      }
    payuConfig.setData(jsonObject.getString(PayuConstantsCorePG.VAR1));
    LookupTask lookupTask = new LookupTask(payuResponse -> {
      try {
        promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
      } catch (JSONException e) {
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
      }
    });
    lookupTask.execute(payuConfig);
  }

  @ReactMethod
  public void checkBalance(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.CHECK_BALANCE);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();


    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
      }

      payuConfig.setData(postData.getResult());
      CheckBalanceTask checkBalanceTask = new CheckBalanceTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      checkBalanceTask.execute(payuConfig);
    }else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getConfig(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.SDK_CONFIGURATION);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetConfigTask getConfigTask = new GetConfigTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      getConfigTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void eligibleBinsForEmi(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.ELIGIBLE_BINS_FOR_EMI);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      EligibleBinsForEMITask eligibleBinsForEMITask = new EligibleBinsForEMITask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      eligibleBinsForEMITask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void deleteTokenisedCard(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.VAR2,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.DELETE_TOKENISED_USER_CARD);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setVar2(jsonObject.getString(PayuConstantsCorePG.VAR2));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      DeleteTokenisedCardTask deleteTokenisedCardTask = new DeleteTokenisedCardTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      deleteTokenisedCardTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getTokenisedCard(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.GET_TOKENISED_USER_CARD);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetTokenisedCardTask getTokenisedCardTask = new GetTokenisedCardTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      getTokenisedCardTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getTokenisedCardDetails(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.VAR2,PayuConstantsCorePG.VAR3,PayuConstantsCorePG.VAR4,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.GET_TOKENISED_CARD_DETAILS);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setVar2(jsonObject.getString(PayuConstantsCorePG.VAR2));
    merchantWebService.setVar3(jsonObject.getString(PayuConstantsCorePG.VAR3));
    merchantWebService.setVar4(jsonObject.getString(PayuConstantsCorePG.VAR4));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetTokenisedCardDetailsTask getTokenisedCardDetailsTask = new GetTokenisedCardDetailsTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      getTokenisedCardDetailsTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void getIbiboCodes(ReadableMap jsonObject, Promise promise) {
    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.VAR1,PayuConstantsCorePG.HASH,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

    MerchantWebService merchantWebService = new MerchantWebService();
    merchantWebService.setKey(jsonObject.getString(PayuConstantsCorePG.KEY));
    merchantWebService.setCommand(PayuConstants.GET_MERCHANT_IBIBO_CODES);
    merchantWebService.setVar1(jsonObject.getString(PayuConstantsCorePG.VAR1));
    merchantWebService.setHash(jsonObject.getString(PayuConstantsCorePG.HASH));

    PostData postData = new MerchantWebServicePostParams(merchantWebService).getMerchantWebServicePostParams();

    if (postData.getCode() == PayuErrors.NO_ERROR) {
      PayuConfig payuConfig = new PayuConfig();
      try{
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));
      }catch(NumberFormatException e){
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
      payuConfig.setData(postData.getResult());
      GetIbiboCodesTask getIbiboCodesTask = new GetIbiboCodesTask(payuResponse -> {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      });
      getIbiboCodesTask.execute(payuConfig);
    }
    else{
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, postData.getResult()));
    }
  }

  @ReactMethod
  public void fetchIFSCDetails(ReadableMap jsonObject, Promise promise) {
    //TODO need to implement with v2 hash
     promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, PayuConstantsCorePG.NOT_IMPLEMENTED));
  }
 

  @ReactMethod
  public void hashGenerated(final ReadableMap map) {
    HashCompletionListener hashCompletionListener = listenermap.get(commond);

    HashMap<String, String> hashMap = new HashMap<>();
      Iterator<Map.Entry<String, Object>> i = map.getEntryIterator();
      while(i.hasNext()){
        Map.Entry <String,Object> mapEntry = i.next();
        hashMap.put(mapEntry.getKey(),String.valueOf(mapEntry.getValue()));
      }

    hashCompletionListener.onSignatureGenerated(hashMap);
  }

  @ReactMethod
  public void fetchOfferDetails(ReadableMap jsonObject,Promise promise){

    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.AMOUNT,PayuConstantsCorePG.USER_TOKEN,PayuConstantsCorePG.COMMAND,PayuConstantsCorePG.ENVIRONMENT));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

     String amount = jsonObject.getString(PayuConstantsCorePG.AMOUNT);
     String userToken = jsonObject.getString(PayuConstantsCorePG.USER_TOKEN);
     commond = jsonObject.getString(PayuConstantsCorePG.COMMAND);
     String merchantkey = jsonObject.getString(PayuConstantsCorePG.KEY);
     ReadableMap skuDetailsMap = jsonObject.getMap(PayuConstantsCorePG.SKU_OFFER_DETAILS);

    try {
      JSONObject skuDetails = utils.convertMapToJson(skuDetailsMap);
      FetchOfferApiRequest fetchOfferApiRequest = new FetchOfferApiRequest.Builder(Double.parseDouble(amount),userToken).setSkuDetails(skuDetails.toString()).build();
      PayuConfig payuConfig = new PayuConfig();
      payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));

    V2ApiTask v2ApiTask = new V2ApiTask(merchantkey,payuConfig);
    v2ApiTask.getOffers(fetchOfferApiRequest, this, new FetchOfferDetailsListener() {
      @Override
      public void onFetchOfferDetailsResponse(PayuResponse payuResponse) {
        try {
          promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
        } catch (JSONException e) {
          promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        }
      }
    });
    } catch (NumberFormatException | JSONException e) {
        promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
        return;
      }
  }

  @ReactMethod
  public void validateOfferDetails(ReadableMap jsonObject, Promise promise) {

    List<String> missingKeys = checkMissingKeys(jsonObject, ImmutableList.of(PayuConstantsCorePG.KEY,PayuConstantsCorePG.AMOUNT,PayuConstantsCorePG.USER_DETAIL,PayuConstantsCorePG.COMMAND,PayuConstantsCorePG.ENVIRONMENT,PayuConstantsCorePG.PAYMENT_DETAIL));
    if (missingKeys.size() > 0) {
      promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.MISSING_KEYS_STRING, missingKeys));
      return;
    }

      PayuConfig payuConfig = new PayuConfig();
    try {
        payuConfig.setEnvironment(Integer.parseInt(jsonObject.getString(PayuConstantsCorePG.ENVIRONMENT)));

          commond = jsonObject.getString(PayuConstantsCorePG.COMMAND);
          String amount = jsonObject.getString(PayuConstantsCorePG.AMOUNT);
          ReadableMap skuDetailsMap = jsonObject.getMap(PayuConstantsCorePG.SKU_OFFER_DETAILS);
          JSONObject skuDetails = utils.convertMapToJson(skuDetailsMap);
          boolean autoApply = jsonObject.getBoolean(PayuConstantsCorePG.AUTO_APPLY);

          String key = jsonObject.getString(PayuConstantsCorePG.KEY);
          ReadableArray offerKeyArray = jsonObject.getArray(PayuConstantsCorePG.OFFER_KEY);
          JSONArray offerKey = new JSONArray();

          if (offerKeyArray != null) {
            for (int keyValue = 0; keyValue < offerKeyArray.size(); keyValue++) {
              offerKey.put(offerKeyArray.getString(keyValue));
            }
          }



          ReadableMap paymentDetailsMap = jsonObject.getMap(PayuConstantsCorePG.PAYMENT_DETAIL);
          String cardNumber = paymentDetailsMap.getString(PayuConstantsCorePG.CARD_NUMBER);
          String paymentCode = paymentDetailsMap.getString(PayuConstantsCorePG.PAYMENT_CODE);
          String cardHash = paymentDetailsMap.getString(PayuConstantsCorePG.CARD_HASH);
          String category = paymentDetailsMap.getString(PayuConstantsCorePG.CATEGORY);
          String cardMask = paymentDetailsMap.getString(PayuConstantsCorePG.CARD_MASK);
          String vpa = paymentDetailsMap.getString(PayuConstantsCorePG.VPA);
          String cardToken = paymentDetailsMap.getString(PayuConstantsCorePG.CARD_TOKEN);

          ReadableMap userDetailsMap = jsonObject.getMap(PayuConstantsCorePG.USER_DETAIL);
          String email = userDetailsMap.getString(PayuConstantsCorePG.EMAIL);
          String phoneNo = userDetailsMap.getString(PayuConstantsCorePG.PHONE_NO);
          String userToken = userDetailsMap.getString(PayuConstantsCorePG.USER_TOKEN);
          Integer cardTokenType;
          if(jsonObject.hasKey(PayuConstantsCorePG.CARD_TOKEN_TYPE)) {
            cardTokenType = jsonObject.getInt(PayuConstantsCorePG.CARD_TOKEN_TYPE);
          }
          else{
            cardTokenType = 1;
          }

          PaymentDetailsForOffer paymentDetails = new PaymentDetailsForOffer.Builder(category, paymentCode).setCardNumber(cardNumber).setCardHash(cardHash).setCardMask(cardMask).setVpa(vpa).setCardToken(cardToken).setCardTokenType(cardTokenType).build();
          UserDetailsForOffer userDetails = new UserDetailsForOffer.Builder(userToken).setEmail(email).setPhoneNo(phoneNo).build();
          ValidateOfferRequest validateOfferApiRequest = new ValidateOfferRequest.Builder(amount).setOfferKey(offerKey).setPaymentDetails(paymentDetails).setuserDetails(userDetails).setSkuDetails(skuDetails.toString()).setAutoApply(autoApply).build();

          V2ApiTask v2ApiTask = new V2ApiTask(key,payuConfig);
          v2ApiTask.validateOffers(validateOfferApiRequest, this, new ValidateOfferApiListener() {
            @Override
            public void onValiDateOfferResponse(PayuResponse payuResponse) {
              try {
                if (payuResponse.getRawResponse() != null) {
                  promise.resolve(utils.convertJsonToMap(payuResponse.getRawResponse()));
                }
              } catch (JSONException e) {
                promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
              }
            }
          });
  } catch (NumberFormatException | JSONException e) {
    promise.reject(PayuConstantsCorePG.ERROR, String.format(PayuConstantsCorePG.ERROR_STRING, e));
    return;
  }
  }

    @Override
    public void generateSignature(
      HashMap<String, String> hashMap,
      HashCompletionListener hashCompletionListener
    ) {
      listenermap.put(commond,hashCompletionListener);

      WritableMap map = new WritableNativeMap();
      map.putString(PayuConstantsCorePG.HASH_NAME, commond);
      map.putString(PayuConstantsCorePG.HASH_STRING, hashMap.get(PayuConstantsCorePG.SIGNING_STRING));
      sendResultBack(PayuConstantsCorePG.GENERATE_HASH,map);
  }

  private void sendResultBack(String eventName, WritableMap params) {
    this.reactContext
      .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
      .emit(eventName, params);
  }

  private List<String> checkMissingKeys(ReadableMap map, List<String> keys) {
    List<String> missingKeys = new ArrayList<String>();
    for (String key : keys) {
      if (!map.hasKey(key)) {
        missingKeys.add(key);
      }
    }
    return missingKeys;
  }

}
