@import UIKit;
#import "RNRegulaDocumentReader.h"

@implementation RNRegulaDocumentReader

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE();

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

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

RCT_EXPORT_METHOD(initializeReaderWithDatabasePath:(NSDictionary*)options databasePath:(NSString * _Nonnull)databasePath callback:(RCTResponseSenderBlock)callback)
{
    NSString *licenseKey = options[@"licenseKey"];
    NSData *licenseData = [[NSData alloc] initWithBase64EncodedString:licenseKey options:0];
    self.docReader = RGLDocReader.shared;
    
    [self.docReader initializeReader: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)
{
    self.docReader = RGLDocReader.shared;
    [self.docReader prepareDatabase: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 isDocumentReaderIsReady]){
    __block RCTResponseSenderBlock callback = cb;
    // prevent multiple invocations of cb
    void __block (^callbackWith)(id results) = ^(id results)
    {
        if (callback == nil) return;
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
        callback(results);
        callback = nil;
        // [self.docReader stopScanner];
    };
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
        UIViewController *currentViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
        [self.docReader showScanner:currentViewController completion:^(enum RGLDocReaderAction action, RGLDocumentReaderResults * _Nullable result, NSString * _Nullable error) {
            NSLog(@"DocumentReaderAction %ld", (long)action);
            
            switch (action) {
                case RGLDocReaderActionCancel: {
                    callbackWith(@[@"Cancelled by user", [NSNull null]]);
                    break;
                }
                    
                case RGLDocReaderActionComplete: {
                    callbackWith(@[[NSString stringWithFormat: @"%@%@", @"Success:", [JsonConstructor resultsToJsonString:result]]]);
                    
                    break;
                }
                    
                case RGLDocReaderActionError: {
                    callbackWith(@[error, [NSNull null]]);
                    break;
                }
                    
                case RGLDocReaderActionProcess: {
                    break;
                }
                    
                case RGLDocReaderActionMorePagesAvailable: {
                    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 isDocumentReaderIsReady]){
        __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 completion:^(enum RGLDocReaderAction action, RGLDocumentReaderResults * _Nullable result, NSString * _Nullable error) {
                NSLog(@"DocumentReaderAction %ld", (long)action);
                
                switch (action) {
                    case RGLDocReaderActionCancel: {
                        callbackWith(@[@"Cancelled by user", [NSNull null]]);
                        break;
                    }
                        
                    case RGLDocReaderActionComplete: {
                        callbackWith(@[[NSString stringWithFormat: @"%@%@", @"Success:", [JsonConstructor resultsToJsonString:result]]]);
                        
                        break;
                    }
                        
                    case RGLDocReaderActionError: {
                        callbackWith(@[error, [NSNull null]]);
                        break;
                    }
                        
                    case RGLDocReaderActionProcess: {
                        break;
                    }
                        
                    case RGLDocReaderActionMorePagesAvailable: {
                        break;
                    }
                        
                    default: {
                        callbackWith(@[@"unknown scanning status"]);
                        break;
                    }
                }
            }];
        });
    }else{
        cb(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(recognizeImageWithCameraMode:(NSString *) base64image cameraMode:(BOOL)cameraMode callback:(RCTResponseSenderBlock)cb )
{
    if([self.docReader isDocumentReaderIsReady]){
        __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:cameraMode completion:^(enum RGLDocReaderAction action, RGLDocumentReaderResults * _Nullable result, NSString * _Nullable error) {
                NSLog(@"DocumentReaderAction %ld", (long)action);
                
                switch (action) {
                    case RGLDocReaderActionCancel: {
                        callbackWith(@[@"Cancelled by user", [NSNull null]]);
                        break;
                    }
                        
                    case RGLDocReaderActionComplete: {
                        callbackWith(@[[NSString stringWithFormat: @"%@%@", @"Success:", [JsonConstructor resultsToJsonString:result]]]);
                        
                        break;
                    }
                        
                    case RGLDocReaderActionError: {
                        callbackWith(@[error, [NSNull null]]);
                        break;
                    }
                        
                    case RGLDocReaderActionProcess: {
                        break;
                    }
                        
                    case RGLDocReaderActionMorePagesAvailable: {
                        break;
                    }
                        
                    default: {
                        callbackWith(@[@"unknown scanning status"]);
                        break;
                    }
                }
            }];
        });
    }else{
        cb(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(runAutoUpdate:(NSString *) dbID callback:(RCTResponseSenderBlock)callback)
{
    self.docReader = RGLDocReader.shared;
    [self.docReader runAutoUpdate: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 isDocumentReaderIsReady]){
        [RegulaConfig setConfig:options :self.docReader];
        callback(@[@""]);
    }else{
        callback(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(getConfig:(RCTResponseSenderBlock)callback)
{
    if([self.docReader isDocumentReaderIsReady]){
        callback(@[[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[RegulaConfig getConfig:self.docReader] options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding]]);
    }else{
        callback(@[@"document reader not ready"]);
    }
}

RCT_EXPORT_METHOD(startRFIDReaderFromPresenter:(RCTResponseSenderBlock)cb)
{
//    [self.docReader startRFIDReaderFromPresenter];
    cb(@[@"in development"]);
}

RCT_EXPORT_METHOD(startRFIDReading:(RCTResponseSenderBlock)cb)
{
    //    [self.docReader startRFIDReading];
    cb(@[@"in development"]);
}

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

RCT_EXPORT_METHOD(selectedScenario:(RCTResponseSenderBlock)cb )
{
    cb(@[[JsonConstructor generateScenario:self.docReader.selectedScenario]]);
}

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

RCT_EXPORT_METHOD(getDocumentReaderIsReady:(RCTResponseSenderBlock)cb )
{
    cb(@[[self.docReader isDocumentReaderIsReady] ? @"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(@[[NSString stringWithFormat: @"%ld", (long)self.docReader.version.database.countriesNumber]]);
}

RCT_EXPORT_METHOD(getDatabaseDocumentsNumber:(RCTResponseSenderBlock)cb )
{
    cb(@[[NSString stringWithFormat: @"%ld", (long)self.docReader.version.database.documentsNumber]]);
}

RCT_EXPORT_METHOD(getLicenseExpiryDate:(RCTResponseSenderBlock)cb )
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setFormatterBehavior:NSDateFormatterBehaviorDefault];
    [formatter setDateStyle:NSDateFormatterShortStyle];
    [formatter setTimeStyle:NSDateFormatterNoStyle];
    cb(@[[formatter stringFromDate:self.docReader.license.expiryDate]]);
}

RCT_EXPORT_METHOD(getLicenseCountryFilter:(RCTResponseSenderBlock)cb )
{
    cb(@[[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:self.docReader.license.countryFilter options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding]]);
}

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

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

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

RCT_EXPORT_METHOD(getAvailableScenarios:(RCTResponseSenderBlock)cb )
{
    NSMutableArray *availableScenarios = [[NSMutableArray alloc] init];
    for(RGLScenario *scenario in [self.docReader availableScenarios]){
        [availableScenarios addObject:[JsonConstructor generateScenario:scenario]];
    }
    cb(@[[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:availableScenarios options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding]]);
}

@end
