#import "RNScanbotBarcodeScannerViewControllerWrapper.h"


@implementation RNScanbotBarcodeScannerViewControllerWrapper

+ (SBSDKBarcodeScannerViewController * _Nonnull)initController {

    SBSDKBarcodeScannerViewController *scannerViewController = [[SBSDKBarcodeScannerViewController alloc] init];
    scannerViewController.generalConfiguration = [SBSDKBaseScannerGeneralConfiguration defaultConfiguration];
    scannerViewController.zoomConfiguration = [SBSDKBaseScannerZoomConfiguration defaultConfiguration];
    scannerViewController.energyConfiguration = [SBSDKBaseScannerEnergyConfiguration defaultConfiguration];

    SBSDKBaseScannerViewFinderConfiguration *finderConfig = [SBSDKBaseScannerViewFinderConfiguration defaultConfiguration];
    finderConfig.backgroundColor = [UIColor fromRgbAHex: @"#000000A9"];
    finderConfig.lineColor = [UIColor fromRgbAHex: @"#ffffffff"];
    scannerViewController.viewFinderConfiguration = finderConfig;

    //DEFAULTS
    scannerViewController.trackingOverlayController.configuration.polygonStyle.polygonBackgroundColor = [self uiColorToUiColorWithTransparentAlpha: [UIColor fromRgbAHex: @"#00CFA633"]];
    scannerViewController.trackingOverlayController.configuration.polygonStyle.polygonBackgroundSelectedColor = [UIColor fromRgbAHex: @"#00CFA633"];
    scannerViewController.trackingOverlayController.configuration.polygonStyle.polygonColor = [UIColor fromRgbAHex: @"#00CFA6CC"];
    scannerViewController.trackingOverlayController.configuration.polygonStyle.polygonSelectedColor = [UIColor fromRgbAHex: @"#00CFA6CC"];
    scannerViewController.trackingOverlayController.configuration.textStyle.textColor = [UIColor fromRgbAHex: @"#000000"];
    scannerViewController.trackingOverlayController.configuration.textStyle.selectedTextColor = [UIColor fromRgbAHex: @"#000000"];
    scannerViewController.trackingOverlayController.configuration.textStyle.textBackgroundColor = [UIColor fromRgbAHex: @"#00CFA6CC"];
    scannerViewController.trackingOverlayController.configuration.textStyle.textBackgroundSelectedColor = [UIColor fromRgbAHex: @"#00CFA6CC"];

    return scannerViewController;
}

+ (void)setFlashEnabled:(SBSDKBarcodeScannerViewController * _Nonnull)controller value:(BOOL)value {
    controller.isFlashLightEnabled = value;
}

+ (void)setFinderEnabled:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config value:(BOOL)value {
    config.isViewFinderEnabled = value;
}

+ (void)setFinderStrokeWidth:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config value:(int)value {
    config.lineWidth = value;
}

+ (void)setFinderStrokeColor:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config value:(UIColor * _Nullable)value {
    config.lineColor = value != nil ? value : [UIColor fromRgbAHex: @"#ffffffff"];
}

+ (void)setFinderOverlayColor:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config value:(UIColor * _Nullable)value {
    config.backgroundColor = value != nil ? value : [UIColor fromRgbAHex: @"#000000A9"];
}

+ (void)setFinderInset:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config
                   top:(float)top
                  left:(float)left
                bottom:(float)bottom
                 right:(float)right {
    config.minimumInset = UIEdgeInsetsMake(top, left, bottom, right);
}

+ (void)setFinderRequiredAspectRatios:(SBSDKBaseScannerViewFinderConfiguration * _Nonnull)config
                                width:(double)width
                               height:(double)height {
    config.aspectRatio = [[SBSDKAspectRatio alloc] initWithWidth:width andHeight:height];
}

+ (void)setCameraZoomFactor:(SBSDKBaseScannerZoomConfiguration * _Nonnull)config value:(float)value {
    config.initialZoomFactor = (value*100)/100;
}

+ (void)setCameraZoomRange:(SBSDKBaseScannerZoomConfiguration * _Nonnull)config minZoom:(float)minZoom maxZoom:(float)maxZoom{
    config.zoomRange =  [[SBSDKZoomRange alloc] initWithMinZoom:minZoom andMaxZoom:maxZoom];
}

+ (void)setCameraDevice:(SBSDKBarcodeScannerViewController * _Nonnull)controller value:(NSString * _Nullable)value {
    SBSDKCameraDevice *cameraConfig = value != NULL ? [SBSDKCameraDevice fromString:value] : NULL;

    if (cameraConfig != NULL) {
        controller.cameraDevice = cameraConfig;
    } else {
        controller.cameraDevice = [SBSDKCameraDevice defaultBackFacingCamera];
    }
}

+ (void)setMinFocusDistanceLock:(SBSDKBarcodeScannerViewController * _Nonnull)controller value:(BOOL)value {
    if(value){
        [controller beginFocusLockAtLensPosition:0.0f];
    } else {
        [controller endFocusLock];
    }
}

+ (void)setLowPowerMode:(SBSDKBarcodeScannerViewController * _Nonnull)controller value:(BOOL)value {
    if(value){
        if(!controller.isEnergySavingActive) [controller startEnergySaving];
    } else {
        if(controller.isEnergySavingActive) [controller endEnergySaving];
    }
}

+ (void)setMaximumTextLenght:(SBSDKBarcodeAdditionalParameters * _Nonnull)config value:(int)value {
    config.maximumTextLength = value;
}

+ (void)setMinimumTextLenght:(SBSDKBarcodeAdditionalParameters * _Nonnull)config value:(int)value {
    config.minimumTextLength = value;
}

+ (void)setMinimum1DBarcodesQuietZone:(SBSDKBarcodeAdditionalParameters * _Nonnull)config value:(int)value {
    config.minimum1DBarcodesQuietZone = value;
}

+ (void)setStripCheckDigits:(SBSDKBarcodeAdditionalParameters * _Nonnull)config value:(BOOL)value {
    config.stripCheckDigits = value;
}

+ (void)setBarcodeFormats:(SBSDKBarcodeScannerViewController * _Nonnull)controller acceptedBarcodeTypes:(NSArray<SBSDKBarcodeType *> * _Nonnull)acceptedBarcodeTypes {
    controller.acceptedBarcodeTypes = acceptedBarcodeTypes;
}

+ (void)setDocumentFormats:(SBSDKBarcodeScannerViewController * _Nonnull)controller acceptedDocumentTypes:(NSArray<SBSDKBarcodeDocumentRootType *> * _Nonnull)acceptedDocumentTypes {
    controller.acceptedDocumentTypes = acceptedDocumentTypes;
}

+ (void)setEngineMode:(SBSDKBarcodeScannerViewController * _Nonnull)controller engineMode:(SBSDKBarcodeEngineMode)engineMode {
    controller.engineMode = engineMode;
}

+ (void)setBarcodeExtensionFilter:(SBSDKBarcodeScannerViewController * _Nonnull)controller filter:(SBSDKBarcodesExtensionFilter)filter {
    controller.extensionFilter = filter;
}

+ (void)setGS1HandlingMode:(SBSDKBarcodeAdditionalParameters * _Nonnull)config gs1HandlingMode:(SBSDKGS1Handling)gs1HandlingMode {
    config.gs1Handling = gs1HandlingMode;
}

+ (void)setMsiPlesseyChecksumAlgorithm:(SBSDKBarcodeAdditionalParameters * _Nonnull)config msiPlesseyChecksumAlgorithm:(SBSDKBarcodeMSIPlesseyChecksumAlgorithm)msiPlesseyChecksumAlgorithm {
    config.msiPlesseyChecksumAlgorithm = msiPlesseyChecksumAlgorithm;
}

+ (void)freezeCamera:(SBSDKBarcodeScannerViewController * _Nonnull)controller {
    [controller freezeCamera];
}

+ (void)unfreezeCamera:(SBSDKBarcodeScannerViewController * _Nonnull)controller {
    [controller unfreezeCamera];
}

+ (NSString *) jsonFromResultOrNil:(NSArray<SBSDKBarcodeScannerResult *> * _Nonnull)codes {
    if(!codes || codes.count == 0) return nil;

    NSDictionary* _Nullable result = [SBBarcodeScannerUtils nativeResultsToDictionary:codes];
    if(result != NULL) {
        NSData *data = [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingFragmentsAllowed error:nil];
        return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }

    return nil;
}

+ (void)setOverlayEnabled:(SBSDKBarcodeScannerViewController *)config value:(BOOL)value {
    config.isTrackingOverlayEnabled = value;
    config.trackingOverlayController.configuration.isSelectable = value;
}

+ (void)setOverlayPolygonColor:(SBSDKBarcodeScannerViewController *)config  value:(UIColor * _Nullable)value {
    config.trackingOverlayController.configuration.polygonStyle.polygonBackgroundColor = [self uiColorToUiColorWithTransparentAlpha:value != nil ? value : [UIColor fromRgbAHex: @"#00CFA633"]];
    config.trackingOverlayController.configuration.polygonStyle.polygonBackgroundSelectedColor = value != nil ? value : [UIColor fromRgbAHex: @"#00CFA633"];
}

+ (void)setOverlayStrokeColor:(SBSDKBarcodeScannerViewController *)config value:(UIColor * _Nullable)value {
    config.trackingOverlayController.configuration.polygonStyle.polygonColor = value != nil ? value : [UIColor fromRgbAHex: @"#00CFA6CC"];
    config.trackingOverlayController.configuration.polygonStyle.polygonSelectedColor = value != nil ? value : [UIColor fromRgbAHex: @"#00CFA6CC"];
}

+ (void)setOverlayTextColor:(SBSDKBarcodeScannerViewController *)config value:(UIColor * _Nullable)value {
    config.trackingOverlayController.configuration.textStyle.textColor = value != nil ? value : [UIColor fromRgbAHex: @"#C81A3CCC"];
    config.trackingOverlayController.configuration.textStyle.selectedTextColor = value != nil ? value : [UIColor fromRgbAHex: @"#C81A3CCC"];
}

+ (void)setOverlayTextContainerColor:(SBSDKBarcodeScannerViewController *)config value:(UIColor * _Nullable)value {
    config.trackingOverlayController.configuration.textStyle.textBackgroundColor = value != nil ? value : [UIColor fromRgbAHex: @"#00CFA6CC"];
    config.trackingOverlayController.configuration.textStyle.textBackgroundSelectedColor = value != nil ? value : [UIColor fromRgbAHex: @"#00CFA6CC"];
}

+ (void)setOverlayTextFormat:(SBSDKBarcodeScannerViewController * _Nonnull)config value:(SBSDKBarcodeOverlayFormat)value {
    config.trackingOverlayController.configuration.textStyle.trackingOverlayTextFormat = value;
}

+ (void)setOverlayAutomaticSelectionEnabled:(SBSDKBarcodeScannerViewController * _Nonnull)config value:(BOOL)value {
    config.trackingOverlayController.configuration.isAutomaticSelectionEnabled = value;
}

+ (void)addBarcodeItemOverlayViewInitialBinderInDictionary:(NSMutableDictionary * _Nullable)dictionary
                                               loadingText:(NSString * _Nullable)loadingText
                                                  barcodes:(NSArray<SBSDKBarcodeScannerResult *> * _Nonnull)barcodes {
    
    if (dictionary != nil) {
        for (SBSDKBarcodeScannerResult* barcode in barcodes) {
            NSString* barcodeItemUuid = [BarcodeItem uuidFor:barcode];

            if ([dictionary objectForKey:barcodeItemUuid] == nil) {
                if(loadingText != nil) {
                    [dictionary setValue:@{@"text": loadingText} forKey:barcodeItemUuid];
                } else {
                    [dictionary setValue:@{} forKey:barcodeItemUuid];
                }
            }
        }
    }
}

+ (void)updateBarcodeItemOverlayViewBinderInDictionary:(NSMutableDictionary * _Nullable)dictionary
                                       barcodeItemUuid:(NSString * _Nonnull)barcodeItemUuid
                          barcodeItemOverlayViewConfigJson:(NSString * _Nonnull)barcodeItemOverlayViewConfigJson {
    
    if (dictionary != nil && [dictionary objectForKey:barcodeItemUuid] != nil) {
        NSError *fjsonError;
        NSData *objectData = [barcodeItemOverlayViewConfigJson dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *bindingPolygonStyleConfig = [NSJSONSerialization JSONObjectWithData:objectData
                                                                                options:NSJSONReadingMutableContainers
                                                                                  error:&fjsonError];
        
        long lastBind = (long)([[NSDate date] timeIntervalSince1970] * 1000.0);
        [bindingPolygonStyleConfig setValue:[NSNumber numberWithLong:lastBind] forKey:@"lastBind"];
      
        [dictionary setObject:bindingPolygonStyleConfig forKey:barcodeItemUuid];
    }
}

+ (SBSDKBarcodeTrackedViewPolygonStyle * _Nonnull) scannedBarcodePolygonStyle:(SBSDKBarcodeScannerResult * _Nonnull)barcode
                                           barcodeItemOverlayViewBinding:(NSDictionary * _Nullable) barcodeItemOverlayViewBinding
                                                         controller:(SBSDKBarcodeScannerViewController* _Nonnull)controller {

    SBSDKBarcodeTrackedViewPolygonStyle *current = controller.trackingOverlayController.configuration.polygonStyle;
    SBSDKBarcodeTrackedViewPolygonStyle *polygon = [[SBSDKBarcodeTrackedViewPolygonStyle alloc] init];

    polygon.polygonColor = current.polygonColor;
    polygon.polygonSelectedColor = current.polygonSelectedColor;
    polygon.polygonBackgroundColor = current.polygonBackgroundColor;
    polygon.polygonBackgroundSelectedColor = current.polygonBackgroundSelectedColor;

    if (barcodeItemOverlayViewBinding != nil) {
        
        if ([self useGeneralSelectionOverlayConfig:barcodeItemOverlayViewBinding]) {
            return polygon;
        }
        
        NSString* strokeColor = [barcodeItemOverlayViewBinding valueForKey:@"strokeColor"];
        if(strokeColor != nil) {
            polygon.polygonColor = [UIColor fromRgbAHex:strokeColor];
            polygon.polygonSelectedColor = [UIColor fromRgbAHex:strokeColor];
        }
        
        NSString* polygonColor = [barcodeItemOverlayViewBinding valueForKey:@"polygonColor"];
        if(polygonColor != nil) {
            polygon.polygonBackgroundColor = [self uiColorToUiColorWithTransparentAlpha:[UIColor fromRgbAHex:polygonColor]]; // To make it like Android
            polygon.polygonBackgroundSelectedColor = [UIColor fromRgbAHex:polygonColor];
        }
    }

    return polygon;

}

+ (SBSDKBarcodeTrackedViewTextStyle * _Nonnull) scannedBarcodeOverlayViewTextStyle:(SBSDKBarcodeScannerResult * _Nonnull)barcode
                                                     barcodeItemOverlayViewBinding:(NSDictionary * _Nullable) barcodeItemOverlayViewBinding
                                                             controller:(SBSDKBarcodeScannerViewController* _Nonnull)controller {

    SBSDKBarcodeTrackedViewTextStyle *current = controller.trackingOverlayController.configuration.textStyle;
    SBSDKBarcodeTrackedViewTextStyle *text = [[SBSDKBarcodeTrackedViewTextStyle alloc] init];

    text.textColor = current.textColor;
    text.textBackgroundColor = current.textBackgroundColor;
    text.selectedTextColor = current.selectedTextColor;
    text.textBackgroundSelectedColor = current.textBackgroundSelectedColor;
    text.trackingOverlayTextFormat = current.trackingOverlayTextFormat;

    if (barcodeItemOverlayViewBinding != nil) {
        
        if ([self useGeneralSelectionOverlayConfig:barcodeItemOverlayViewBinding]) {
            return text;
        }

        NSString* textColor = [barcodeItemOverlayViewBinding valueForKey:@"textColor"];
        if(textColor != nil) {
            text.textColor = [UIColor fromRgbAHex:textColor];
            text.selectedTextColor = [UIColor fromRgbAHex:textColor];
        }
        
        NSString* textContainerColor = [barcodeItemOverlayViewBinding valueForKey:@"textContainerColor"];
        if(textContainerColor != nil) {
            text.textBackgroundColor = [UIColor fromRgbAHex:textContainerColor];
            text.textBackgroundSelectedColor = [UIColor fromRgbAHex:textContainerColor];
        }
    }
    
    return text;
}

+ (NSString * _Nonnull) scannedBarcodeOverlayViewText:(NSString * _Nonnull)barcodeItemUuid
                                       proposedString:(NSString * _Nonnull)proposedString
                        barcodeItemOverlayViewBinding:(NSDictionary * _Nullable) barcodeItemOverlayViewBinding {
    
    NSString * _Nonnull resultText = proposedString;
    
    if(barcodeItemOverlayViewBinding != nil) {
        
        NSString* bindedText = [barcodeItemOverlayViewBinding valueForKey:@"text"];
        if(bindedText != nil) {
            resultText = bindedText;
        } else {
            resultText = proposedString;
        }
    }
    
    return resultText;
}

+ (BOOL) useGeneralSelectionOverlayConfig: (NSDictionary * _Nonnull) barcodeItemOverlayViewBinding {
    NSNumber* _Nullable refreshRate = [barcodeItemOverlayViewBinding valueForKey:@"refreshRate"];
    NSNumber* _Nullable lastBind = [barcodeItemOverlayViewBinding valueForKey:@"lastBind"];
    
    long currentTimeInMs = (long)([[NSDate date] timeIntervalSince1970] * 1000.0);
    
    return (refreshRate != nil  && refreshRate.intValue > 0) &&
           (lastBind != nil && lastBind.longValue > 0) &&
           (currentTimeInMs - lastBind.longValue >= refreshRate.intValue);
}

+ (UIColor * _Nonnull) uiColorToUiColorWithTransparentAlpha: (UIColor * _Nonnull) originalColor {
    CGFloat red,green,blue,alpha;
    
    [originalColor getRed:&red green:&green blue:&blue alpha:&alpha];
    
    return [UIColor colorWithRed:red green:green blue:blue alpha:(alpha * 0.2)];
}

@end
