#import "GBTheme.h"
#import "GBVerticalLayout.h"
#import "GBHorizontalLayout.h"
#import "GBBackgroundView.h"

@interface GBLazyObject : NSProxy
@end

@implementation GBLazyObject
{
    id _target;
    id (^_constructor)(void);
}


- (instancetype)initWithConstructor:(id (^)(void))constructor
{
    _constructor = constructor;
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    if (GB_likely(!_target)) {
        _target = _constructor();
        _constructor = nil;
    }
    return [_target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    if (GB_likely(!_target)) {
        _target = _constructor();
        _constructor = nil;
    }
    invocation.target = _target;
    [invocation invoke];
}

- (instancetype)self
{
    if (GB_likely(!_target)) {
        _target = _constructor();
        _constructor = nil;
    }
    return _target;
}

@end

#define MakeColor(r, g, b) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:1.0]

__attribute__((objc_direct_members))
@implementation GBTheme
{
    NSDictionary<NSString *, UIImage *> *_imageOverrides;
    UIImage *_horizontalPreview;
    UIImage *_verticalPreview;
}


// Assumes the image has a purple hue
+ (UIImage *)_recolorImage:(UIImage *)image withColor:(UIColor *)color
{
    double scale = image.scale;
    
    image = [UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationUp];

    CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorMatrix"];
    double r, g, b;
    [color getRed:&r green:&g blue:&b alpha:NULL];
    
    [filter setDefaults];
    [filter setValue:ciImage forKey:@"inputImage"];
    
    [filter setValue:[CIVector vectorWithX:r * 1.34  Y:1 - r Z:0 W:0] forKey:@"inputRVector"];
    [filter setValue:[CIVector vectorWithX:g * 1.34  Y:1 - g Z:0 W:0] forKey:@"inputGVector"];
    [filter setValue:[CIVector vectorWithX:b * 1.34  Y:1 - b Z:0 W:0] forKey:@"inputBVector"];
    
    [filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"];
    

    CIContext *context = [CIContext context];
    CGImageRef cgImage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
    image = [UIImage imageWithCGImage:cgImage scale:scale orientation:0];
    CGImageRelease(cgImage);

    return image;
}

+ (UIImage *)recolorImage:(UIImage *)image withColor:(UIColor *)color
{
    return (id)[[GBLazyObject alloc] initWithConstructor:^id{
        return [self _recolorImage:image withColor:color];
    }];
}

- (instancetype)initDefaultTheme
{
    self = [super init];
    
    _brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
    _backgroundGradientTop = [UIColor colorWithRed:192 / 255.0 green:195 / 255.0 blue:199 / 255.0 alpha:1.0];
    _backgroundGradientBottom = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0];
    
    _bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
    _bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
    
    _name = @"SameBoy";
    
    return self;
}

- (void)setupBackgroundWithColor:(uint32_t)color
{
    uint8_t r = color >> 16;
    uint8_t g = color >> 8;
    uint8_t b = color;
    
    _backgroundGradientTop = MakeColor(r, g, b);
    _backgroundGradientBottom = [UIColor colorWithRed:pow(r / 255.0, 1.125) green:pow(g / 255.0, 1.125) blue:pow(b / 255.0, 1.125) alpha:1.0];
}

- (void)setupButtonsWithColor:(UIColor *)color
{
    _imageOverrides = @{
        @"button": [GBTheme recolorImage:[UIImage imageNamed:@"button"] withColor:color],
        @"buttonPressed": [GBTheme recolorImage:[UIImage imageNamed:@"buttonPressed"] withColor:color],
        
        @"dpad": [GBTheme recolorImage:[UIImage imageNamed:@"dpad-tint"] withColor:color],
        @"swipepad": [GBTheme recolorImage:[UIImage imageNamed:@"swipepad-tint"] withColor:color],
        
        @"button2": [GBTheme recolorImage:[UIImage imageNamed:@"button2-tint"] withColor:color],
        @"button2Pressed": [GBTheme recolorImage:[UIImage imageNamed:@"button2Pressed-tint"] withColor:color],
    };
}

- (instancetype)initDarkTheme
{
    self = [super init];
    
    [self setupBackgroundWithColor:0x181c23];

    _brandColor = [UIColor colorWithRed:0 / 255.0 green:70 / 255.0 blue:141 / 255.0 alpha:1.0];
    _bezelsGradientTop = [UIColor colorWithWhite:53 / 255.0 alpha:1.0];
    _bezelsGradientBottom = [UIColor colorWithWhite:45 / 255.0 alpha:1.0];
    
    [self setupButtonsWithColor:MakeColor(0x08, 0x0c, 0x12)];

    _name = @"SameBoy Dark";
    
    return self;
}


- (UIColor *)buttonColor
{
    double r, g, b;
    [_brandColor getRed:&r green:&g blue:&b alpha:NULL];
    if (r == 1.0 && g == 1.0 && b == 1.0) {
        return _backgroundGradientTop;
    }
    return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
}

- (bool)isDark
{
    double r, g, b;
    [_backgroundGradientTop getRed:&r green:&g blue:&b alpha:NULL];
    if (r > 0.25) return false;
    if (g > 0.25) return false;
    if (b > 0.25) return false;
    return true;
}

- (UIImage *)imageNamed:(NSString *)name
{
    UIImage *ret = _imageOverrides[name].self ?: [UIImage imageNamed:name];
    if (!ret) {
        if  ([name isEqual:@"buttonA"] || [name isEqual:@"buttonB"]) {
            return [self imageNamed:@"button"];
        }
        if  ([name isEqual:@"buttonAPressed"] || [name isEqual:@"buttonBPressed"]) {
            return [self imageNamed:@"buttonPressed"];
        }
    }
    return ret;
}

- (UIImage *)horizontalPreview
{
    if (_horizontalPreview) return _horizontalPreview;
    _renderingPreview = true;
    GBLayout *layout = [[GBHorizontalLayout alloc] initWithTheme:self cutoutOnRight:false];
    _renderingPreview = false;
    GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
    [view enterPreviewMode:false];
    view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
    view.layout = layout;
    view.bounds = CGRectMake(0, 0,
                             MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
                             MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
        view.bounds.size.height / 8,
    }];
    return _horizontalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
        CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
        [view.layer renderInContext:rendererContext.CGContext];
    }];
}

- (UIImage *)verticalPreview
{
    if (_verticalPreview) return _verticalPreview;
    _renderingPreview = true;
    GBLayout *layout = [[GBVerticalLayout alloc] initWithTheme:self];
    _renderingPreview = false;
    GBBackgroundView *view = [[GBBackgroundView alloc] initWithLayout:layout];
    [view enterPreviewMode:false];
    view.usesSwipePad = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipePad"];
    view.layout = layout;
    view.bounds = CGRectMake(0, 0,
                             MIN(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height),
                             MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:(CGSize){view.bounds.size.width / 8,
                                                                                               view.bounds.size.height / 8,
    }];
    return _verticalPreview = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
        CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1 / 8.0, 1 / 8.0);
        [view.layer renderInContext:rendererContext.CGContext];
    }];
}

@end
