#import "PayUSdk.h"

#import <PayUBizCoreKit/PayUBizCoreKit.h>
#import <PayUParamsKit/PayUParamsKit.h>

#import <React/RCTUtils.h>
#import <CommonCrypto/CommonDigest.h>

#import "NSObject+BWJSONMatcher.h"

#define __TAG__ [NSString stringWithFormat:@"%@.%@#%d", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__]

const NSErrorDomain errorDomain = @"PayUDSdkError";

@interface WebVCDelegate : NSObject
-(instancetype)initWithSuccessCallback:(RCTResponseSenderBlock)successCallback
                         errorCallback: (RCTResponseErrorBlock)errorCallback;
@end

@interface PayUSdk()

@property (nonatomic, strong) NSMutableDictionary *hashCallbacks;

@end

@implementation PayUSdk {
    WebVCDelegate* _delegate;
    bool hasListeners;
}

NSString *const GenerateHash = @"generateHash";

RCT_EXPORT_MODULE(PayUSdk)

#pragma mark - RCTEventEmitter Methods

-(NSArray<NSString *> *)supportedEvents {
    return @[GenerateHash];
}

-(void)startObserving {
    hasListeners = YES;
}

-(void)stopObserving {
    hasListeners = NO;
}

- (void)sendEventWithName:(NSString *)name body:(id)body {
    if (hasListeners) {
        [super sendEventWithName:name body:body];
    }
}

#pragma mark - Internal METHODS

-(NSDictionary*)createPaymentRequest:(NSDictionary*)jsonObject error:(NSError**)error {
    
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    
    NSString* paymentType = [jsonObject objectForKey:@"paymentType"];
    
    NSLog(@"paymentType%@", paymentType);
    NSError* hashError;
    paymentParamForPassing.hashes.paymentHash = [jsonObject objectForKey:@"hash"];
    if (hashError) {
        *error = hashError;
        return nil;
    }
    
    
    PayUCreateRequest* createRequest = [PayUCreateRequest new];
    
    __block NSMutableURLRequest *blockRequest = nil;
    __block NSString *blockPostParam = nil;
    __block NSError *blockError = nil;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    __weak PayUSdk *weakSelf = self;
    [createRequest createRequestWithPaymentParam:paymentParamForPassing forPaymentType:paymentType withCompletionBlock:^(NSMutableURLRequest *request, NSString *postParam, NSString *requestError) {
        NSData* data = request.HTTPBody;
        NSString* bodyString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        postParam = [weakSelf addAnalyticsParams: postParam];
        bodyString = [weakSelf addAnalyticsParams: bodyString];
        request.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
        if (requestError) {
            blockError = [NSError errorWithDomain:errorDomain code:100 userInfo:@{NSLocalizedDescriptionKey:requestError}];
        } else  {
            blockRequest = request;
            blockPostParam = postParam;
        }
        
        dispatch_semaphore_signal(sem);
    }];
    
    if (blockError && ( !blockRequest || !blockPostParam ) ) {
        *error = blockError;
        return nil;
    }
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    NSDictionary* result = @{@"request": blockRequest, @"postParams": blockPostParam};
    return result;
}

-(NSString*)addAnalyticsParams:(NSString*)param {
    NSArray *arr = [param componentsSeparatedByString:@"&"];
    NSMutableDictionary *paramDict = [[NSMutableDictionary alloc] init];
    for (NSString *str in arr) {
        NSArray *keyValue = [str componentsSeparatedByString:@"="];
        if(keyValue.count > 1) {
            paramDict[keyValue[0]] = keyValue[1];
        }
    }
    if ([[paramDict allKeys] containsObject:@"sdk_platform"]) {
        paramDict[@"sdk_platform"] = [self addAnalyticsStringValue:paramDict[@"sdk_platform"]];
    } else {
        paramDict[@"sdk_platform"] = [NSString stringWithFormat:@"[%@]",[self getAnalyticsStringValue]];
    }
    
    NSMutableArray *paramArray = [[NSMutableArray alloc] init];
    for (NSString* key in paramDict.allKeys) {
        NSString *value = (NSString *)[paramDict objectForKey:key];
        [paramArray addObject:[NSString stringWithFormat:@"%@=%@",key,value]];
    }
    
    NSString *updatedPostParams = [paramArray componentsJoinedByString:@"&"];
    return updatedPostParams;
}

- (NSString*)addAnalyticsStringValue:(NSString*)string {
    
    string = [string stringByReplacingOccurrencesOfString:@"[" withString:@""];
    string = [string stringByReplacingOccurrencesOfString:@"]" withString:@""];
    NSMutableArray *strArr = [[string componentsSeparatedByString:@","] mutableCopy];
    [strArr addObject:[self getAnalyticsStringValue]];
    
    return [NSString stringWithFormat:@"[%@]",[strArr componentsJoinedByString:@","]];
}

- (NSString*)getAnalyticsStringValue {
    NSString *analyticsString;
    NSString *version = [self reactVersion];
    NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"iOS", @"platform", @"react-core", @"name", version,@"version", nil];
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
                                                       options:0
                                                         error:&error];
    
    if (! jsonData) {
        NSLog(@"Got an error: %@", error);
        return @"";
    } else {
        analyticsString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    
    analyticsString = [NSString stringWithFormat:@"%@", analyticsString];
    
    return analyticsString;
}

-(NSString *)reactVersion {
    @try {
        NSBundle* bundle = [self getVersionPlistBundle];
        NSString *path = [bundle pathForResource: @"PayUSdkInfo" ofType: @"plist"];
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: path];
        NSString *version = [dict objectForKey: @"SDKVersion"];
        return version;
    }
    @catch(NSException *e) {
        return @"";
    }
}

-(NSBundle *)getVersionPlistBundle {
    @try {
        NSBundle* bundle = [[NSBundle alloc] initWithURL: [NSBundle URLForResource:@"PayUResource" withExtension:@"bundle" subdirectory:nil inBundleWithURL:[[NSBundle bundleForClass:[self class]] bundleURL]]];
        return bundle;
    } @catch (NSException *exception) {
        return [NSBundle mainBundle];
    }
}

- (NSString*)getStringOrBlank:(NSDictionary*)dict forKey:(NSString*)key {
    if ([dict objectForKey:key]) {
        return [dict objectForKey:key];
    }
    return @"";
}

- (NSString*)getEnvironment:(NSDictionary *)jsonObject {
    if ([@"0" caseInsensitiveCompare:[jsonObject objectForKey:@"environment"]] == NSOrderedSame) {
        return ENVIRONMENT_PRODUCTION;
    } else {
        return ENVIRONMENT_TEST;
    }
}

- (PayUModelPaymentParams*)createPaymentParams:(NSDictionary*)jsonObject {
    PayUModelPaymentParams *paymentParamForPassing = [PayUModelPaymentParams fromJSONObject:jsonObject];
    
    if ([jsonObject objectForKey:@"siParams"] && paymentParamForPassing.siParams == NULL) {
        PayUSIParams* siParams = [PayUSIParams fromJSONObject:[jsonObject objectForKey:@"siParams"]];
        paymentParamForPassing.siParams = siParams;
    }
    
    if ([jsonObject objectForKey:@"beneficiaryParams"] && paymentParamForPassing.beneficiaryParams == NULL) {
        PayUBeneficiaryParams* beneficiaryParams = [PayUBeneficiaryParams fromJSONObject:[jsonObject objectForKey:@"beneficiaryParams"]];
        paymentParamForPassing.beneficiaryParams = beneficiaryParams;
    }
    paymentParamForPassing.phoneNumber = [jsonObject objectForKey:@"phone"];
    paymentParamForPassing.environment = [self getEnvironment:jsonObject];
    paymentParamForPassing.offerParams = [PayUModelOfferParams new];
    NSArray<NSString*>* offerKeys = [jsonObject valueForKey:@"offerKey"];
    if (offerKeys && offerKeys.count > 0) {
        paymentParamForPassing.offerParams.offerKeys = [jsonObject valueForKey:@"offerKey"];
    }
    NSDictionary *JSONDic=[jsonObject valueForKey:@"skuOfferDetails"];
    if (JSONDic && [JSONDic isKindOfClass:[NSDictionary class]]) {
        paymentParamForPassing.offerParams.skuOfferDetails = [[jsonObject valueForKey:@"skuOfferDetails"] toJSONString];
    }
    
    paymentParamForPassing.offerParams.userToken = [jsonObject valueForKey:@"userToken"];

    
    return paymentParamForPassing;
}

-(void) saveCallbackAndSendEventToReactToGenerateHash:(NSDictionary *)parameters completionBlock: (completionBlock) completionBlock {
    if (!self.hashCallbacks) {
        self.hashCallbacks = [NSMutableDictionary new];
    }
    [self.hashCallbacks setObject:completionBlock forKey:[parameters objectForKey:@"hashName"]];
    [self sendEventWithName:GenerateHash body:parameters];
}

#pragma mark - RCT EXPORT METHODS

RCT_EXPORT_METHOD(hashGenerated:(NSDictionary *)hashDict) {
    completionBlock callback = [self.hashCallbacks objectForKey:hashDict.allKeys.firstObject];
    @try {
        dispatch_async(dispatch_get_main_queue(), ^{
            callback(hashDict);
            [self.hashCallbacks removeObjectForKey:hashDict.allKeys.firstObject];
        });
    } @catch (NSException *exception) {
        NSLog(@"Unable to send callback to native %@", exception.reason);
    }
}

RCT_EXPORT_METHOD(createPaymentRequest:(NSDictionary *)jsonObject resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    NSError* error;
    NSDictionary* requestData = [self createPaymentRequest:jsonObject error:&error];
    if (error) {
        NSMutableDictionary *erroDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:error,@"error", nil];
        resolve(erroDictionary.toJSONObject);
    } else {
        resolve(requestData.toJSONData);
    }
}

RCT_EXPORT_METHOD(makePayment:(NSDictionary *)jsonObject
                  successCallback: (RCTResponseSenderBlock)successCallback
                  errorCallback: (RCTResponseErrorBlock)errorCallback) {
    _delegate = nil;
    NSError* error;
    NSLog(@"jsonObject%@", jsonObject);
    NSMutableDictionary* json = [jsonObject mutableCopy];
    if ([json[@"paymentType"] compare: @"Twid"  options:NSCaseInsensitiveSearch] == NSOrderedSame) {
        json[@"paymentType"] = @"Cash Card";
    }
    NSDictionary* requestData = [self createPaymentRequest:json error:&error];
    
    if (error) {
        errorCallback(error);
    } else {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSURLRequest* request = (NSURLRequest*) requestData[@"request"];
            NSString* data = (NSString*) requestData[@"postParams"];
            NSLog(@"data%@", data);
            NSDictionary* dict = @{@"data":data, @"url": request.URL.absoluteString};
            successCallback(@[ dict.toJSONString ]);
            
        });
        
    }
}

RCT_EXPORT_METHOD(fetchPaymentOptions:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.userCredentials = [jsonObject objectForKey:@"var1"];
    paymentParamForPassing.subventionEligibility = [jsonObject objectForKey:@"var2"];
    paymentParamForPassing.hashes.paymentRelatedDetailsHash = [jsonObject objectForKey:@"hash"];

    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getPayUPaymentRelatedDetailForMobileSDK:paymentParamForPassing withCompletionBlock:^(PayUModelPaymentRelatedDetail *paymentRelatedDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(vas:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.VASForMobileSDKHash = [jsonObject objectForKey:@"hash"];
    
    NSString* bankCode = [self getStringOrBlank:jsonObject forKey:@"bankCode"];
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse callVASForMobileSDKWithPaymentParam:paymentParamForPassing withCompletionBlock:^(PayUModelVAS *vas, NSString *errorMessage, id extraParam) {
        if (bankCode && [bankCode length] != 0) {
            [webServiceResponse getVASStatusForCardBinOrBankCode:bankCode withCompletionBlock:^(id ResponseMessage, NSString *errorMessage, id extraParam) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    resolve(extraParam[@"JsonResponse"]);
                });
            }];
        }
        else{
            resolve(extraParam[@"JsonResponse"]);
        }
    }];
}

RCT_EXPORT_METHOD(getEMIDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.EMIDetailsHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getEMIAmountAccordingToInterest:paymentParamForPassing withCompletionBlock:^(NSDictionary *dictEMIDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getCheckoutDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    NSError* error = nil;
    NSData *objectData = [[jsonObject objectForKey:@"var1"] dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                                         options:NSJSONReadingMutableContainers
                                                           error:&error];
    if (error) {
        reject(__TAG__, error.localizedDescription, nil);
        return;
    }
    
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    // Use Cases
    NSDictionary *useCases = [json objectForKey:@"useCase"];
    paymentParamForPassing.getExtendedPaymentDetails = [useCases objectForKey:@"getExtendedPaymentDetails"];
    paymentParamForPassing.checkTaxSpecification = [useCases objectForKey:@"getTaxSpecification"];
    paymentParamForPassing.checkDownStatus = [useCases objectForKey:@"checkDownStatus"];
    paymentParamForPassing.getPgIdForEachOption = [useCases objectForKey:@"getPgIdForEachOption"];
    paymentParamForPassing.checkCustomerEligibility = [useCases objectForKey:@"checkCustomerEligibility"];
    paymentParamForPassing.getPaymentDetailsWithExtraFields = [useCases objectForKey:@"getPaymentDetailsWithExtraFields"];
    paymentParamForPassing.getSdkDetails = [useCases objectForKey:@"getSdkDetails"];
    paymentParamForPassing.getMerchantDetails = [useCases objectForKey:@"getMerchantDetails"];
    paymentParamForPassing.checkAdditionalCharges = [useCases objectForKey:@"getAdditionalCharges"];
    // Other Details
    paymentParamForPassing.transactionID = [json objectForKey:@"requestId"];
    paymentParamForPassing.amount = [[json objectForKey:@"transactionDetails"] objectForKey:@"amount"];
    paymentParamForPassing.phoneNumber = [[json objectForKey:@"customerDetails"] objectForKey:@"mobile"];
    // Hash
    paymentParamForPassing.hashes.getCheckoutDetailsHash = [jsonObject objectForKey:@"hash"];

    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getCheckoutDetail:paymentParamForPassing withCompletionBlock:^(PayUModelPaymentRelatedDetail *paymentRelatedDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getTransactionInfo:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.getTransactionInfoHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getTransactionInfo:paymentParamForPassing withCompletionBlock:^(NSArray *arrOfGetTxnInfo, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(checkIsDomestic:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.checkIsDomesticHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse checkIsDomestic:paymentParamForPassing withCompletionBlock:^(PayUModelCheckIsDomestic *checkIsDomestic, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}



RCT_EXPORT_METHOD(lookupAPI:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    NSError *jsonError;
    NSData *objectData = [[jsonObject objectForKey:@"var1"] dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                                         options:NSJSONReadingMutableContainers
                                                           error:&jsonError];
    if (jsonError) {
        reject(__TAG__, jsonError.localizedDescription, nil);
        return;
    }
    
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.merchantAccessKey = [json objectForKey:@"merchantAccessKey"];
    paymentParamForPassing.amount = [[json objectForKey:@"baseAmount"] objectForKey:@"value"];
    paymentParamForPassing.lookupRequestId = [json objectForKey:@"merchantOrderId"];
    paymentParamForPassing.hashes.lookupApiHash = [json objectForKey:@"signature"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse mcpLookup:paymentParamForPassing withCompletionBlock:^(PayUModelMultiCurrencyPayment *mcpInfo, NSString *errorMessage, id extraParam)
     {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(checkBalance:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    NSError *jsonError;
    NSData *objectData = [[jsonObject objectForKey:@"var1"] dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                                         options:NSJSONReadingMutableContainers
                                                           error:&jsonError];
    if (jsonError) {
        reject(__TAG__, jsonError.localizedDescription, nil);
        return;
    }
    
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.sodexoSourceId = [json objectForKey:@"sodexoSourceId"];
    paymentParamForPassing.hashes.checkBalanceApiHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse checkBalance:paymentParamForPassing withCompletionBlock:^(PayUModelSodexoCardDetail *sodexoCardDetail, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getConfig:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.getSDKConfigurationHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getSDKConfiguration:paymentParamForPassing withCompletionBlock:^(NSArray<PayUSDKConfiguration *> *configuration, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(eligibleBinsForEmi:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.eligibleBinsForEMI = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse eligibleBinsForEMI:paymentParamForPassing withCompletionBlock:^(NSArray<PayUModelEMIDetails *> *arrEMIDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(deleteTokenisedCard:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.userCredentials = [jsonObject objectForKey:@"var1"];
    paymentParamForPassing.cardToken = [jsonObject objectForKey:@"var2"];
    paymentParamForPassing.networkToken = [jsonObject objectForKey:@"var3"];
    paymentParamForPassing.issuerToken = [jsonObject objectForKey:@"var4"];
    paymentParamForPassing.hashes.deleteTokenizedStoredCardHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse deleteTokenizedStoredCard:paymentParamForPassing withCompletionBlock:^(NSString *deleteStoredCardStatus, NSString *deleteStoredCardMessage, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getTokenisedCard:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.userCredentials = [jsonObject objectForKey:@"var1"];
    paymentParamForPassing.hashes.getTokenizedStoredCardHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getTokenizedStoredCards:paymentParamForPassing withCompletionBlock:^(NSDictionary *dictStoredCard, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getTokenisedCardDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.userCredentials = [jsonObject objectForKey:@"var1"];
    paymentParamForPassing.cardToken = [jsonObject objectForKey:@"var2"];
    paymentParamForPassing.amount = [jsonObject objectForKey:@"var3"];
    paymentParamForPassing.currency = [jsonObject objectForKey:@"var4"];
    paymentParamForPassing.hashes.getTokenizedPaymentDetailHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getTokenizedPaymentDetails:paymentParamForPassing withCompletionBlock:^(PayUModelTokenizedPaymentDetails *tokenizedPaymentdetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getIbiboCodes:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(@{@"error": @"This API is not available in iOS"});
    });
}

RCT_EXPORT_METHOD(fetchIFSCDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    
    NSString *ifscCode = [jsonObject objectForKey:@"var1"];
    PayUBeneficiaryParams* beneficiaryParams = [[PayUBeneficiaryParams alloc] initWithBeneficiaryName:@""
                                                                             beneficiaryAccountNumber:@""
                                                                                      beneficiaryIFSC:ifscCode
                                                                               beneficiaryAccountType:BeneficiaryAccountTypeSavings
                                                                                      verficationMode:@""];
    paymentParamForPassing.beneficiaryParams = beneficiaryParams;
    
    paymentParamForPassing.beneficiaryParams.beneficiaryIFSC = [jsonObject objectForKey:@"var1"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
  [webServiceResponse fetchIFSCDetails:paymentParamForPassing withCompletionBlock:^(PayUModelIFSCInfo *isfcInfo, NSString *errorMessage, id extraParam) {
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(extraParam[@"JsonResponse"]);
    });
  } completionBlockForHashGeneration:^(NSDictionary *parameters, completionBlock completionBlock) {
    [self saveCallbackAndSendEventToReactToGenerateHash:parameters completionBlock:completionBlock];
  }];
}

RCT_EXPORT_METHOD(fetchOfferDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getAllOfferDetails:paymentParamForPassing completionBlockForHashGeneration:^(NSDictionary *parameters, completionBlock completionBlock) {
        [self saveCallbackAndSendEventToReactToGenerateHash:parameters completionBlock:completionBlock];
    } completionBlockForAPIResponse:^(PayUModelAllOfferDetail *offerDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(validateOfferDetails:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.amount = [jsonObject valueForKey:@"amount"];
    paymentParamForPassing.offerParams.clientId = [jsonObject valueForKey:@"clientId"];
    paymentParamForPassing.paymentId = [jsonObject valueForKey:@"paymentId"];
    paymentParamForPassing.offerParams.platformId = [jsonObject valueForKey:@"platformId"];
    paymentParamForPassing.offerParams.autoApplyOffer = [jsonObject valueForKey:@"autoApplyOffer"];
    NSDictionary *userDetail = [jsonObject valueForKey:@"userDetail"];
    paymentParamForPassing.email = [userDetail valueForKey:@"email"];
    paymentParamForPassing.phoneNumber = [userDetail valueForKey:@"phoneNo"];
    paymentParamForPassing.offerParams.userToken = [userDetail valueForKey:@"userToken"];


    NSDictionary *paymentDetail = [jsonObject valueForKey:@"paymentDetail"];
    paymentParamForPassing.cardNumber = [paymentDetail valueForKey:@"cardNumber"];
    paymentParamForPassing.cardHash = [paymentDetail valueForKey:@"cardHash"];
    paymentParamForPassing.cardMask = [paymentDetail valueForKey:@"cardMask"];
    paymentParamForPassing.category = [paymentDetail valueForKey:@"category"];
    paymentParamForPassing.offerParams.paymentCode = [paymentDetail valueForKey:@"paymentCode"];
    paymentParamForPassing.vpa = [paymentDetail valueForKey:@"vpa"];
    

    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse validateOfferDetails:paymentParamForPassing completionBlockForHashGeneration:^(NSDictionary *parameters, completionBlock completionBlock) {
        [self saveCallbackAndSendEventToReactToGenerateHash:parameters completionBlock:completionBlock];
    } completionBlockForAPIResponse:^(PayUModelOfferDetail *offerDetails, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

RCT_EXPORT_METHOD(getBinInfo:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.hashes.getBinInfoHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse getBinInfo:paymentParamForPassing withCompletionBlock:^(NSArray<PayUModelCheckIsDomestic *> *allBin, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}


RCT_EXPORT_METHOD(verifyPayment:(NSDictionary *)jsonObject
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    PayUModelPaymentParams *paymentParamForPassing = [self createPaymentParams:jsonObject];
    paymentParamForPassing.transactionID = [jsonObject objectForKey:@"txnId"];
    paymentParamForPassing.hashes.verifyTransactionHash = [jsonObject objectForKey:@"hash"];
    
    PayUWebServiceResponse *webServiceResponse = [PayUWebServiceResponse new];
    [webServiceResponse verifyPayment:paymentParamForPassing withCompletionBlock:^(NSDictionary *dictVerifyPayment, NSString *errorMessage, id extraParam) {
        dispatch_async(dispatch_get_main_queue(), ^{
            resolve(extraParam[@"JsonResponse"]);
        });
    }];
}

@end


@implementation WebVCDelegate {
    RCTResponseSenderBlock _successCallback;
    RCTResponseErrorBlock _errorCallback;
}

- (instancetype)initWithSuccessCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseErrorBlock)errorCallback {
    if (self = [super init]) {
        _successCallback = successCallback;
        _errorCallback = errorCallback;
    }
    return self;
}

- (void)PayUConnectionError:(NSDictionary *)notification {
    _errorCallback([NSError errorWithDomain:errorDomain code:51 userInfo:notification]);
}

- (void)PayUFailureResponse:(id)response {
    _errorCallback([NSError errorWithDomain:errorDomain code:52 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Error: %@", response]}]);
}

- (void)PayUFailureResponse:(id)payUResponse FURLResponse:(id)furlResponse {
    //_errorCallback([NSError errorWithDomain:errorDomain code:52 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Error: %@", payUResponse]}]);
}

- (void)PayUSuccessResponse:(id)response {
    //_successCallback(response);
}

- (void)PayUSuccessResponse:(id)payUResponse SURLResponse:(id)surlResponse {
    _successCallback(payUResponse);
}

- (void)PayUTransactionCancel {
    _errorCallback([NSError errorWithDomain:errorDomain code:52 userInfo:@{NSLocalizedDescriptionKey:@"Transaction cancel"}]);
}

@end
