#ifdef RCT_NEW_ARCH_ENABLED
#import "RNScanbotCroppingView.h"

#import <react/renderer/components/RNScanbotScannerViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/RNScanbotScannerViewSpec/EventEmitters.h>
#import <react/renderer/components/RNScanbotScannerViewSpec/Props.h>
#import <react/renderer/components/RNScanbotScannerViewSpec/RCTComponentViewHelpers.h>

#import "RCTFabricComponentsPlugins.h"
#import <React/RCTConversions.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>
@property (strong, nonatomic) RNScanbotCroppingLegacyView *view;
@end

@implementation RNScanbotCroppingView

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

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

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _props = defaultProps;
        
        _view = [[RNScanbotCroppingLegacyView alloc]
                 initWithFrame:frame
                 eventDelegate: [[RNScanbotCroppingViewEventsDelegate alloc] initOnExtractArea:^(NSString *json) { [self onCroppedAreaResultEvent:json];} onError:^(NSString *errorMsg) { [self onErrorEvent:errorMsg]; }]
        ];
        
        self.contentView = _view;
    }
    return self;
}

-(void) prepareForRecycle {
    self.contentView = [[UIView alloc] initWithFrame:self.view.frame];;
    self.view = nil;
    _props = defaultProps;
    [super prepareForRecycle];
}

-(void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps {
    
    if(self.view == nil){
        _view = [[RNScanbotCroppingLegacyView alloc]
                 initWithFrame:self.contentView.frame
                 eventDelegate: [[RNScanbotCroppingViewEventsDelegate alloc] initOnExtractArea:^(NSString *json) { [self onCroppedAreaResultEvent:json];} onError:^(NSString *errorMsg) { [self onErrorEvent:errorMsg]; }]
        ];
        
        self.contentView = _view;
    }
    
    const auto &oldViewProps = *std::static_pointer_cast<ScanbotCroppingViewProps const>(_props);
    const auto &newViewProps = *std::static_pointer_cast<ScanbotCroppingViewProps const>(props);
    
    if(![self compareStringProps:oldViewProps.imageFileSrc withString:newViewProps.imageFileSrc]){
        [self.view setImageFileSrc:[self toNSString:newViewProps.imageFileSrc]];
    }
    if(![self compareStringProps:oldViewProps.imageRefSrc withString:newViewProps.imageRefSrc]){
        [self.view setImageRefSrc:[self toNSString:newViewProps.imageRefSrc]];
    }
    if(oldViewProps.edgeColor != newViewProps.edgeColor){
        [self.view setEdgeColor:RCTUIColorFromSharedColor(newViewProps.edgeColor)];
    }
    if(oldViewProps.edgeLineWidth != newViewProps.edgeLineWidth){
        [self.view setEdgeLineWidth:[NSNumber numberWithDouble:newViewProps.edgeLineWidth]];
    }
    if(oldViewProps.edgeColorOnLine != newViewProps.edgeColorOnLine){
        [self.view setEdgeColorOnLine:RCTUIColorFromSharedColor(newViewProps.edgeColorOnLine)];
    }
    if(oldViewProps.anchorPointsColor != newViewProps.anchorPointsColor){
        [self.view setAnchorPointsColor:RCTUIColorFromSharedColor(newViewProps.anchorPointsColor)];
    }

    [super updateProps:props oldProps:oldProps];
}

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

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

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

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

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

- (void)onCroppedAreaResultEvent:(NSString *) 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])
    });
}

- (void)onErrorEvent:(NSString *) errorMsg {
    if (_eventEmitter == nullptr) return;
    
    const auto &eventEmitter = std::dynamic_pointer_cast<const facebook::react::ScanbotCroppingViewEventEmitter>(_eventEmitter);
    
    eventEmitter -> onError(facebook::react::ScanbotCroppingViewEventEmitter::OnError{
        .result = std::string([errorMsg UTF8String])
    });
}

- (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
