#import "SvgUrlView.h"
#import <SVGKit/SVGKit.h>
#import <react/renderer/components/SvgUrlViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/SvgUrlViewSpec/Props.h>
#import <react/renderer/components/SvgUrlViewSpec/RCTComponentViewHelpers.h>

#if __has_include("RCTFabricComponentsPlugins.h")
#import "RCTFabricComponentsPlugins.h"
#endif

using namespace facebook::react;

@interface SvgUrlView () <RCTSvgUrlViewViewProtocol>
@end

@implementation SvgUrlView {
    SVGKFastImageView *_svgView;
    UIView *_skeletonView;
    UIImageView *_placeholderView;
    CAGradientLayer *_skeletonGradient;
    NSString *_lastLoadedURL;
    BOOL _showSkeleton;
    UIImage *_placeholderImage;
    UIImage *_failedPlaceholderImage;
}

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

#pragma mark - Cache

+ (NSCache<NSString *, SVGKImage *> *)imageCache {
    static NSCache<NSString *, SVGKImage *> *cache = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cache = [[NSCache alloc] init];
        cache.countLimit = 50;
    });
    return cache;
}

#pragma mark - Init

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.contentView = [[UIView alloc] init];
        self.contentView.backgroundColor = [UIColor clearColor];
        [self addSubview:self.contentView];

        // Skeleton view
        _skeletonView = [[UIView alloc] init];
        _skeletonView.backgroundColor = [UIColor clearColor];
        _skeletonView.layer.cornerRadius = 4;
        _skeletonView.clipsToBounds = YES;
        _skeletonView.hidden = YES;
        [self.contentView addSubview:_skeletonView];

        _skeletonGradient = [CAGradientLayer layer];
        _skeletonGradient.colors = @[
            (id)[UIColor colorWithWhite:0.85 alpha:1.0].CGColor,
            (id)[UIColor colorWithWhite:0.75 alpha:1.0].CGColor,
            (id)[UIColor colorWithWhite:0.85 alpha:1.0].CGColor
        ];
        _skeletonGradient.startPoint = CGPointMake(0.0, 0.5);
        _skeletonGradient.endPoint = CGPointMake(1.0, 0.5);
        _skeletonGradient.locations = @[@0.0, @0.5, @1.0];
        [_skeletonView.layer addSublayer:_skeletonGradient];

        // Placeholder image view
        _placeholderView = [[UIImageView alloc] init];
        _placeholderView.contentMode = UIViewContentModeScaleAspectFit;
        _placeholderView.hidden = YES;
        [self.contentView addSubview:_placeholderView];

        _showSkeleton = YES;
    }
    return self;
}

#pragma mark - Update Props

- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
    auto newPropsCast = std::static_pointer_cast<const SvgUrlViewProps>(props);

    // Set URL
    if (_url == nil || !newPropsCast->url.empty()) {
        self.url = [NSString stringWithUTF8String:newPropsCast->url.c_str()];
    }

    // Width / Height
    if (newPropsCast->width > 0) {
        self.width = @(newPropsCast->width);
    }
    if (newPropsCast->height > 0) {
        self.height = @(newPropsCast->height);
    }

    // Skeleton flag
    _showSkeleton = newPropsCast->showSkeleton;

    // Placeholder image (local or remote)
    _placeholderImage = [self loadImageFromString:newPropsCast->placeholder];

    // Failed placeholder (local or remote)
    _failedPlaceholderImage = [self loadImageFromString:newPropsCast->failedPlaceholder];

    // Load SVG with updated props
    [self loadSVGWithShowSkeleton:_showSkeleton placeholder:_placeholderImage failedPlaceholder:_failedPlaceholderImage];

    [super updateProps:props oldProps:oldProps];
}

#pragma mark - Helpers to load images

- (UIImage *)loadImageFromString:(std::string)str {
    if (str.empty()) return nil;

    NSString *urlStr = [NSString stringWithUTF8String:str.c_str()];
    UIImage *image = nil;

    if ([urlStr hasPrefix:@"http"]) {
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]];
        if (data) {
            image = [UIImage imageWithData:data];
        }
    } else {
        image = [UIImage imageNamed:urlStr]; // Local asset
    }
    return image;
}

#pragma mark - Setters

- (void)setUrl:(NSString *)url {
    if (!url || [_url isEqualToString:url]) return;
    _url = [url copy];
}

- (void)setWidth:(NSNumber *)width {
    _width = width;
    [self updateLayoutIfNeeded];
}

- (void)setHeight:(NSNumber *)height {
    _height = height;
    [self updateLayoutIfNeeded];
}

#pragma mark - Load SVG

- (void)loadSVGWithShowSkeleton:(BOOL)showSkeleton placeholder:(UIImage *)placeholder failedPlaceholder:(UIImage *)failedPlaceholder {
    if (!_url || _url.length == 0) return;
    if ([_url isEqualToString:_lastLoadedURL]) {
        [self updateLayoutIfNeeded];
        return;
    }
    _lastLoadedURL = [_url copy];

    [_svgView removeFromSuperview];
    _svgView = nil;

    // Show skeleton or placeholder
    if (placeholder) {
        _placeholderView.hidden = NO;
        _placeholderView.image = placeholder;
        _skeletonView.hidden = YES;
    } else if (showSkeleton) {
        _skeletonView.hidden = NO;
        _placeholderView.hidden = YES;
        [self startSkeletonAnimation];
    } else {
        _skeletonView.hidden = YES;
        _placeholderView.hidden = YES;
    }

    // Try cache
    SVGKImage *cachedImage = [[[self class] imageCache] objectForKey:_url];
    if (cachedImage) {
        [self renderSVG:cachedImage];
        return;
    }

    // Fetch SVG from network
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSURL *urlObj = [NSURL URLWithString:self->_url];
        if (!urlObj) return;

        NSData *data = [NSData dataWithContentsOfURL:urlObj];
        SVGKImage *svgImage = nil;
        if (data) {
            svgImage = [SVGKImage imageWithData:data];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            if (svgImage) {
                [[[self class] imageCache] setObject:svgImage forKey:self->_url];
                [self renderSVG:svgImage];
            } else if (failedPlaceholder) {
                _placeholderView.hidden = NO;
                _placeholderView.image = failedPlaceholder;
                _skeletonView.hidden = YES;
                [self stopSkeletonAnimation];
            } else {
                _skeletonView.hidden = YES;
                _placeholderView.hidden = YES;
                [self stopSkeletonAnimation];
            }
        });
    });
}

#pragma mark - Render SVG

- (void)renderSVG:(SVGKImage *)svgImage {
    if (!svgImage) return;

    [_svgView removeFromSuperview];
    _svgView = [[SVGKFastImageView alloc] initWithSVGKImage:svgImage];
    _svgView.backgroundColor = [UIColor clearColor];
    _svgView.clipsToBounds = YES;
    [self.contentView addSubview:_svgView];

    // Hide skeleton / placeholder
    _placeholderView.hidden = YES;
    _skeletonView.hidden = YES;
    [self stopSkeletonAnimation];

    [self updateLayoutIfNeeded];
}

#pragma mark - Skeleton Animation

- (void)startSkeletonAnimation {
    [_skeletonGradient removeAllAnimations];
    CABasicAnimation *shimmerAnimation = [CABasicAnimation animationWithKeyPath:@"locations"];
    shimmerAnimation.fromValue = @[@0.0, @0.0, @0.25];
    shimmerAnimation.toValue   = @[@0.75, @1.0, @1.0];
    shimmerAnimation.duration = 1.0;
    shimmerAnimation.repeatCount = HUGE_VALF;
    [_skeletonGradient addAnimation:shimmerAnimation forKey:@"shimmerAnimation"];
}

- (void)stopSkeletonAnimation {
    [_skeletonGradient removeAllAnimations];
}

#pragma mark - Layout

- (void)updateLayoutIfNeeded {
    CGFloat targetWidth = self.width ? [self.width floatValue] : (_svgView ? _svgView.image.size.width : 100);
    CGFloat targetHeight = self.height ? [self.height floatValue] : (_svgView ? _svgView.image.size.height : 100);

    _skeletonView.frame = CGRectMake(0, 0, targetWidth, targetHeight);
    _skeletonGradient.frame = _skeletonView.bounds;
    _placeholderView.frame = CGRectMake(0, 0, targetWidth, targetHeight);

    if (!_svgView) return;

    CGFloat aspectRatio = _svgView.image.size.width / _svgView.image.size.height;
    CGFloat finalWidth, finalHeight;

    if (targetWidth / targetHeight > aspectRatio) {
        finalHeight = targetHeight;
        finalWidth = finalHeight * aspectRatio;
    } else {
        finalWidth = targetWidth;
        finalHeight = finalWidth / aspectRatio;
    }

    CGFloat originX = (targetWidth - finalWidth) / 2.0;
    CGFloat originY = (targetHeight - finalHeight) / 2.0;

    _svgView.frame = CGRectMake(originX, originY, finalWidth, finalHeight);
}

Class<RCTComponentViewProtocol> SvgUrlViewCls(void) {
    return SvgUrlView.class;
}

@end

#ifdef RCT_REGISTER_COMPONENT_VIEW
RCT_REGISTER_COMPONENT_VIEW(SvgUrlView)
#endif
