#import "DapiConnectManager.h"
#import <React/RCTConvert.h>
#import <React/RCTUtils.h>
#import <WebKit/WebKit.h>
#import "DPCCrossSDK.h"
#import "DAPIBankConnection+Dictionary.h"
@import DapiSDK;

@interface DapiConnectManager () <DAPIConnectDelegate>

@property (nonatomic, assign) BOOL hasListeners;
@property (nonatomic, assign) BOOL isStarted;
@property (nonatomic, strong) DAPIAutoFlowVC *autoFlow;
@property (nonatomic, strong) DAPIConnectVC *connectVC;

@end

@implementation DapiConnectManager

// MARK: - Native Module Setup
RCT_EXPORT_MODULE();

+ (BOOL)requiresMainQueueSetup {
    return YES;
}

- (NSArray<NSString *> *)supportedEvents {
    return @[
        // connect
        @"EventConnectSuccessful",
        @"EventConnectFailure",
        @"EventDapiUIWillTransfer",
        @"EventConnectDismissed",
        @"EventConnectBankRequest",
        @"EventDapiTransferUIDismissed",
    ];
}

- (void)startObserving {
    self.hasListeners = YES;
}

- (void)stopObserving {
    self.hasListeners = NO;
}


RCT_EXPORT_METHOD(start:(NSString *)appKey
                  clientUserID:(NSString *)clientUserID
                  configurations:(NSDictionary<NSString *, id> *)configs
                  resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    NSString *environment = [configs objectForKey:@"environment"];
    DAPIEnvironment dapiEnvironment = DAPIEnvironmentSandbox;
    if (environment != nil && [environment isEqualToString: @"production"]) {
        dapiEnvironment = DAPIEnvironmentProduction;
    }
    [DPC.sharedInstance startWithAppKey:appKey
                            environment:dapiEnvironment
                           clientUserID:clientUserID
                             completion:^(Dapi * _Nullable dapi , NSError * _Nullable error ) {
        if (dapi) {
            [DPCCrossSDK setNativeConfigurations:configs];
            self.isStarted = YES;
            resolve(nil);
        } else {
            reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
        }

    }];
}

RCT_EXPORT_METHOD(presentConnect:(NSString *)bankID) {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            self.connectVC = [[DAPIConnectVC alloc] initWithBankID:nil];
            self.connectVC.delegate = self;
            [DPCCrossSDK.topViewController presentViewController:self.connectVC
                                                        animated:true
                                                      completion:nil];
        });
    });
}

RCT_EXPORT_METHOD(dismissConnect) {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.connectVC) {
                [self.connectVC dismissViewControllerAnimated:true completion:nil];
            }
        });
    });
}

RCT_EXPORT_METHOD(setClientUserID:(NSString *)clientUserID) {
    Dapi.shared.clientUserID = clientUserID;
}

RCT_EXPORT_METHOD(clientUserID:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    resolve(Dapi.shared.clientUserID);
}

RCT_EXPORT_METHOD(setConfigurations:(NSDictionary<NSString *, id> *)configs) {
    [DPCCrossSDK setNativeConfigurations:configs];
}

RCT_EXPORT_METHOD(configurations:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    resolve([DPCCrossSDK jsConfigurations]);
}

RCT_EXPORT_METHOD(isStarted:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    resolve([NSNumber numberWithBool:self.isStarted]);
}

RCT_EXPORT_METHOD(getConnections:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        NSMutableArray *arrayObjects = [NSMutableArray array];
        dispatch_async(dispatch_get_main_queue(), ^{
            [DPC.sharedInstance.getConnections enumerateObjectsUsingBlock:^(DAPIBankConnection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                [arrayObjects addObject: [obj dicRepresentation]];
            }];

            resolve(arrayObjects);
        });
    });
}

RCT_EXPORT_METHOD(getConnectionParameters:(NSString *)userID
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {

    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    NSDictionary<NSString *, id> *connectionParams = bankConnection.getParameters;
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:connectionParams
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:&error];

    if (!jsonData) {
        reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
    } else {
        NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        resolve(json);
    }
}

RCT_EXPORT_METHOD(createConnection:(NSString *)jsonConnectionParameters resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    NSData *jsonData = [jsonConnectionParameters dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    NSDictionary<NSString *, id> *connectionParams = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&err];

    if (err) {
        reject([NSNumber numberWithInteger:err.code].stringValue, err.dapiErrorMessage, err);
    }

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{

            [DPC.sharedInstance createBankConnectionWithParameters:connectionParams
                                                        completion:^(NSDictionary<NSString *,id> * _Nullable connection, NSError * _Nullable error) {
                if (error != nil) {
                    reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
                } else {
                    resolve(connection);
                }
            }];
        });
    });
}

RCT_EXPORT_METHOD(presentAccountSelection:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            //            [bankConnection presentAccountSelectionWithCompletion:^(DPCAccount * _Nullable account, NSError * _Nullable error) {
            //                if(error) {
            //                    reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
            //                } else {
            //                    resolve(account.accountID);
            //                }
            //            }];
        });
    });
}

RCT_EXPORT_METHOD(getIdentity:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance identityWithBankConnection:bankConnection
                                        completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                     NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(getAccounts:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance bankAccountsWithBankConnection:bankConnection
                                            completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                         NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(getCards:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance bankCardsWithBankConnection:bankConnection
                                         completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                      NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(getTransactionsForAccount:(NSString *)userID
                  accountID:(NSString *)accountID
                  startDate:(NSDate *)startDate
                  endDate:(NSDate *)endDate
                  type:(NSString *)type
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    DAPITransactionType enumType = DAPITransactionTypeDefault;
    if([type isEqualToString:@"enriched"]) {
        enumType = DAPITransactionTypeEnriched;
    } else if([type isEqualToString:@"categorized"]) {
        enumType = DAPITransactionTypeCategorized;
    }

    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance accountTransactionsWithBankConnection:bankConnection
                                                bankAccountID:accountID
                                                         type:enumType
                                                         from:startDate
                                                           to:endDate
                                                   completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(getTransactionsForCard:(NSString *)userID
                  cardID:(NSString *)cardID
                  startDate:(NSDate *)startDate
                  endDate:(NSDate *)endDate
                  type:(NSString *)type
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    DAPITransactionType enumType = DAPITransactionTypeDefault;
    if([type isEqualToString:@"enriched"]) {
        enumType = DAPITransactionTypeEnriched;
    } else if([type isEqualToString:@"categorized"]) {
        enumType = DAPITransactionTypeCategorized;
    }

    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance cardTransactionsWithBankConnection:bankConnection
                                                    cardID:cardID
                                                      type:enumType
                                                      from:startDate
                                                        to:endDate
                                                completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                             NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(delete:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance delinkWithBankConnection:bankConnection
                                      completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                   NSError * _Nullable error ) {
        if (error) {
            reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
        } else {
            resolve(nil);
        }
    }];
}

RCT_EXPORT_METHOD(getBeneficiaries:(NSString *)userID
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance bankBeneficiariesWithBankConnection:bankConnection
                                                 completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                              NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(createBeneficiary:(NSString *)userID beneficiary:(NSDictionary<NSString *, id> *)beneficiary resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{

        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        DAPIBeneficiary *nativeBeneficiary = [DPCCrossSDK nativeBeneficiaryInfoFromDictionary:beneficiary];
        [DPC.sharedInstance createBeneficiaryWithBankConnection:bankConnection
                                             beneficiaryDetails:nativeBeneficiary
                                                     completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                  NSError * _Nullable error ) {
            [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
        }];
    });
}

RCT_EXPORT_METHOD(createWireBeneficiary:(NSString *)userID beneficiary:(NSDictionary<NSString *, id> *)beneficiary resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{
        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        DAPIWireBeneficiary *nativeBeneficiary = [DPCCrossSDK nativeWireBeneficiaryInfoFromDictionary:beneficiary];
        [DPC.sharedInstance createWireBeneficiaryWithBankConnection:bankConnection
                                                 beneficiaryDetails:nativeBeneficiary
                                                         completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                      NSError * _Nullable error ) {
            [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
        }];
    });
}

RCT_EXPORT_METHOD(getWireBeneficiaries:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance bankWireBeneficiariesWithBankConnection:bankConnection
                                                     completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                  NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(getAccountsMetadata:(NSString *)userID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
    [DPC.sharedInstance accountMetadataWithBankConnection:bankConnection
                                               completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                            NSError * _Nullable error ) {
        [self respondForDictionaryRepresentableObject:data error:error resolver:resolve rejecter:reject];
    }];
}

RCT_EXPORT_METHOD(createTransferToExistingBeneficiary:(NSString *)userID
                  accountID:(NSString *)accountID
                  receiverID:(NSString *)receiverID
                  amount:(double)amount remark:(NSString *)remark resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{

        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        [DPC.sharedInstance createTransferToExistBeneficiaryWithBankConnection:bankConnection
                                                           senderBankAccountID:accountID
                                                         receiverBeneficiaryID:receiverID
                                                                        amount:amount
                                                                        remark:remark
                                                                    completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                                 NSError * _Nullable error) {
            if (error) {
                NSString *jsonError = [DPCCrossSDK jsonRepresentationOfError:error
                                                                   accountID:accountID
                                                                 operationID: [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]] ];
                reject([NSNumber numberWithInteger:error.code].stringValue, jsonError, error);
            } else {
                    resolve(@{
                        @"account": [[NSString alloc] initWithFormat:@"%@", data[@"senderAccountID"]],
                        @"amount": [NSNumber numberWithDouble:amount],
                        @"operationID": [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]],
                        @"remark": [[NSString alloc] initWithFormat:@"%@", data[@"remark"]] ?: [NSNull null],
                        @"reference": [[NSString alloc] initWithFormat:@"%@", data[@"reference"]] ?: [NSNull null]
                    });
            }
        }];
    });
}

RCT_EXPORT_METHOD(createWireTransferToExistingBeneficiary:(NSString *)userID accountID:(NSString *)accountID receiverID:(NSString *)receiverID amount:(double)amount remark:(NSString *)remark resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{
        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        [DPC.sharedInstance createWireTransferToExistBeneficiaryWithBankConnection:bankConnection
                                                               senderBankAccountID:accountID
                                                             receiverBeneficiaryID:receiverID
                                                                            amount:amount
                                                                            remark:remark
                                                                        completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                                                     NSError * _Nullable error ) {
            if (error) {
                NSString *jsonError = [DPCCrossSDK jsonRepresentationOfError:error
                                                                   accountID:accountID
                                                                 operationID: [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]] ];
                reject([NSNumber numberWithInteger:error.code].stringValue, jsonError, error);
            } else {
                    resolve(@{
                        @"account": [[NSString alloc] initWithFormat:@"%@", data[@"senderAccountID"]],
                        @"amount": [NSNumber numberWithDouble:amount],
                        @"operationID": [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]],
                        @"remark": [[NSString alloc] initWithFormat:@"%@", data[@"remark"]] ?: [NSNull null],
                        @"reference": [[NSString alloc] initWithFormat:@"%@", data[@"reference"]] ?: [NSNull null]
                    });
            }
        }];
    });
}



RCT_EXPORT_METHOD(createWireTransfer:(NSString *)userID beneficiary:(NSDictionary<NSString *, id> *)beneficiary accountID:(NSString *)accountID amount:(double)amount remark:(NSString *)remark resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{
        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        DAPIWireBeneficiary *nativeBeneficiary = [DPCCrossSDK nativeWireBeneficiaryInfoFromDictionary:beneficiary];

        [self createWireTransferWithBankConnection:bankConnection
                               senderBankAccountId:accountID
                                     toBeneficiary:nativeBeneficiary
                                            amount:amount
                                            remark:remark
                                        completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                     NSError * _Nullable error ) {
            if (error) {
                NSString *jsonError = [DPCCrossSDK jsonRepresentationOfError:error
                                                                   accountID:accountID
                                                                 operationID: [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]] ];
                reject([NSNumber numberWithInteger:error.code].stringValue, jsonError, error);
            } else {
                    resolve(@{
                        @"account": [[NSString alloc] initWithFormat:@"%@", data[@"senderAccountID"]],
                        @"amount": [NSNumber numberWithDouble:amount],
                        @"operationID": [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]],
                        @"remark": [[NSString alloc] initWithFormat:@"%@", data[@"remark"]] ?: [NSNull null],
                        @"reference": [[NSString alloc] initWithFormat:@"%@", data[@"reference"]] ?: [NSNull null]
                    });
            }
        }];
    });
}

RCT_EXPORT_METHOD(createTransfer:(NSString *)userID
                  accountID:(NSString *)accountID
                  beneficiary:(NSDictionary<NSString *, id> *)beneficiary
                  amount:(double)amount
                  remark:(NSString *)remark
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    dispatch_async(dispatch_get_main_queue(), ^{
        DAPIBankConnection *bankConnection = [DPCCrossSDK  bankConnectionForUserID:userID];
        DAPIBeneficiary *nativeBeneficiary = [DPCCrossSDK nativeBeneficiaryInfoFromDictionary:beneficiary];

        [self createTransferWithBankConnection:bankConnection
                           senderBankAccountId:accountID
                                 toBeneficiary:nativeBeneficiary
                                        amount:amount
                                        remark:remark
                                    completion:^(NSDictionary<NSString *,id> * _Nullable data ,
                                                 NSError * _Nullable error ) {
            if (error) {
                NSString *jsonError = [DPCCrossSDK jsonRepresentationOfError:error
                                                                   accountID:accountID
                                                                 operationID: [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]] ];
                reject([NSNumber numberWithInteger:error.code].stringValue, jsonError, error);
            } else {
                    resolve(@{
                        @"account": [[NSString alloc] initWithFormat:@"%@", data[@"senderAccountID"]],
                        @"amount": [NSNumber numberWithDouble:amount],
                        @"operationID": [[NSString alloc] initWithFormat:@"%@", data[@"operationID"]],
                        @"remark": [[NSString alloc] initWithFormat:@"%@", data[@"remark"]] ?: [NSNull null],
                        @"reference": [[NSString alloc] initWithFormat:@"%@", data[@"reference"]] ?: [NSNull null]
                    });
            }
        }];
    });
}

- (void)connectDidRequestBank:(NSString *)bankName iban:(NSString *)iban {
    id body = @{
        @"bankName": bankName ?: [NSNull null],
        @"iban": iban ?: [NSNull null]
    };
    if (self.hasListeners)
        [self sendEventWithName:self.supportedEvents[4] body:body];
}



// MARK: - Helper Methods

- (void)emitAccountSelectionCanceledEvent {
    if (self.hasListeners)
        [self sendEventWithName:self.supportedEvents[5] body:nil];
}

- (void)respondForDictionaryRepresentableObject:(NSDictionary<NSString *,id> * _Nullable)object
                                          error:(NSError * _Nullable)error
                                       resolver:(RCTPromiseResolveBlock)resolve
                                       rejecter:(RCTPromiseRejectBlock)reject{
    if (error) {
        reject([NSNumber numberWithInteger:error.code].stringValue, error.dapiErrorMessage, error);
    } else if (object != nil) {
        resolve(object);
    }else {
        NSError *castingError = [NSError errorWithDomain:@"com.dapi.dapiconnect.reactnative" code:1012 userInfo:@{NSLocalizedDescriptionKey: @"Couldn't construct JSON representation of native array objects"}];
        reject([NSNumber numberWithInteger:error.code].stringValue, castingError.localizedDescription, castingError);
    }
}



- (void)createTransferWithBankConnection:(DAPIBankConnection * _Nonnull)bankConnection
                     senderBankAccountId:(NSString * _Nonnull)senderBankAccountId
                           toBeneficiary:(DAPIBeneficiary *__nullable)beneficiary
                                  amount:(double)amount
                                  remark:(NSString *__nullable)remark
                              completion:(void (^ _Nonnull)(NSDictionary<NSString *,id> * _Nullable data ,
                                                            NSError * _Nullable error))completion {

    BOOL hasAmount = amount != 0 && amount != NSNotFound;
    BOOL hasAccount = senderBankAccountId != nil;
    if (hasAccount && hasAmount) {

        [DPC.sharedInstance createTransferWithBankConnection:bankConnection
                                         senderBankAccountId:senderBankAccountId
                                         receiverBeneficiary:beneficiary
                                                      amount:amount
                                                      remark:remark
                                                  completion:completion];

    } else {
        DAPIBankAccount *account;
        if (senderBankAccountId) {
            account = [[DAPIBankAccount alloc ] init];
            [account setId:senderBankAccountId];
        }
        self.autoFlow = [[DAPIAutoFlowVC alloc] initWithBankConnection:bankConnection
                                                               account:account
                                                       wireBeneficiary: nil
                                                           beneficiary:beneficiary
                                                          transferType:DAPITransferTypeNormal
                                                                amount:amount
                                                                remark:remark];
        [self.autoFlow setTransferDidFail:^(NSError * _Nonnull error) {
            completion(nil,error);
        }];

        [self.autoFlow setTransferDidSucceed:^(DAPITransferResult * _Nonnull data) {
            completion(data.dictionaryRepresentation,nil);

        }];

        [DPCCrossSDK.topViewController presentViewController: [self autoFlow]
                                                    animated:YES
                                                  completion:nil];

    }

}

- (void)createWireTransferWithBankConnection:(DAPIBankConnection * _Nonnull)bankConnection
                         senderBankAccountId:(NSString * _Nonnull)senderBankAccountId
                               toBeneficiary:(DAPIWireBeneficiary *__nullable)beneficiary
                                      amount:(double)amount
                                      remark:(NSString *__nullable)remark
                                  completion:(void (^ _Nonnull)(NSDictionary<NSString *,id> * _Nullable data ,
                                                                NSError * _Nullable error))completion {

    BOOL hasAmount = amount != 0 && amount != NSNotFound;
    BOOL hasAccount = senderBankAccountId != nil;
    if (hasAccount && hasAmount) {

        [DPC.sharedInstance createWireTransferWithBankConnection:bankConnection
                                             senderBankAccountID:senderBankAccountId
                                             receiverBeneficiary:beneficiary
                                                          amount:amount
                                                          remark:remark
                                                      completion:completion];

    } else {
        DAPIBankAccount *account;
        if (senderBankAccountId) {
            account = [[DAPIBankAccount alloc ] init];
            [account setId:senderBankAccountId];
        }
        self.autoFlow = [[DAPIAutoFlowVC alloc] initWithBankConnection:bankConnection
                                                               account:account
                                                       wireBeneficiary:beneficiary
                                                           beneficiary:nil
                                                          transferType:DAPITransferTypeWire
                                                                amount:amount
                                                                remark:remark];
        [self.autoFlow setTransferDidFail:^(NSError * _Nonnull error) {
            completion(nil,error);
        }];

        [self.autoFlow setTransferDidSucceed:^(DAPITransferResult * _Nonnull data) {
            completion(data.dictionaryRepresentation,nil);

        }];

        [DPCCrossSDK.topViewController presentViewController: [self autoFlow]
                                                    animated:YES
                                                  completion:nil];

    }

}

- (void)dapiConnect:(DAPIConnectVC * _Nonnull)dapiConnect
didFailConnectingWith:(NSString * _Nonnull)error {
    id body = @{
        //        @"bankID": bankID ?: [NSNull null],
        @"error": error ?: [NSNull null]
    };
    if (self.hasListeners)
        [self sendEventWithName:self.supportedEvents[1] body:body];

}

- (void)dapiConnect:(DAPIConnectVC * _Nonnull)dapiConnect
didSuccessfullyConnectTo:(NSString * _Nullable)bankID
     bankConnection:(DAPIBankConnection * _Nonnull)bankConnection {

    id body = @{
        @"bankID": bankID,
        @"connection": bankConnection.dicRepresentation ?: [NSNull null]
    };

    if (self.hasListeners)
        [self sendEventWithName:self.supportedEvents[0] body:body];

}

- (void)dapiConnectUserDidCancel:(DAPIConnectVC * _Nonnull)dapiConnect {
    if (self.hasListeners)
        [self sendEventWithName:self.supportedEvents[3] body:nil];

}



@end

