import AppKit
import Foundation

/// One menu bar icon per app in `statusBarAppIDsData` (left-click opens in-app browser, right-click to remove).
final class StatusBarAppIconsController: NSObject {
    static let shared = StatusBarAppIconsController()

    /// Logical points; matches typical template icons (Wi‑Fi, Control Center, etc.).
    private static let menuBarIconSide: CGFloat = 16

    private var appStatusItems: [UUID: NSStatusItem] = [:]
    private var lastOrderedIDs: [UUID] = []

    private override init() {
        super.init()
    }

    func start() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(statusBarShortcutsMayHaveChanged),
            name: .statusBarShortcutIDsChanged,
            object: nil
        )
        DispatchQueue.main.async { [weak self] in
            self?.synchronize()
        }
    }

    @objc private func statusBarShortcutsMayHaveChanged() {
        synchronize()
    }

    private func synchronize() {
        let apps = LauncherApp.statusBarShortcutsOrdered()
        let orderedIDs = apps.map(\.id)
        guard orderedIDs != lastOrderedIDs else { return }
        lastOrderedIDs = orderedIDs

        for (_, item) in appStatusItems {
            NSStatusBar.system.removeStatusItem(item)
        }
        appStatusItems.removeAll()

        for app in apps {
            let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
            appStatusItems[app.id] = item

            guard let button = item.button else { continue }
            button.identifier = NSUserInterfaceItemIdentifier(app.id.uuidString)
            button.toolTip = app.name
            button.target = self
            button.action = #selector(appIconClicked(_:))
            button.sendAction(on: [.leftMouseUp, .rightMouseUp])
            button.imageScaling = .scaleProportionallyDown
            button.imagePosition = .imageOnly

            button.image = Self.statusBarImage(for: app)
        }
    }

    /// Renders at a fixed menu bar size so full‑resolution assets don’t fill the entire status item.
    private static func statusBarImage(for app: LauncherApp) -> NSImage? {
        if !app.assetIconName.isEmpty, let source = NSImage(named: app.assetIconName) {
            return scaledStatusBarImage(from: source, asTemplate: false)
        }

        guard let baseSymbol = NSImage(
            systemSymbolName: app.fallbackSymbolName,
            accessibilityDescription: app.name
        ) else { return nil }
        let config = NSImage.SymbolConfiguration(pointSize: 13, weight: .medium)
        let symbol = baseSymbol.withSymbolConfiguration(config) ?? baseSymbol
        symbol.isTemplate = true
        return scaledStatusBarImage(from: symbol, asTemplate: true)
    }

    private static func scaledStatusBarImage(from source: NSImage, asTemplate: Bool) -> NSImage {
        let side = menuBarIconSide
        let target = NSSize(width: side, height: side)
        let srcSize = source.size
        guard srcSize.width > 0, srcSize.height > 0 else {
            source.isTemplate = asTemplate
            return source
        }

        let image = NSImage(size: target, flipped: false) { _ in
            let scale = min(side / srcSize.width, side / srcSize.height)
            let w = srcSize.width * scale
            let h = srcSize.height * scale
            let x = (side - w) / 2
            let y = (side - h) / 2
            let dest = NSRect(x: x, y: y, width: w, height: h)
            let srcRect = NSRect(origin: .zero, size: srcSize)
            source.draw(
                in: dest,
                from: srcRect,
                operation: .sourceOver,
                fraction: 1,
                respectFlipped: true,
                hints: [.interpolation: NSImageInterpolation.high]
            )
            return true
        }
        image.isTemplate = asTemplate
        return image
    }

    @objc private func appIconClicked(_ sender: NSButton) {
        guard let raw = sender.identifier?.rawValue,
              let id = UUID(uuidString: raw) else { return }

        guard let event = NSApp.currentEvent else {
            openInAppBrowser(appID: id)
            return
        }

        if event.type == .rightMouseUp {
            let menu = NSMenu()
            let removeItem = NSMenuItem(
                title: "Remove from Status Bar",
                action: #selector(removeFromMenuBar(_:)),
                keyEquivalent: ""
            )
            removeItem.target = self
            removeItem.representedObject = raw as NSString
            menu.addItem(removeItem)
            let origin = NSPoint(x: 0, y: sender.bounds.height)
            menu.popUp(positioning: nil, at: origin, in: sender)
        } else {
            openInAppBrowser(appID: id)
        }
    }

    @objc private func removeFromMenuBar(_ sender: NSMenuItem) {
        guard let raw = sender.representedObject as? String,
              let id = UUID(uuidString: raw) else { return }
        var ids = LauncherApp.statusBarShortcutIDSet()
        ids.remove(id)
        LauncherApp.persistStatusBarShortcutIDs(ids)
    }

    private func openInAppBrowser(appID: UUID) {
        guard let app = LauncherApp.allLaunchableAppsFromUserDefaults().first(where: { $0.id == appID }),
              let url = app.webURL else { return }
        NSApp.setActivationPolicy(.regular)
        NSApp.activate(ignoringOtherApps: true)
        InAppBrowserWindowManager.shared.open(url: url, title: app.name)
    }
}
