//
// SparklePlugin.m
// Native macOS plugin for Unity to initialize Sparkle auto-updates
//
// Copyright 2026 Dan Crosby
//

#import <AppKit/AppKit.h>
#import <Sparkle/Sparkle.h>
#include <sys/mount.h>

// The updater controller - retained for the lifetime of the app
static SPUStandardUpdaterController *updaterController = nil;

// Export macro for Unity P/Invoke
#define EXPORT __attribute__((visibility("default")))

// Called from Unity to initialize Sparkle
// This should be called once at app startup
EXPORT void SparklePlugin_Initialize(void) {
    if (updaterController != nil) {
        NSLog(@"SparklePlugin: Already initialized");
        return;
    }

    NSLog(@"SparklePlugin: Initializing Sparkle auto-updater");

    // Log Info.plist configuration
    NSBundle *mainBundle = [NSBundle mainBundle];
    NSString *feedURL = [mainBundle objectForInfoDictionaryKey:@"SUFeedURL"];
    NSString *publicKey = [mainBundle objectForInfoDictionaryKey:@"SUPublicEDKey"];
    NSString *version = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
    NSString *buildNumber = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
    NSNumber *autoCheck = [mainBundle objectForInfoDictionaryKey:@"SUEnableAutomaticChecks"];

    NSLog(@"SparklePlugin: App version: %@ (build %@)", version ?: @"(not set)", buildNumber ?: @"(not set)");
    NSLog(@"SparklePlugin: Feed URL: %@", feedURL ?: @"(not set)");
    NSLog(@"SparklePlugin: Public key: %@", publicKey ? @"(set)" : @"(not set)");
    NSLog(@"SparklePlugin: Auto-check enabled in plist: %@", autoCheck ?: @"(not set)");

    // Create the updater controller with automatic update checking enabled
    // The feed URL and public key are read from Info.plist (SUFeedURL, SUPublicEDKey)
    updaterController = [[SPUStandardUpdaterController alloc]
        initWithStartingUpdater:YES
        updaterDelegate:nil
        userDriverDelegate:nil];

    if (updaterController != nil) {
        NSLog(@"SparklePlugin: Sparkle initialized successfully");
        NSLog(@"SparklePlugin: Auto-check currently: %@",
              [[updaterController updater] automaticallyChecksForUpdates] ? @"enabled" : @"disabled");
        NSLog(@"SparklePlugin: Last update check: %@",
              [[updaterController updater] lastUpdateCheckDate] ?: @"never");
    } else {
        NSLog(@"SparklePlugin: Failed to initialize Sparkle");
    }
}

// Manually trigger an update check (shows UI)
EXPORT void SparklePlugin_CheckForUpdates(void) {
    if (updaterController == nil) {
        NSLog(@"SparklePlugin: Not initialized, call Initialize first");
        return;
    }

    NSLog(@"SparklePlugin: Checking for updates");
    [updaterController checkForUpdates:nil];
}

// Check for updates silently in background (no UI unless update found)
EXPORT void SparklePlugin_CheckForUpdatesInBackground(void) {
    if (updaterController == nil) {
        NSLog(@"SparklePlugin: Not initialized, call Initialize first");
        return;
    }

    NSLog(@"SparklePlugin: Checking for updates in background");
    [[updaterController updater] checkForUpdatesInBackground];
}

// Returns 1 if an update check is in progress, 0 otherwise
EXPORT int SparklePlugin_IsCheckingForUpdates(void) {
    if (updaterController == nil) {
        return 0;
    }
    return [[updaterController updater] sessionInProgress] ? 1 : 0;
}

// Returns 1 if automatic update checks are enabled, 0 otherwise
EXPORT int SparklePlugin_GetAutomaticallyChecksForUpdates(void) {
    if (updaterController == nil) {
        return 0;
    }
    return [[updaterController updater] automaticallyChecksForUpdates] ? 1 : 0;
}

// Enable or disable automatic update checks
EXPORT void SparklePlugin_SetAutomaticallyChecksForUpdates(int enabled) {
    if (updaterController == nil) {
        NSLog(@"SparklePlugin: Not initialized");
        return;
    }
    [[updaterController updater] setAutomaticallyChecksForUpdates:(enabled != 0)];
}

// Check if app is running from a read-only filesystem (e.g., mounted DMG)
// Returns 1 if read-only, 0 if writable
EXPORT int SparklePlugin_IsRunningFromReadOnlyVolume(void) {
    NSBundle *mainBundle = [NSBundle mainBundle];
    NSString *bundlePath = [mainBundle bundlePath];

    struct statfs fsInfo;
    if (statfs([bundlePath fileSystemRepresentation], &fsInfo) == 0) {
        BOOL isReadOnly = (fsInfo.f_flags & MNT_RDONLY) != 0;
        NSLog(@"SparklePlugin: Bundle path: %@, read-only: %@", bundlePath, isReadOnly ? @"YES" : @"NO");
        return isReadOnly ? 1 : 0;
    }

    NSLog(@"SparklePlugin: Failed to check filesystem for %@", bundlePath);
    return 0; // Assume writable if we can't check
}

// Show a dialog telling user to drag app out of DMG
EXPORT void SparklePlugin_ShowDMGWarning(void) {
    NSLog(@"SparklePlugin: Showing DMG warning dialog");

    dispatch_async(dispatch_get_main_queue(), ^{
        NSAlert *alert = [[NSAlert alloc] init];
        [alert setMessageText:@"Please install Eagle0 first"];
        [alert setInformativeText:
                @"Eagle0 is running from the disk image (DMG). "
                 "To play, please drag Eagle0 to your Applications folder first, "
                 "then launch it from there.\n\n"
                 "The app will now quit."];
        [alert setAlertStyle:NSAlertStyleCritical];
        [alert addButtonWithTitle:@"Quit"];

        [alert runModal];
        [NSApp terminate:nil];
    });
}
