//
//  KBSkinManager.m
//

#import "KBSkinManager.h"
#import <Security/Security.h>
#import "KBConfig.h"

NSString * const KBSkinDidChangeNotification = @"KBSkinDidChangeNotification";
NSString * const KBDarwinSkinChanged = @"com.loveKey.nyx.skin.changed";

static NSString * const kKBSkinService = @"com.loveKey.nyx.skin"; // Keychain service
static NSString * const kKBSkinAccount = @"current";              // Keychain account

@implementation KBSkinTheme

+ (BOOL)supportsSecureCoding { return YES; }

- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.skinId forKey:@"skinId"];
    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeObject:self.keyboardBackground forKey:@"keyboardBackground"];
    [coder encodeObject:self.keyBackground forKey:@"keyBackground"];
    [coder encodeObject:self.keyTextColor forKey:@"keyTextColor"];
    [coder encodeObject:self.keyHighlightBackground forKey:@"keyHighlightBackground"];
    [coder encodeObject:self.accentColor forKey:@"accentColor"];
    if (self.backgroundImageData) {
        [coder encodeObject:self.backgroundImageData forKey:@"backgroundImageData"];
    }
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super init]) {
        _skinId = [coder decodeObjectOfClass:NSString.class forKey:@"skinId"] ?: @"default";
        _name = [coder decodeObjectOfClass:NSString.class forKey:@"name"] ?: @"Default";
        _keyboardBackground = [coder decodeObjectOfClass:UIColor.class forKey:@"keyboardBackground"] ?: [UIColor colorWithWhite:0.95 alpha:1.0];
        _keyBackground = [coder decodeObjectOfClass:UIColor.class forKey:@"keyBackground"] ?: UIColor.whiteColor;
        _keyTextColor = [coder decodeObjectOfClass:UIColor.class forKey:@"keyTextColor"] ?: UIColor.blackColor;
        _keyHighlightBackground = [coder decodeObjectOfClass:UIColor.class forKey:@"keyHighlightBackground"] ?: [UIColor colorWithWhite:0.85 alpha:1.0];
        _accentColor = [coder decodeObjectOfClass:UIColor.class forKey:@"accentColor"] ?: [UIColor colorWithRed:0.77 green:0.93 blue:0.82 alpha:1.0];
        _backgroundImageData = [coder decodeObjectOfClass:NSData.class forKey:@"backgroundImageData"];
    }
    return self;
}

@end

@interface KBSkinManager ()
@property (atomic, strong, readwrite) KBSkinTheme *current;
@end

@implementation KBSkinManager

+ (instancetype)shared {
    static KBSkinManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBSkinManager new]; });
    return m;
}

- (instancetype)init {
    if (self = [super init]) {
        _current = [self p_loadFromKeychain] ?: [self.class defaultTheme];
        // Observe Darwin notification for cross-process updates
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                        (__bridge const void *)(self),
                                        KBSkinDarwinCallback,
                                        (__bridge CFStringRef)KBDarwinSkinChanged,
                                        NULL,
                                        CFNotificationSuspensionBehaviorDeliverImmediately);
    }
    return self;
}

static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    KBSkinManager *self = (__bridge KBSkinManager *)observer;
    [self p_reloadFromKeychainAndBroadcast:YES];
}

- (void)dealloc {
    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), (__bridge CFStringRef)KBDarwinSkinChanged, NULL);
}

#pragma mark - Public

- (BOOL)applyThemeFromJSON:(NSDictionary *)json {
    if (json.count == 0) return NO;
    KBSkinTheme *t = [KBSkinTheme new];
    t.skinId = [json[@"id"] isKindOfClass:NSString.class] ? json[@"id"] : @"custom";
    t.name = [json[@"name"] isKindOfClass:NSString.class] ? json[@"name"] : t.skinId;
    t.keyboardBackground = [self.class colorFromHexString:json[@"background"] defaultColor:[self.class defaultTheme].keyboardBackground];
    t.keyBackground = [self.class colorFromHexString:json[@"key_bg"] defaultColor:[self.class defaultTheme].keyBackground];
    t.keyTextColor = [self.class colorFromHexString:json[@"key_text"] defaultColor:[self.class defaultTheme].keyTextColor];
    t.keyHighlightBackground = [self.class colorFromHexString:json[@"key_highlight"] defaultColor:[self.class defaultTheme].keyHighlightBackground];
    t.accentColor = [self.class colorFromHexString:json[@"accent"] defaultColor:[self.class defaultTheme].accentColor];
    return [self applyTheme:t];
}

- (BOOL)applyTheme:(KBSkinTheme *)theme {
    if (!theme) return NO;
    if ([self p_saveToKeychain:theme]) {
        self.current = theme;
        [[NSNotificationCenter defaultCenter] postNotificationName:KBSkinDidChangeNotification object:nil];
        CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)KBDarwinSkinChanged, NULL, NULL, true);
        return YES;
    }
    return NO;
}

- (void)resetToDefault {
    [self applyTheme:[self.class defaultTheme]];
}

- (BOOL)applyImageSkinWithData:(NSData *)imageData skinId:(NSString *)skinId name:(NSString *)name {
    if (imageData.length == 0) return NO;
    // 构造新主题，继承当前配色作为按键/强调色的默认值
    KBSkinTheme *base = self.current ?: [self.class defaultTheme];
    KBSkinTheme *t = [KBSkinTheme new];
    t.skinId = skinId ?: @"image";
    t.name = name ?: t.skinId;
    t.keyboardBackground = base.keyboardBackground ?: [self.class defaultTheme].keyboardBackground;
    t.keyBackground = base.keyBackground ?: [self.class defaultTheme].keyBackground;
    t.keyTextColor = base.keyTextColor ?: [self.class defaultTheme].keyTextColor;
    t.keyHighlightBackground = base.keyHighlightBackground ?: [self.class defaultTheme].keyHighlightBackground;
    t.accentColor = base.accentColor ?: [self.class defaultTheme].accentColor;
    t.backgroundImageData = imageData;
    return [self applyTheme:t];
}

- (UIImage *)currentBackgroundImage {
    NSData *d = self.current.backgroundImageData;
    if (d.length == 0) return nil;
    return [UIImage imageWithData:d scale:[UIScreen mainScreen].scale] ?: nil;
}

+ (UIColor *)colorFromHexString:(NSString *)hex defaultColor:(UIColor *)fallback {
    if (![hex isKindOfClass:NSString.class] || hex.length == 0) return fallback;
    NSString *s = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString];
    if ([s hasPrefix:@"#"]) s = [s substringFromIndex:1];
    unsigned long long v = 0; NSScanner *scanner = [NSScanner scannerWithString:s];
    if (![scanner scanHexLongLong:&v]) return fallback;
    if (s.length == 6) { // RRGGBB
        CGFloat r = ((v >> 16) & 0xFF) / 255.0;
        CGFloat g = ((v >> 8) & 0xFF) / 255.0;
        CGFloat b = (v & 0xFF) / 255.0;
        return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
    } else if (s.length == 8) { // RRGGBBAA
        CGFloat r = ((v >> 24) & 0xFF) / 255.0;
        CGFloat g = ((v >> 16) & 0xFF) / 255.0;
        CGFloat b = ((v >> 8) & 0xFF) / 255.0;
        CGFloat a = (v & 0xFF) / 255.0;
        return [UIColor colorWithRed:r green:g blue:b alpha:a];
    }
    return fallback;
}

#pragma mark - Defaults

+ (KBSkinTheme *)defaultTheme {
    KBSkinTheme *t = [KBSkinTheme new];
    t.skinId = @"default";
    t.name = @"Default";
    t.keyboardBackground = [UIColor colorWithWhite:0.95 alpha:1.0];
    t.keyBackground = UIColor.whiteColor;
    t.keyTextColor = UIColor.blackColor;
    t.keyHighlightBackground = [UIColor colorWithWhite:0.85 alpha:1.0];
    t.accentColor = [UIColor colorWithRed:0.77 green:0.93 blue:0.82 alpha:1.0];
    t.backgroundImageData = nil;
    return t;
}

#pragma mark - Keychain

- (NSMutableDictionary *)baseKCQuery {
    NSMutableDictionary *q = [@{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
                                 (__bridge id)kSecAttrService: kKBSkinService,
                                 (__bridge id)kSecAttrAccount: kKBSkinAccount } mutableCopy];
    q[(__bridge id)kSecAttrAccessGroup] = KB_KEYCHAIN_ACCESS_GROUP;
    return q;
}

- (BOOL)p_saveToKeychain:(KBSkinTheme *)theme {
    NSError *err = nil;
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:theme requiringSecureCoding:YES error:&err];
    if (err || data.length == 0) return NO;
    NSMutableDictionary *q = [self baseKCQuery];
    SecItemDelete((__bridge CFDictionaryRef)q);
    q[(__bridge id)kSecValueData] = data;
    q[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
    OSStatus st = SecItemAdd((__bridge CFDictionaryRef)q, NULL);
    return (st == errSecSuccess);
}

- (KBSkinTheme *)p_loadFromKeychain {
    NSMutableDictionary *q = [self baseKCQuery];
    q[(__bridge id)kSecReturnData] = @YES;
    q[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
    CFTypeRef dataRef = NULL; OSStatus st = SecItemCopyMatching((__bridge CFDictionaryRef)q, &dataRef);
    if (st != errSecSuccess || !dataRef) return nil;
    NSData *data = (__bridge_transfer NSData *)dataRef;
    if (data.length == 0) return nil;
    @try {
        KBSkinTheme *t = [NSKeyedUnarchiver unarchivedObjectOfClass:KBSkinTheme.class fromData:data error:NULL];
        return t;
    } @catch (__unused NSException *e) { return nil; }
}

- (void)p_reloadFromKeychainAndBroadcast:(BOOL)broadcast {
    KBSkinTheme *t = [self p_loadFromKeychain] ?: [self.class defaultTheme];
    self.current = t;
    if (broadcast) {
        [[NSNotificationCenter defaultCenter] postNotificationName:KBSkinDidChangeNotification object:nil];
    }
}

@end
