
#import "CDVIndigitallInApp.h"
#import <Indigitall/IndigitallInApp.h>
#import <Indigitall/INInAppUtils.h>
#import <Indigitall/INEventUtils.h>
#import "CDVIndigitallInAppParse.h"

#import "CDVInAppHandler.h"
#import <Indigitall/INEventUtils.h>
#import <Indigitall/INInAppConfig.h>
#import <Indigitall/INInAppTopicListCallback.h>

@implementation CDVIndigitallInApp

- (void) packageName:(CDVInvokedUrlCommand *)command{
    [self.commandDelegate runInBackground:^{
        NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:bundleIdentifier];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];        
    }];
}

- (void) showPopUp: (CDVInvokedUrlCommand *)command{
    NSDictionary *params = command.arguments.firstObject;
    NSString *appKey = params[@"appKey"];
    NSString *inAppCode;
    NSString *domainInApp = @"https://device-api.indigitall.com/v2";
    NSString *profile = nil;
    BOOL closeIconDisabled = false;
    NSString *closeIconName;
    UIButton *button;
    int customTimeSlideForCarousel = INInAppAPIConstants.INAPP_TIME_SLIDE_CAROUSEL;
    
    BOOL closePopupWhenClicked = false;
    
    if (params[@"domainInApp"]) domainInApp = params[@"domainInApp"];
    if (params[@"schemeId"]) inAppCode = params[@"schemeId"];
    if ([params[@"closeIconDisabled"]boolValue] ==  true) closeIconDisabled = true;
    if (params[@"imageCloseButtonName"]){
        closeIconName = params[@"imageCloseButtonName"];
        button = [[UIButton alloc]init];
        [button setImage:[UIImage imageNamed:closeIconName] forState:normal];
        [button setTranslatesAutoresizingMaskIntoConstraints:false];
    }
    if (params[@"closePopupWhenClicked"]){
        closePopupWhenClicked = params[@"closePopupWhenClicked"];
    }
    if (params[@"profile"]) profile = params[@"profile"];
    if (params[@"customTimeSlideForCarousel"]) customTimeSlideForCarousel = [params[@"customTimeSlideForCarousel"]intValue];
        
    
    if (inAppCode && appKey) {
        [self.commandDelegate runInBackground:^{
            INInAppConfig *config = [[INInAppConfig alloc]initWithAppKey:appKey];
            config.domainInApp = domainInApp;
            if (inAppCode != nil){
                INInApp *inApp = [INInAppDao searchInApp:inAppCode];
                config.inAppCurrent = config;
                [INInAppDefaults setAppKey:config.appKey];
                config.profile = profile;
                config.customTimeSlideForCarousel = customTimeSlideForCarousel;
                [config updateConfig];
                [INInAppDefaults setLocationPermissionMode:[CDVIndigitallInApp permissionToInt:config.locationPermissionMode]];
                [InAppIndigitall getInAppApplicationConfigWithOnSuccess:^(INInAppApplication * _Nonnull inAppApplication) {
                    config.inAppCurrent = config;
                    [InAppIndigitall updateConfig:config withApplication:inAppApplication];
                    [[[CDVInAppHandler alloc]init]showPopup:inAppCode closePopupWhenClicked:closePopupWhenClicked closeIcon:button closeIconDisabled:closeIconDisabled didAppear:^{
                        [self successWithInApp:inApp command:command];
                    } didCancel:^{
                        [self failedWithString:@"InApp didCancel" command:command];
                    } didTouchWithAction:^(INInAppAction * _Nonnull action) {
                        [self successWithInApp:inApp action:action command:command];
                    } didDismissed:^{
                        [self failedWithString:@"InApp dismiss" command:command];
                    } onShowTimeFinished:^(INInApp * _Nonnull inApp, int showTime) {
                        [self failedWithErrorCode:showTime message:@"InApp onShowTimeFinished" command:command];
                    } didExpired:^(INInApp * _Nonnull inApp, INError * _Nonnull error) {
                        [self failedWithError:error command:command];
                    } didShowManyTimes:^(INInApp * _Nonnull inApp, INError * _Nonnull error) {
                        [self failedWithError:error command:command];
                    } didClickOut:^(INInApp * _Nonnull inApp, INError * _Nonnull error) {
                        [self failedWithError:error command:command];
                    } didDismissForever:^(INInApp * _Nonnull inApp, INError * _Nonnull error) {
                        [self failedWithError:error command:command];
                    } failed:^(INError * _Nonnull error) {
                        [self failedWithError:error command:command];
                    } formFailed:^(NSArray<INInAppError *> * _Nonnull error) {
                        [self failedWithErrorCode:error[0].errorCode message:@"InApp didFormError" command:command];
                    } formSubmit:^(INInApp * _Nonnull inApp, NSDictionary *jsonForm) {
                        [self successWithCommand:command];
                    }];
                } onError:^(INError * _Nonnull error) {
                    [self failedWithError:error command:command];
                }];
                
            }else{
                [self failedWithString:@"InApp is not a JsonObject" command:command];
            }
        }];
    }
}

+ (int) permissionToInt: (PermissionMode)permission{
    switch (permission) {
        case manual:
            return 0;
            break;
        case provisional:
            return 2;
            break;
        case automatic:
        default:
            return 1;
    }
    return 1;
}

- (void) inAppWasShown: (CDVInvokedUrlCommand *)command{
    NSDictionary *params = command.arguments.firstObject;
    NSString *appKey = params[@"appKey"];
    NSString *inAppCode;
    NSString *profile;
    int customTimeSlideForCarousel = INInAppAPIConstants.INAPP_TIME_SLIDE_CAROUSEL;
    NSString *domainInApp = @"https://device-api.indigitall.com/v2";
    if (params[@"domainInApp"]) domainInApp = params[@"domainInApp"];
    if (params[@"schemeId"]) inAppCode = params[@"schemeId"];
    if (params[@"profile"]) profile = params[@"profile"];
    if (params[@"customTimeSlideForCarousel"]) customTimeSlideForCarousel = [params[@"customTimeSlideForCarousel"]intValue];
        
    if (inAppCode && appKey) {
        [self.commandDelegate runInBackground:^{
            INInAppConfig *config = [[INInAppConfig alloc]initWithAppKey:appKey];
            config.domainInApp = domainInApp;
            config.profile = profile;
            config.customTimeSlideForCarousel = customTimeSlideForCarousel;
            [INInAppDefaults setDomainInApp:domainInApp];
            [INInAppDefaults setAppKey:config.appKey];
            [config updateConfig];
            if (inAppCode != nil){
                [self inAppWasGotWithInAppCode:inAppCode config:config command:command];
            }else{
                [self failedWithString:@"InApp is not a JsonObject" command:command];
            }
        }];
    }
}

- (void) inAppWasGotWithInAppCode: (NSString *)inAppCode config:(INInAppConfig*)config command:(CDVInvokedUrlCommand *)command{
    [self.commandDelegate runInBackground:^{
        [InAppIndigitall showCustomInAppWithConfig:config inAppCode:inAppCode onSuccess:^(INInApp * _Nonnull inApp) {
            [self successWithInApp:inApp command:command];
        } onFailed:^(INInAppError * _Nonnull error) {
            if (error.inAppErrorCode == 2101) {
                [self failedWithErrorCode:2101 message:@"did expired" command:command];
            } else if (error.inAppErrorCode == INAPP_WAS_SHOWN_MANY_TIMES) {
                [self failedWithErrorCode:2102 message:@"did show many times" command:command];
            } else if (error.inAppErrorCode == INAPP_WAS_CLICKED_MANY_TIMES) {
                [self failedWithErrorCode:2103 message:@"did click out" command:command];
            }
            [self failedWithInAppError:error command:command];
        }];
    }];
}

- (void) inAppAddNewClick: (CDVInvokedUrlCommand *)command{
    [self.commandDelegate runInBackground:^{
        id object = [command.arguments objectAtIndex:0];
        INInApp *inApp= nil;
        INInAppAction *action = nil;
        if (![object isKindOfClass:[NSString class]]){
            inApp = [[INInApp alloc]initWithJson:object];
        } else if ([object isKindOfClass:[NSString class]]){
            inApp = [[INInApp alloc]initWithJson:[CDVIndigitallInApp toNSDictionary:object]];
        }
        int inAppId = inApp.inAppId;
        if (inAppId != 0) inApp = [INInAppDao searchInAppWithInAppId:inAppId];
        id actionObject = [command.arguments objectAtIndex:1];
        if (inApp != nil && actionObject != nil) {
            NSDictionary *jsonAction = [CDVIndigitallInApp toNSDictionary:actionObject];
            if ([jsonAction objectForKey:@"action"]) {
                action = [[INInAppAction alloc]init:[jsonAction objectForKey:@"action"]];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [INInAppUtils inAppOpenUrl:action];
                });
                [inApp.properties setAction:action];
            }
            inApp.properties.action = action;
        }
        if (inApp != nil){
            [INInAppUtils inAppWasTappedWithInApp:inApp];
            [self successWithInApp:inApp action:action command:command];
        }else{
            [self failedWithString:@"InApp is not a JsonObject" command:command];
        }
    }];
}

- (void) eventClickInAppRequest: (CDVInvokedUrlCommand *)command {
    NSDictionary *params = command.arguments.firstObject;
    [self.commandDelegate runInBackground:^{
        if (params != nil && [params objectForKey:INInAppAPIConstants.inAppId]) {
            INInApp *inApp = [INInAppDao searchInApp:[params objectForKey:INInAppAPIConstants.inAppId]];
            if (inApp != nil){
                [INEventUtils eventClickInAppRequest:inApp];
                [self successWithCommand:command];
            }else{
                [self failedWithString:@"InApp is not a JsonObject" command:command];
            }
        }
    }];
}

- (void) eventPrintInAppRequest: (CDVInvokedUrlCommand *)command {
    NSDictionary *params = command.arguments.firstObject;
    [self.commandDelegate runInBackground:^{
        INInApp *inApp = [[INInApp alloc]initWithJson:params];
        if (inApp != nil){
            [INEventUtils eventPrintInAppRequest:inApp];
            [self successWithCommand:command];
        }else{
            [self failedWithString:@"InApp is not a JsonObject" command:command];
        }
    }];
}

- (void) addNewInAppToDismissForever:(CDVInvokedUrlCommand *)command {
    NSDictionary *params = command.arguments.firstObject;
    [self.commandDelegate runInBackground:^{
        INInApp *inApp = [[INInApp alloc]initWithJson:params];
        [INInAppUtils addNewInAppToDismissForever:inApp];
    }];
}

- (void) topicsList: (CDVInvokedUrlCommand *)command {
    [self.commandDelegate runInBackground:^{
        [InAppIndigitall topicsListWithOnSuccess:^(NSArray<INInAppTopic *> * _Nonnull topics) {
            [self successWithTopic:topics command:command];
        } onError:^(INError * _Nonnull error) {
           
        }];
    }];
}

- (void) topicsListFromConsole: (CDVInvokedUrlCommand *)command {
    [self.commandDelegate runInBackground:^{
        NSDictionary *params = command.arguments.firstObject;
        NSString *appKey = nil;
        NSString *domainInApp = @"https://device-api.indigitall.com/v2";
        int limit = 20;
        int page = 0;
        
        if (params[@"appKey"]) appKey = params[@"appKey"];
        if (params[@"domainInApp"]) domainInApp = params[@"domainInApp"];
        if (params[@"limit"]) limit = [params[@"limit"]intValue];
        if (params[@"page"]) page = [params[@"page"]intValue];
        
        INInAppConfig *config = [[INInAppConfig alloc]init];
        if (appKey != nil) config.appKey = appKey;
        if (domainInApp != nil) config.domainInApp = domainInApp;
        
        INRequestInAppTopicList *request = [[INRequestInAppTopicList alloc] initWithPage: page];
        request.limit = 20;
        INInAppTopicListCallback *callback = [[INInAppTopicListCallback alloc] initWithCurrentPage:page onSuccess:^(INInAppPageTopic * _Nonnull inAppPageTopic) {
            [self successWithInAppPageTopic:inAppPageTopic command:command];
        } onError:^(INInAppError * _Nonnull error) {
            [self failedWithError:error command:command];
        } request:request];
        [INInAppAPIClient getTopics: request callback: callback];
    }];
}

- (void) topicsSubscribe: (CDVInvokedUrlCommand *)command {
    NSArray<NSString *>* params = command.arguments;
    [self.commandDelegate runInBackground:^{
        [InAppIndigitall topicsSubscribeWithArrayString:params onSuccess:^(NSArray<INInAppTopic *> * _Nonnull topics) {
            [self successWithTopic:topics command:command];
        } onError:^(INError * _Nonnull error) {
            [self failedWithCommand:command];
        }];
     }];
}

- (void) topicsUnsubscribe: (CDVInvokedUrlCommand *)command {
    NSArray<NSString *>* params = command.arguments;
    [self.commandDelegate runInBackground:^{
        [InAppIndigitall topicsUnSubscribeWithArrayString:params onSuccess:^(NSArray<INInAppTopic *> * _Nonnull topics) {
            [self successWithTopic:topics command:command];
        } onError:^(INError * _Nonnull error) {
            [self failedWithCommand:command];
        }];
     }];
}

- (void) topicsUnsubscribeAll: (CDVInvokedUrlCommand *)command {
    NSArray<NSString *>* params = command.arguments;
    [self.commandDelegate runInBackground:^{
        [InAppIndigitall topicsUnsubscribeAllWithOnSuccess:^(NSArray<INInAppTopic *> * _Nonnull topics) {
            [self successWithTopic:topics command:command];
        } onError:^(INError * _Nonnull error) {
            [self failedWithCommand:command];
        }];
     }];
}

- (void) inAppFormSubmit:(CDVInvokedUrlCommand *)command {
    NSArray<NSString *>* params = command.arguments;
    [self.commandDelegate runInBackground:^{
        if (params != nil && params.count > 0) {
            id object = params[0];
            INInApp *inApp = [[INInApp alloc]initWithJson:object];
            if (inApp != nil) {
                NSMutableDictionary *dicForms = [NSMutableDictionary new];
                [dicForms setValue:params[1] forKey:@"formOptions"];
                [dicForms setValue:params[2] forKey:@"jsonForm"];
                [dicForms setValue:params[3] forKey:@"jsonCustomer"];
                NSArray<INInAppError *> *errorList = [INInAppFormUtils checkFieldsForm:[dicForms copy] withInApp:inApp];
                if (errorList.count > 0) {
                    [self failedWithErrorList:errorList command:command];
                } else {
                    [self successWithInApp:inApp withJsonForm:params[2] command:command];
                }
            }            
        }
    }];
}

- (void) updateInAppGetWithInAppDb: (CDVInvokedUrlCommand *)command {
   NSString *params = command.arguments.firstObject;
    [self.commandDelegate runInBackground:^{
        INInApp *inAppDb = [INInAppDao searchInApp:params];
        NSString *inAppCode = inAppDb.code;
        [INInAppHandler getInAppToUpdate:inAppCode success:^(INInApp * _Nonnull inApp) {
            if ([INInAppDao updateInAppField:inApp withInAppDb:inAppDb keys:nil values:nil]) {
                INInApp *newInApp = [INInAppDao searchInApp:inAppCode];
                INInAppError *error = [INInAppUtils wasInAppPassedFilterProperties:newInApp];
                if (error != nil) {
                    if (error.inAppErrorCode == INAPP_WAS_SHOWN_MANY_TIMES) {
                        [self failedWithErrorCode:2102 message:@"did show many times" command:command];
                    } else if (error.inAppErrorCode == INAPP_WAS_CLICKED_MANY_TIMES) {
                        [self failedWithErrorCode:2103 message:@"did click out" command:command];
                    }
                } else {
                    [self successWithInApp:newInApp command:command];
                }
            } else {
                [self failedWithString:@"InApp was not updated after get from cache" command:command];
            }
        } errorLoad:^(INError * _Nonnull error) {
            [self failedWithError:error command:command];
        }];
    }];
}

+ (NSDictionary *)toNSDictionary: (NSString *) jsonString {
    NSData *data = nil;
    @try {
        data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    } @catch (NSException *exception) {
        NSLog(@"%@", exception.description);
    }
    return [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
}

- (void) successWithCommand: (CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) successWithString:(NSString *)resultString command:(CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:resultString];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) successWithBool:(BOOL)resultBool command:(CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:resultBool];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) successWithInApp: (INInApp *)inApp command: (CDVInvokedUrlCommand *)command{
    NSDictionary *data = [CDVIndigitallInAppParse jsonFromInApp: inApp];
    [self.commandDelegate runInBackground:^{
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:data];
        [result setKeepCallbackAsBool:true];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    }];
}

- (void) successWithInApp: (INInApp *)inApp withJsonForm:(NSDictionary *)json command: (CDVInvokedUrlCommand *)command{
    NSDictionary *inAppDic = [CDVIndigitallInAppParse jsonFromInApp: inApp];
    NSMutableDictionary *data = [NSMutableDictionary new];
    [data setValue:inAppDic forKey:@"inApp"];
    [data setValue:json forKey:@"jsonForm"];
    
    [self.commandDelegate runInBackground:^{
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:data];
        [result setKeepCallbackAsBool:true];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    }];
}

- (void) successWithInApp: (INInApp *)inApp action: (INInAppAction *)action command: (CDVInvokedUrlCommand *)command{
    NSMutableDictionary *dataMutable = [NSMutableDictionary new];
    [dataMutable setValue:[CDVIndigitallInAppParse jsonFromInApp: inApp] forKey:@"inApp"];
    [dataMutable setValue:[CDVIndigitallInAppParse jsonFromAction:action] forKey:@"action"];
    [self.commandDelegate runInBackground:^{
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[dataMutable copy]];
        [result setKeepCallbackAsBool:true];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    }];
}

- (void) successWithInAppPageTopic: (INInAppPageTopic *)inAppPageTopic command: (CDVInvokedUrlCommand *)command{
    NSMutableDictionary *dataMutable = [NSMutableDictionary new];
    [dataMutable setValue:[CDVIndigitallInAppParse jsonFromInAppPageTopic: inAppPageTopic] forKey:@"inAppPageTopic"];
    [self.commandDelegate runInBackground:^{
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[dataMutable copy]];
        [result setKeepCallbackAsBool:true];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    }];
}

- (void) successWithTopic: (NSArray<INInAppTopic *> *)topics command: (CDVInvokedUrlCommand *)command{
   NSArray<NSDictionary *>* data = [CDVIndigitallInAppParse jsonArrayFromtopics: topics];
   CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:data];
   [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}


- (void) failedWithCommand: (CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) failedWithErrorList: (NSArray<INInAppError *>*) errorList command:(CDVInvokedUrlCommand *)command{
    
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorList.firstObject.message];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) failedWithError: (INError *)error command:(CDVInvokedUrlCommand *)command{
    [self failedWithErrorCode:error.errorCode message:error.message command:command];
}

- (void) failedWithInAppError: (INInAppError *)error command:(CDVInvokedUrlCommand *)command{
    [self failedWithErrorCode:error.errorCode message:error.message command:command];
}

- (void) failedWithErrorCode: (int) errorCode message:(NSString* )message  command:(CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{@"errorCode": @(errorCode), @"errorMessage": message}];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) failedWithString: (NSString *)message command:(CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

- (void) failedWithNSDictionary: (NSDictionary *)dic command:(CDVInvokedUrlCommand *)command{
    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

@end
