#ifdef RCT_NEW_ARCH_ENABLED
#import "RNScanbotCroppingView.h"

#import <ScanbotSDK/ScanbotSDK-Swift.h>
#import <ScanbotSDKNativeWrapper/ScanbotSDKNativeWrapper-Swift.h>

#if __has_include(<RNScanbotSDK/RNScanbotSDK-Swift.h>)
#import <RNScanbotSDK/RNScanbotSDK-Swift.h>
#else
#import "RNScanbotSDK-Swift.h"
#endif

using namespace facebook::react;

@interface RNScanbotCroppingView() <RCTScanbotCroppingViewViewProtocol, RNScanbotCroppingViewEventsDelegate>
@property (strong, nonatomic) RNScanbotCroppingViewController *scannerViewController;
@property (nonatomic) BOOL attached;
@end

@implementation RNScanbotCroppingView

+ (ComponentDescriptorProvider)componentDescriptorProvider {
    return concreteComponentDescriptorProvider<ScanbotCroppingViewComponentDescriptor>();
}

static const auto defaultProps = std::make_shared<const ScanbotCroppingViewProps>();

- (instancetype)initWithFrame:(CGRect)frame {
    
    if (self = [super initWithFrame:frame]) {
        _props = defaultProps;
        self.attached = false;
        [self setBackgroundColor:[UIColor blackColor]];
        
        self.scannerViewController = [[RNScanbotCroppingViewController alloc] init];
        self.scannerViewController.delegate = self;
    }
    return self;
}

- (void)didMoveToWindow {
    [super didMoveToWindow];
    
    if(self.window && !self.attached){
        [self.scannerViewController attachControllerWithParentViewController:[self reactViewController] inView:self];
        self.attached = true;
    }
}

-(void) prepareForRecycle {
    self.scannerViewController.delegate = nil;
    [self.scannerViewController detachController];
    self.scannerViewController = nil;
    
    self.attached = false;
    _props = defaultProps;
    [super prepareForRecycle];
}

-(void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps {
    
    if(self.scannerViewController == nil){
        self.scannerViewController = [[RNScanbotCroppingViewController alloc] init];
        self.scannerViewController.delegate = self;
    }
    
    const auto &oldViewProps = *std::static_pointer_cast<ScanbotCroppingViewProps const>(_props);
    const auto &newViewProps = *std::static_pointer_cast<ScanbotCroppingViewProps const>(props);
    
    // MARK: Sources
    if(![self compareStringProps:oldViewProps.imageFileSrc withString:newViewProps.imageFileSrc]){
        [self.scannerViewController setImageFileSrc:[self toNSString:newViewProps.imageFileSrc] attached:self.attached];
    }
    if(![self compareStringProps:oldViewProps.imageRefSrc withString:newViewProps.imageRefSrc]){
        [self.scannerViewController setImageRefSrc:[self toNSString:newViewProps.imageRefSrc] attached:self.attached];
    }
    // MARK: Polygon configuration
    if(oldViewProps.edgeColor != newViewProps.edgeColor){
        [self.scannerViewController setEdgeColor:RCTUIColorFromSharedColor(newViewProps.edgeColor)];
    }
    if(oldViewProps.edgeLineWidth != newViewProps.edgeLineWidth){
        [self.scannerViewController setEdgeLineWidth:@(newViewProps.edgeLineWidth)];
    }
    if(oldViewProps.edgeColorOnLine != newViewProps.edgeColorOnLine){
        [self.scannerViewController setEdgeColorOnLine:RCTUIColorFromSharedColor(newViewProps.edgeColorOnLine)];
    }
    if(oldViewProps.anchorPointsColor != newViewProps.anchorPointsColor){
        [self.scannerViewController setAnchorPointsColor:RCTUIColorFromSharedColor(newViewProps.anchorPointsColor)];
    }

    [super updateProps:props oldProps:oldProps];
}

//MARK: Commands

- (void)handleCommand:(nonnull const NSString *)commandName args:(nonnull const NSArray *)args {
    RCTScanbotCroppingViewHandleCommand(self, commandName, args);
}

- (void)detectPolygon {
    [self.scannerViewController detectPolygon];
}

- (void)resetPolygon {
    [self.scannerViewController resetPolygon];
}

- (void)extractCroppedArea {
    [self.scannerViewController extractCroppedArea];
}

- (void)rotate:(BOOL)clockwise {
    [self.scannerViewController rotate:clockwise];
}

//MARK: Delegate Events

- (void)onError:(NSString * _Nonnull)errorMessage errorCode:(NSInteger)errorCode {
    if (_eventEmitter == nullptr) return;
    
    const auto &eventEmitter = std::dynamic_pointer_cast<const facebook::react::ScanbotCroppingViewEventEmitter>(_eventEmitter);
    
    eventEmitter -> onError(facebook::react::ScanbotCroppingViewEventEmitter::OnError{
        .message = RCTStringFromNSString(errorMessage),
        .code = (int)errorCode
    });
}

- (void)onExtractCroppingArea:(NSString * _Nonnull)json {
    if (_eventEmitter == nullptr) return;
    
    const auto &eventEmitter = std::dynamic_pointer_cast<const facebook::react::ScanbotCroppingViewEventEmitter>(_eventEmitter);
    
    eventEmitter -> onCroppedAreaResult(facebook::react::ScanbotCroppingViewEventEmitter::OnCroppedAreaResult{
        .result = std::string([json UTF8String])
    });
}

//MARK: Utils

- (BOOL)compareStringProps:(std::string)oldProp withString:(std::string)newProp {
    return [[self toNSString:oldProp] isEqualToString: [self toNSString:newProp]];
}

- (NSString*) toNSString:(std::string) value {
    return [[NSString alloc] initWithCString:value.c_str() encoding:NSUTF8StringEncoding];
}

Class <RCTComponentViewProtocol> ScanbotCroppingViewCls(void){
    return RNScanbotCroppingView.class;
}

@end

#endif
