#import "RCTDefaultReactNativeFactoryDelegate.h"
#import "MarkerView.h"
#import "DgisMapView.h"
#import <Dgis-Swift.h>

#import <React/RCTConversions.h>
#import <React/RCTFabricComponentsPlugins.h>

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

using namespace facebook::react;

@interface MarkerView () <RCTMarkerViewViewProtocol>
@end

@implementation MarkerView {
    UIImage *_loadedIcon;
}

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

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        static const auto defaultProps = std::make_shared<const MarkerViewProps>();
        _props = defaultProps;
        _iconOpacity = 1.0;
        _iconWidth = 24.0;
        _anchorX = 0.5;
        _anchorY = 0.5;
    }
    return self;
}

- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps {
    const auto &oldViewProps = *std::static_pointer_cast<MarkerViewProps const>(_props);
    const auto &newViewProps = *std::static_pointer_cast<MarkerViewProps const>(props);

    if (oldViewProps.point.latitude != newViewProps.point.latitude ||
        oldViewProps.point.longitude != newViewProps.point.longitude) {
        _latitude = newViewProps.point.latitude;
        _longitude = newViewProps.point.longitude;
        [self updatePosition];
    }
    if (oldViewProps.iconSource != newViewProps.iconSource) {
        [self setIconSource:[NSString stringWithUTF8String:newViewProps.iconSource.c_str()]];
    }
    if (oldViewProps.iconOpacity != newViewProps.iconOpacity) {
        _iconOpacity = newViewProps.iconOpacity;
        [self updateMarkerOpacity];
    }
    if (oldViewProps.iconWidth != newViewProps.iconWidth) {
        _iconWidth = newViewProps.iconWidth;
        [self updateMarkerWidth];
    }
    if (oldViewProps.anchor.x != newViewProps.anchor.x || oldViewProps.anchor.y != newViewProps.anchor.y) {
        _anchorX = newViewProps.anchor.x;
        _anchorY = newViewProps.anchor.y;
        [self updateMarkerAnchor];
    }
    [super updateProps:props oldProps:oldProps];
}

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

#pragma mark - RCTMarkerViewViewProtocol

- (void)animatedMoveTo:(NSArray *)args {
    if (!args.count) return;
    NSDictionary *params = args[0];
    NSDictionary *coords = params[@"coords"];
    NSNumber *duration = params[@"duration"];
    if (coords) {
        double lat = [coords[@"latitude"] doubleValue];
        double lng = [coords[@"longitude"] doubleValue];
        double dur = duration ? [duration doubleValue] : 300.0;
        [self animatedMoveToLatitude:lat longitude:lng duration:dur];
    }
}

#pragma mark - Public Methods

- (void)initializeMarker {
    if (!self.dgisMapView.mapBridge || self.markerBridge) return;
    DGisMarkerViewBridge *bridge = [self.dgisMapView.mapBridge addMarkerWithLat:_latitude lng:_longitude icon:_loadedIcon anchorX:(float)_anchorX anchorY:(float)_anchorY opacity:(float)_iconOpacity width:(float)_iconWidth];
    if (bridge) {
        self.markerBridge = bridge;
        self.markerId = bridge.markerId;
    }
}

- (void)updatePosition {
    if (!self.markerBridge) return;
    [self.markerBridge updatePositionWithLat:_latitude lng:_longitude];
}

- (void)animatedMoveToLatitude:(double)latitude longitude:(double)longitude duration:(double)duration {
    _latitude = latitude;
    _longitude = longitude;
    [self updatePosition];
}

- (void)emitPressEvent {
    if (_eventEmitter) {
        std::dynamic_pointer_cast<const MarkerViewEventEmitter>(_eventEmitter)->onPress({});
    }
}

#pragma mark - Private Methods

- (void)setIconSource:(NSString *)source {
    _iconSource = [source copy];
    __weak MarkerView *weakSelf = self;
    [[ImageCacheManager sharedInstance] getImageWithSource:source completion:^(UIImage * _Nullable image) {
        if (!image) return;
        MarkerView *strongSelf = weakSelf;
        if (!strongSelf) return;
        strongSelf->_loadedIcon = image;
        if (strongSelf.markerBridge) {
            [strongSelf.markerBridge updateIconWithImage:image];
        }
    }];
}

- (void)updateMarkerOpacity {
    if (self.markerBridge) {
        [self.markerBridge updateOpacityWithOpacity:(float)_iconOpacity];
    }
}

- (void)updateMarkerWidth {
    if (self.markerBridge) {
        [self.markerBridge updateWidthWithWidth:(float)_iconWidth];
    }
}

- (void)updateMarkerAnchor {
    if (self.markerBridge) {
        [self.markerBridge updateAnchorWithX:(float)_anchorX y:(float)_anchorY];
    }
}


- (void)prepareForRecycle {
    [super prepareForRecycle];
    // Reset markerBridge so the marker is recreated with current values when recycled.
    self.markerBridge = nil;
}

@end

Class<RCTComponentViewProtocol> MarkerViewCls(void) {
    return MarkerView.class;
}
