
@import UIKit;
#import "RNRegulaDocumentReader.h"

@implementation RNRegulaDocumentReader

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE();

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

RCT_EXPORT_METHOD(initialize:(NSDictionary*) options callback:(RCTResponseSenderBlock)callback)
{
    NSString *licenseKey = options[@"licenseKey"];
    NSData *licenseData = [[NSData alloc] initWithBase64EncodedString:licenseKey options:0];
    ProcessParams *params = [[ProcessParams alloc] init];
    self.docReader = [[DocReader alloc] initWithProcessParams:params];
    
    [self.docReader initilizeReaderWithLicense:licenseData completion:^(BOOL successful, NSString * _Nullable error ) {
        if (successful) {
            callback(@[@"init complete"]);
        } else {
            callback(@[@[[NSString stringWithFormat:@"%@/%@", @"init failed: ", error]]]);
        }
    }];
}

RCT_EXPORT_METHOD(initializeWithDatabasePath:(NSDictionary*)options databasePath:(NSString * _Nonnull)databasePath callback:(RCTResponseSenderBlock)callback)
{
    NSString *licenseKey = options[@"licenseKey"];
    NSData *licenseData = [[NSData alloc] initWithBase64EncodedString:licenseKey options:0];
    ProcessParams *params = [[ProcessParams alloc] init];
    self.docReader = [[DocReader alloc] initWithProcessParams:params];
    
    [self.docReader initilizeReaderWithLicense:licenseData databasePath:databasePath completion:^(BOOL successful, NSString * _Nullable error ) {
        if (successful) {
            callback(@[@"init complete"]);
        } else {
            callback(@[@[[NSString stringWithFormat:@"%@/%@", @"init failed: ", error]]]);
        }
    }];
}

RCT_EXPORT_METHOD(prepareDataBase:(NSString *) dbID callback:(RCTResponseSenderBlock)callback)
{
    ProcessParams *params = [[ProcessParams alloc] init];
    self.docReader = [[DocReader alloc] initWithProcessParams:params];
    [self.docReader prepareDatabaseWithDatabaseID:dbID progressHandler:^(NSProgress * _Nonnull progress) {
        [self sendEventWithName:@"prepareDatabaseProgressChangeEvent" body:@{@"msg": [NSString stringWithFormat:@"%@%.1f%@", @"Downloading database: ", progress.fractionCompleted * 100, @"%"]}];
    } completion:^(BOOL successful, NSString * _Nullable error) {
        if (successful) {
            callback(@[@"database prepared"]);
        } else {
            callback(@[@[[NSString stringWithFormat:@"%@/%@", @"database preparation failed: ", error]]]);
        }
    }];
}

RCT_EXPORT_METHOD(showScanner:(RCTResponseSenderBlock)cb)
{
    if([self.docReader documentReaderIsReady]){
    __block RCTResponseSenderBlock callback = cb;
    // prevent multiple invocations of cb
    void __block (^callbackWith)(id results) = ^(id results)
    {
        if (callback == nil) return;
        
        callback(results);
        callback = nil;
        // [self.docReader stopScanner];
    };
    
    dispatch_async(dispatch_get_main_queue(), ^{
        UIViewController *currentViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
        [self.docReader showScanner:currentViewController completion:^(enum DocReaderAction action, DocumentReaderResults * _Nullable result, NSString * _Nullable error) {
            NSLog(@"DocumentReaderAction %ld", (long)action);
            
            switch (action) {
                case DocReaderActionCancel: {
                    callbackWith(@[@"Cancelled by user", [NSNull null]]);
                    break;
                }
                    
                case DocReaderActionComplete: {
                    callbackWith(@[[NSString stringWithFormat: @"%@%@", @"Success:", [JsonConstructor resultsToJsonString:result]]]);
                    
                    break;
                }
                    
                case DocReaderActionError: {
                    callbackWith(@[error, [NSNull null]]);
                    break;
                }
                    
                case DocReaderActionProcess: {
                    break;
                }
                    
                case DocReaderActionMorePagesAvailable: {
                    break;
                }
                    
                default: {
                    callbackWith(@[@"unknown scanning status"]);
                    break;
                }
            }
        }];
    });
    }else{
        cb(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(recognizeImage:(NSString *) base64image callback:(RCTResponseSenderBlock)cb )
{
    if([self.docReader documentReaderIsReady]){
    __block RCTResponseSenderBlock callback = cb;
    // prevent multiple invocations of cb
    void __block (^callbackWith)(id results) = ^(id results)
    {
        if (callback == nil) return;
        
        callback(results);
        callback = nil;
        // [self.docReader stopScanner];
    };
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSMutableString *base64 = [NSMutableString stringWithString: base64image];
        if(![[base64image substringToIndex:10] isEqualToString:@"data:image"]){
            base64 = [NSMutableString stringWithFormat: @"%@%@", @"data:image/jpeg;base64,", base64image];
        }
        NSURL *url = [NSURL URLWithString:base64];
        NSData *imageData = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:imageData];
        NSLog(@"-----SCANNING------");
        [self.docReader recognizeImage:image cameraMode:false completion:^(enum DocReaderAction action, DocumentReaderResults * _Nullable result, NSString * _Nullable error) {
            NSLog(@"DocumentReaderAction %ld", (long)action);
            
            switch (action) {
                case DocReaderActionCancel: {
                    callbackWith(@[@"Cancelled by user", [NSNull null]]);
                    break;
                }
                    
                case DocReaderActionComplete: {
                    callbackWith(@[[NSString stringWithFormat: @"%@%@", @"Success:", [JsonConstructor resultsToJsonString:result]]]);
                    
                    break;
                }
                    
                case DocReaderActionError: {
                    callbackWith(@[error, [NSNull null]]);
                    break;
                }
                    
                case DocReaderActionProcess: {
                    break;
                }
                    
                case DocReaderActionMorePagesAvailable: {
                    break;
                }
                    
                default: {
                    callbackWith(@[@"unknown scanning status"]);
                    break;
                }
            }
        }];
    });
}else{
    cb(@[@"document reader not ready"]);
}
}

RCT_EXPORT_METHOD(runAutoUpdate:(NSDictionary*) options callback:(RCTResponseSenderBlock)callback)
{
    NSString *dbID = @"Full";
    if(options[@"dbID"] != nil){
        dbID = options[@"dbID"];
    }
    ProcessParams *params = [[ProcessParams alloc] init];
    self.docReader = [[DocReader alloc] initWithProcessParams:params];
    [self.docReader runAutoUpdateWithDatabaseID:dbID progressHandler:^(NSProgress * _Nonnull progress) {
        [self sendEventWithName:@"prepareDatabaseProgressChangeEvent" body:@{@"msg": [NSString stringWithFormat:@"%@%.1f%@", @"Downloading database: ", progress.fractionCompleted * 100, @"%"]}];
    } completion:^(BOOL successful, NSString * _Nullable error) {
        if (successful) {
            callback(@[@"database prepared"]);
        } else {
            callback(@[@[[NSString stringWithFormat:@"%@/%@", @"database preparation failed: ", error]]]);
        }
    }];
}

RCT_EXPORT_METHOD(setConfig:(NSDictionary*) options callback:(RCTResponseSenderBlock)callback)
{
    if([self.docReader documentReaderIsReady]){
        [RegulaConfig setConfig:options :self.docReader];
        callback(@[@""]);
    }else{
        callback(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(stopScanner:(RCTResponseSenderBlock)cb )
{
    [self.docReader stopScanner];
    cb(@[@""]);
}

RCT_EXPORT_METHOD(invalidateAllDownloadSessions:(RCTResponseSenderBlock)cb )
{
    [self.docReader invalidateAllDownloadSessions];
    cb(@[@""]);
}
     
RCT_EXPORT_METHOD(startNewSession:(RCTResponseSenderBlock)cb )
{
    [self.docReader startNewSession];
    cb(@[@""]);
}
     
RCT_EXPORT_METHOD(startNewPage:(RCTResponseSenderBlock)cb )
{
    [self.docReader startNewPage];
    cb(@[@""]);
}

RCT_EXPORT_METHOD(getDocumentIsReady:(RCTResponseSenderBlock)cb )
{
    cb(@[[self.docReader documentReaderIsReady] ? @"YES" : @"NO"]);
}

RCT_EXPORT_METHOD(getAPIVersion:(RCTResponseSenderBlock)cb )
{
    cb(@[[[self.docReader version] api]]);
}

RCT_EXPORT_METHOD(getCOREVersion:(RCTResponseSenderBlock)cb )
{
    cb(@[[[self.docReader version] core]]);
}

RCT_EXPORT_METHOD(getCOREMode:(RCTResponseSenderBlock)cb )
{
    cb(@[[[self.docReader version] coreMode]]);
}

RCT_EXPORT_METHOD(getDatabaseID:(RCTResponseSenderBlock)cb )
{
    cb(@[[[[self.docReader version] database] databaseID]]);
}

RCT_EXPORT_METHOD(getDatabaseVersion:(RCTResponseSenderBlock)cb )
{
    cb(@[[[[self.docReader version] database] version]]);
}

RCT_EXPORT_METHOD(getDatabaseDate:(RCTResponseSenderBlock)cb )
{
    cb(@[[[[self.docReader version] database] date]]);
}

RCT_EXPORT_METHOD(getDatabaseDescription:(RCTResponseSenderBlock)cb )
{
    cb(@[[[[self.docReader version] database] databaseDescription]]);
}

RCT_EXPORT_METHOD(getDatabaseCountriesNumber:(RCTResponseSenderBlock)cb )
{
    cb([@([[[self.docReader version] database] countriesNumber]) stringValue]);
}

RCT_EXPORT_METHOD(getDatabaseDocumentsNumber:(RCTResponseSenderBlock)cb )
{
    cb([@([[[self.docReader version] database] documentsNumber]) stringValue]);
}

RCT_EXPORT_METHOD(getCurrentScenario:(RCTResponseSenderBlock)cb )
{
    cb(@[[[self.docReader processParams] scenario]]);
}

RCT_EXPORT_METHOD(getCameraSessionIsPaused:(RCTResponseSenderBlock)cb )
{
    cb(@[[self.docReader cameraSessionIsPaused] ? @"YES" : @"NO"]);
}

RCT_EXPORT_METHOD(getCanRFID:(RCTResponseSenderBlock)cb )
{
    cb(@[@false]);
}

RCT_EXPORT_METHOD(getAvailableScenarios:(RCTResponseSenderBlock)cb )
{
    NSMutableArray *availableScenarios = [[NSMutableArray alloc] init];
    for(Scenario *scenario in [self.docReader availableScenarios]){
        [availableScenarios addObject:[scenario identifier]];
    }
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:availableScenarios
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    cb(@[jsonString]);
}

@end
