#include "MacSupport.h"
#include "properties.h"
#include <JuceHeader.h>
#import <AppKit/AppKit.h>
#import <Sparkle/Sparkle.h>
#import <Security/Security.h>

@interface MenuDelegate : NSObject {
}
- (void) quit;
- (void) checkForUpdates;
- (void) setMacSupport: (MacSupport*) m;
@end

@implementation MenuDelegate {
    MacSupport * macSupport;
}
- (void) quit {
    juce::JUCEApplication::getInstance()->systemRequestedQuit();
}
- (void) checkForUpdates {
    macSupport->checkForUpdates();
}
- (void) clearTrustStore {
    macSupport->clearTrustStore();
}
- (void) editSearchPaths {
    macSupport->editSearchPaths();
}
- (void) setMacSupport: (MacSupport*) m {
    macSupport = m;
}
@end

void MacSupport::showStatusItemDropdownMenu(void * item) {
    @autoreleasepool {
        NSStatusItem * si = (__bridge NSStatusItem*)item;
        NSMenu* m = [[NSMenu alloc] initWithTitle:@"mymenu"];
        
        MenuDelegate * deleg = [[MenuDelegate alloc] init];
        
        [deleg setMacSupport:this];
        
        NSMenuItem* checkUpdatesItem = [m addItemWithTitle:@"Check for updates..." action:@selector(checkForUpdates) keyEquivalent:@""];
        NSMenuItem* clearTrustStoreItem = [m addItemWithTitle:@"Clear trust store" action:@selector(clearTrustStore) keyEquivalent:@""];
        NSMenuItem* editSearchPathsItem = [m addItemWithTitle:@"Edit plugin search paths" action:@selector(editSearchPaths) keyEquivalent:@""];
        NSMenuItem* quitItem = [m addItemWithTitle:@"Quit" action:@selector(quit) keyEquivalent:@"q"];
        [checkUpdatesItem setTarget:deleg];
        [clearTrustStoreItem setTarget:deleg];
        [editSearchPathsItem setTarget:deleg];
        [quitItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
        [quitItem setTarget:deleg];
        
        [si popUpStatusItemMenu:m];
    }
}

bool MacSupport::showTrustQuery() {
    @autoreleasepool {
        NSAlert * alert = [[NSAlert alloc] init];
        [alert setAlertStyle:NSAlertStyleWarning];
        [alert setMessageText:@"WavTool is attempting to load VST settings from an unrecognized source.\n\nLoading untrusted VST settings may lead to compromise of your device. Be sure you trust the author of the project before continuing."];
        NSButton* trustButton = [alert addButtonWithTitle:@"Trust"];
        NSButton* dontTrustButton = [alert addButtonWithTitle:@"Do Not Trust"];
        [dontTrustButton setKeyEquivalent:@"\e"];
        [trustButton setKeyEquivalent:@"\r"];
        [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
        return [alert runModal] == NSAlertFirstButtonReturn;
    }
}

std::string MacSupport::generateOrLoadBridgeKeySeed(std::function<std::string(void)> && generate) {
    @autoreleasepool {
        auto accountKey = @"com.wavtool.bridge.SigningKeySeed";
        NSDictionary *query = @{
            (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
            (__bridge id)kSecAttrAccount: accountKey,
            (__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue,
            (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
        };
        
        CFDataRef retrievedPasswordData = NULL;
        OSStatus statusCopy = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&retrievedPasswordData);
        
        if (statusCopy == errSecSuccess) {
            std::string keySeed(CFDataGetLength(retrievedPasswordData), 0);
            CFDataGetBytes(retrievedPasswordData, CFRangeMake(0, keySeed.size()), (UInt8*)keySeed.data());
            CFRelease(retrievedPasswordData);
            return keySeed;
        }
        
        auto keySeed = generate();
        NSData *passwordData = [[NSData alloc] initWithBytes:keySeed.data() length:keySeed.size()];
        NSDictionary *attributes = @{
            (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
            (__bridge id)kSecAttrAccount: accountKey,
            (__bridge id)kSecValueData: passwordData,
        };
        
        OSStatus statusAdd = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
        
        if (statusAdd == errSecSuccess) {
            return keySeed;
        } else {
            std::stringstream ss;
            ss << "Failed to load and store bridge key! statusCopy = " << statusCopy << ", statusAdd = " << statusAdd;
            throw std::runtime_error(ss.str());
        }
    }
}

@interface AppUpdaterDelegate : NSObject <SPUUpdaterDelegate>

@property (nonatomic) SPUStandardUpdaterController *updaterController;

@end

@implementation AppUpdaterDelegate

@end

MacSupport::MacSupport(std::function<void()> && clearTrustStore,
                       std::function<void()> && editSearchPaths)
  : clearTrustStore(std::move(clearTrustStore)),
    editSearchPaths(std::move(editSearchPaths))
{
    @autoreleasepool {
        _updaterDelegate = [[AppUpdaterDelegate alloc] init];
        _updaterDelegate.updaterController = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES updaterDelegate:_updaterDelegate userDriverDelegate:nil];
    }
}

// Called when the user checks for updates
void MacSupport::checkForUpdates()
{
    @autoreleasepool {
        [_updaterDelegate.updaterController checkForUpdates:nil];
    }
}
