//go:build darwin

#import <Cocoa/Cocoa.h>
#include "_cgo_export.h"

// CdropStatusBarController owns the menu bar item and routes the three menu
// actions back into Go. It is deliberately NOT the NSApplication delegate —
// Wails owns that, and stealing it would break Wails' window / runtime / custom
// scheme handling. A status item can be created independently after launch, so
// we never touch the delegate.
@interface CdropStatusBarController : NSObject
@property (strong) NSStatusItem *item;
@property (strong) NSMenu *menu;
- (void)showWindow:(id)sender;
- (void)openSettings:(id)sender;
- (void)quit:(id)sender;
- (void)statusItemClicked:(id)sender;
@end

@implementation CdropStatusBarController
- (void)showWindow:(id)sender { cdropOnShowWindow(); }
- (void)openSettings:(id)sender { cdropOnOpenSettings(); }
- (void)quit:(id)sender { cdropOnQuit(); }

// showMenu pops the menu now. Temporarily attaching item.menu and performClick
// shows it and BLOCKS until dismissed (menu tracking is modal); detaching after
// keeps left-clicks flowing through statusItemClicked: (so left-click opens the
// window directly instead of popping the menu).
- (void)showMenu {
    self.item.menu = self.menu;
    [self.item.button performClick:nil];
    self.item.menu = nil;
}

// statusItemClicked fires on left/right mouse-up. Click routing (the Windows tray
// should mirror this once implemented):
//   - left-click                  → open the main window
//   - right-click / control-click → menu (Show / Settings / Quit)
// We route clicks manually instead of setting item.menu — item.menu would pop the
// menu on left-click too, leaving no way for left-click to open the window.
- (void)statusItemClicked:(id)sender {
    NSEvent *e = [NSApp currentEvent];
    BOOL secondary = (e.type == NSEventTypeRightMouseUp) ||
                     ((e.modifierFlags & NSEventModifierFlagControl) != 0);
    if (secondary) {
        [self showMenu];     // right-click / control-click → menu
    } else {
        cdropOnShowWindow(); // left-click → open the main window
    }
}
@end

// File-scope strong reference (ARC) keeps the controller and its status item
// alive for the process lifetime.
static CdropStatusBarController *gController = nil;

// cdropStatusBarInstall creates the menu bar item + its menu on the main thread.
// The icon is the embedded brand mascot (a colored, NON-template image — keeps
// brand color instead of tinting to the menu bar). It's displayed at the menu
// bar thickness (logical points); the high-res (256px) source rep keeps it crisp
// on retina. If decoding fails it falls back to the text title. The PNG bytes are
// copied into NSData synchronously here (before the async block) so Go can free
// its C buffer right after this call. Labels arrive as UTF-8 from Go so this
// source stays ASCII-only. Idempotent.
void cdropStatusBarInstall(const void *iconPNG, int iconLen, const char *title,
                           const char *showLabel, const char *settingsLabel,
                           const char *quitLabel) {
    NSData *iconData = (iconPNG != NULL && iconLen > 0)
        ? [NSData dataWithBytes:iconPNG length:(NSUInteger)iconLen]
        : nil;
    NSString *t  = [NSString stringWithUTF8String:title];
    NSString *sl = [NSString stringWithUTF8String:showLabel];
    NSString *gl = [NSString stringWithUTF8String:settingsLabel];
    NSString *ql = [NSString stringWithUTF8String:quitLabel];

    dispatch_async(dispatch_get_main_queue(), ^{
        if (gController != nil) { return; }
        gController = [[CdropStatusBarController alloc] init];

        NSStatusItem *item = [[NSStatusBar systemStatusBar]
            statusItemWithLength:NSVariableStatusItemLength];

        NSImage *icon = (iconData != nil) ? [[NSImage alloc] initWithData:iconData] : nil;
        if (icon != nil) {
            CGFloat th = [[NSStatusBar systemStatusBar] thickness];
            [icon setSize:NSMakeSize(th, th)]; // fill bar height; retina uses 256px rep
            icon.template = NO;                 // keep brand color, don't tint
            item.button.image = icon;
            item.button.accessibilityLabel = t; // image has no text → a11y label
        } else {
            item.button.title = t;
        }

        NSMenu *menu = [[NSMenu alloc] init];

        NSMenuItem *show = [[NSMenuItem alloc] initWithTitle:sl
            action:@selector(showWindow:) keyEquivalent:@""];
        show.target = gController;
        [menu addItem:show];

        NSMenuItem *settings = [[NSMenuItem alloc] initWithTitle:gl
            action:@selector(openSettings:) keyEquivalent:@""];
        settings.target = gController;
        [menu addItem:settings];

        [menu addItem:[NSMenuItem separatorItem]];

        NSMenuItem *quit = [[NSMenuItem alloc] initWithTitle:ql
            action:@selector(quit:) keyEquivalent:@""];
        quit.target = gController;
        [menu addItem:quit];

        // Don't set item.menu (that auto-pops on mouse-down, killing double-click
        // detection). Store the menu and route clicks through statusItemClicked:.
        gController.item = item;
        gController.menu = menu;
        item.button.target = gController;
        item.button.action = @selector(statusItemClicked:);
        [item.button sendActionOn:(NSEventMaskLeftMouseUp | NSEventMaskRightMouseUp)];
    });
}

// cdropSetActivationPolicy flips the Dock presence on the main thread.
// policy: 0 = regular (Dock icon shown), 1 = accessory (Dock hidden, menu bar
// item only).
void cdropSetActivationPolicy(int policy) {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSApplicationActivationPolicy p =
            (policy == 1) ? NSApplicationActivationPolicyAccessory
                          : NSApplicationActivationPolicyRegular;
        [NSApp setActivationPolicy:p];
    });
}
