/*
 * Copyright © Dynamsoft Corporation. All rights reserved.
 */

#import "RNDynamsoftCameraViewManager.h"
#import "RNDynamsoftCameraView.h"
#import <DynamsoftCaptureVisionBundle/DynamsoftCaptureVisionBundle.h>
#import <React/RCTUIManager.h>
#import "RNDynamsoftImageSourceAdapter.h"

@interface RNDynamsoftCameraViewManager ()

@property (nonatomic, strong) DSCameraEnhancer *dce;

@end

@implementation RNDynamsoftCameraViewManager {

}

RCT_EXPORT_MODULE(DynamsoftCameraView)

- (instancetype)init
{
    self = [super init];
    if (self) {
        
    }
    return self;
}

- (UIView *)view {
    return [[RNDynamsoftCameraView alloc] init];
}

RCT_EXPORT_VIEW_PROPERTY(visibleLayerIds, NSArray)
RCT_EXPORT_VIEW_PROPERTY(scanRegionMaskVisible, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scanLaserVisible, BOOL)
RCT_EXPORT_VIEW_PROPERTY(torchButton, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(torchButtonVisible, BOOL)
RCT_EXPORT_VIEW_PROPERTY(cameraToggleButton, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(cameraToggleButtonVisible, BOOL)

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(createInstance) {
    RNDynamsoftImageSourceAdapter *rnAdapter = [self.bridge moduleForClass:[RNDynamsoftImageSourceAdapter class]];
    if (self.dce) {
        [rnAdapter.isaDictionary removeObjectForKey:[NSNumber numberWithUnsignedInteger:self.dce.hash].stringValue];
    }
    self.dce = [[DSCameraEnhancer alloc] init];
    NSString *key = [NSNumber numberWithUnsignedInteger:self.dce.hash].stringValue;
    [rnAdapter.isaDictionary setValue:self.dce forKey:key];
    return key;
}

RCT_EXPORT_METHOD(open) {
    [self.dce open];
}

RCT_EXPORT_METHOD(close) {
    [self.dce close];
}

RCT_EXPORT_METHOD(setCameraView:(nullable NSNumber *)tag) {
    if (tag && tag.integerValue != 0) {
        [self trySetCameraViewWithTag:tag attempt:1];
    } else {
        self.dce.cameraView = nil;
    }
}

- (void)trySetCameraViewWithTag:(nonnull NSNumber *)tag attempt:(NSInteger)attempt {
    const NSInteger maxAttempts = 10;
    const NSTimeInterval retryDelay = 0.1; // 100ms

    [self.bridge.uiManager addUIBlock:
     ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
         id view = viewRegistry[tag];
         if (!view || ![view isKindOfClass:[RNDynamsoftCameraView class]]) {
             if (attempt < maxAttempts) {
                 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                     [self trySetCameraViewWithTag:tag attempt:attempt + 1];
                 });
             } else {
                 RCTLogError(@"Cannot find RNDynamsoftCameraView with tag #%@ after %ld attempts", tag, (long)attempt);
             }
         } else {
             self.dce.cameraView = ((RNDynamsoftCameraView *)view).cameraView;
         }
     }];
}

RCT_EXPORT_METHOD(selectCamera:(NSInteger)position) {
    [self.dce selectCameraWithPosition:position completion:nil];
}

RCT_EXPORT_METHOD(getCameraPosition:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    resolve(@([self.dce getCameraPosition]));
}

RCT_EXPORT_METHOD(setFocus:(CGFloat)x y:(CGFloat)y mode:(NSInteger)mode) {
    [self.dce setFocus:CGPointMake(x, y) focusMode:mode];
}

RCT_EXPORT_METHOD(getFocusMode:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    resolve(@([self.dce getFocusMode]));
}

RCT_EXPORT_METHOD(setZoomFactor:(CGFloat)factor) {
    [self.dce setZoomFactor:factor];
}

RCT_EXPORT_METHOD(getZoomFactor:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    resolve(@([self.dce getZoomFactor]));
}

RCT_EXPORT_METHOD(enableEnhancedFeatures:(NSInteger)features) {
    [self.dce enableEnhancedFeatures:features];
}

RCT_EXPORT_METHOD(disableEnhancedFeatures:(NSInteger)features) {
    [self.dce disableEnhancedFeatures:features];
}

RCT_EXPORT_METHOD(setScanRegion:(NSDictionary *)region
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter: (RCTPromiseRejectBlock)reject)
{
    if (region) {
        NSNumber *top = [region valueForKey:@"top"];
        NSNumber *left = [region valueForKey:@"left"];
        NSNumber *right = [region valueForKey:@"right"];
        NSNumber *bottom = [region valueForKey:@"bottom"];
        NSNumber *measuredInPercentage = [region valueForKey:@"measuredInPercentage"];
        if (top && left && right && bottom && measuredInPercentage) {
            DSRect *rect = [[DSRect alloc] init];
            rect.top = top.floatValue;
            rect.left = left.floatValue;
            rect.right = right.floatValue;
            rect.bottom = bottom.floatValue;
            rect.measuredInPercentage = measuredInPercentage.boolValue;
            NSError *error;
            [self.dce setScanRegion:rect error:&error];
            if (error) {
                NSString *code = [NSString stringWithFormat:@"%ld",(long)error.code];
                reject(code, error.localizedDescription, error);
            }
            resolve(@(true));
        }
    } else {
        [self.dce setScanRegion:nil error:nil];
    }
}

RCT_EXPORT_METHOD(getScanRegion:(RCTPromiseResolveBlock)resolve
                  rejecter: (RCTPromiseRejectBlock)reject)
{
    DSRect *rect = [self.dce getScanRegion];
    NSDictionary *dic = @{@"top" : @(rect.top), @"left" : @(rect.left), @"right" : @(rect.right), @"bottom" : @(rect.bottom), @"measuredInPercentage" : @(rect.measuredInPercentage)};
    resolve(dic);
}

RCT_EXPORT_METHOD(turnOnTorch) {
    [self.dce turnOnTorch];
}

RCT_EXPORT_METHOD(turnOffTorch) {
    [self.dce turnOffTorch];
}

RCT_EXPORT_METHOD(beep) {
    [DSFeedback beep];
}

RCT_EXPORT_METHOD(vibrate) {
    [DSFeedback vibrate];
}

RCT_EXPORT_METHOD(setResolution:(NSInteger)resolution) {
    [self.dce setResolution:resolution];
}

@end
