#import "PayUBizSdk.h"
#import <React/RCTUtils.h>
#import <PayUCheckoutProKit/PayUCheckoutProKit.h>
#import <PayUCheckoutProBaseKit/PayUCheckoutProBaseKit.h>

@interface PayUBizSdk() <PayUCheckoutProDelegate>

typedef void (^hashCompletionCallback)(NSDictionary<NSString *,NSString *> * _Nonnull);

@property (nonatomic, strong) NSMutableDictionary *hashCallbacks;

@end

@implementation PayUBizSdk
{
    bool hasListeners;
}
NSString *const OnPaymentSuccess = @"onPaymentSuccess";
NSString *const OnPaymentFailure = @"onPaymentFailure";
NSString *const OnPaymentCancel = @"onPaymentCancel";
NSString *const OnError = @"onError";
NSString *const GenerateHash = @"generateHash";

RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(hashGenerated:(NSDictionary *)hashDict) {
    @try {
        dispatch_async(dispatch_get_main_queue(), ^{
            hashCompletionCallback callback = [self.hashCallbacks objectForKey:hashDict.allKeys.firstObject];
            if (callback && hashDict) {
                callback(hashDict);
                [self.hashCallbacks removeObjectForKey:hashDict.allKeys.firstObject];
            }
        });
    } @catch (NSException *exception) {
        [self onError:[PayUBizSdk convertExceptionToError:exception]];
    }
}

RCT_EXPORT_METHOD(openCheckoutScreen:(NSDictionary *)params) {
    @try {
        self.hashCallbacks = [[NSMutableDictionary alloc] init];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            UIViewController *rootVc = RCTPresentedViewController();
            [PayUCheckoutPro openOn:rootVc params:params delegate:self];
        });
    }
    @catch (NSException * exception) {
        [self onError:[PayUBizSdk convertExceptionToError:exception]];
    }
}

#pragma mark - PayUCheckoutProDelegate Methods
- (void)generateHashFor:(NSDictionary<NSString *,NSString *> * _Nonnull)param onCompletion:(void (^ _Nonnull)(NSDictionary<NSString *,NSString *> * _Nonnull))onCompletion {
    [self.hashCallbacks setObject:onCompletion forKey:param[HashConstant.hashName]];
    [self sendEventWithName:GenerateHash body:param];
}

- (void)onError:(NSError * _Nullable)error {
    NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
                               error.localizedDescription, @"errorMsg",
                               //                               error.code, @"errorCode",
                               nil];
    [self sendEventWithName:OnError body:errorDict];
}

- (void)onPaymentCancelWithIsTxnInitiated:(BOOL)isTxnInitiated {
    NSDictionary *response = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithBool:isTxnInitiated], @"isTxnInitiated",
                              nil];
    [self sendEventWithName:OnPaymentCancel body:response];
}

- (void)onPaymentFailureWithResponse:(id _Nullable)response {
    [self sendEventWithName:OnPaymentFailure body:response];
}

- (void)onPaymentSuccessWithResponse:(id _Nullable)response {
    [self sendEventWithName:OnPaymentSuccess body:response];
}

#pragma mark - RCTEventEmitter methods

-(NSArray<NSString *> *)supportedEvents {
    return @[OnPaymentSuccess, OnPaymentFailure, OnPaymentCancel, OnError, GenerateHash];
}

// Will be called when this module's first listener is added.
-(void)startObserving {
    hasListeners = YES;
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
    hasListeners = NO;
}

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

+(NSError *)convertExceptionToError:(NSException *)exception{
    NSMutableDictionary * info = [NSMutableDictionary dictionary];
    [info setValue:exception.name forKey:@"ExceptionName"];
    [info setValue:exception.reason forKey:@"ExceptionReason"];
    [info setValue:exception.callStackReturnAddresses forKey:@"ExceptionCallStackReturnAddresses"];
    [info setValue:exception.callStackSymbols forKey:@"ExceptionCallStackSymbols"];
    [info setValue:exception.userInfo forKey:@"ExceptionUserInfo"];
    
    NSError *error = [[NSError alloc] initWithDomain:@"com.payu.bizReactNativeWrapper" code:100 userInfo:info];
    return error;
}

@end
