#if arch(arm64)
import AppKit
import NucleicCore
import Virtualization

/// The **host-side computer-use surface** (docs/MACOS_VM.md §12): the app-layer implementation of
/// `MacVMSurfaceHost`. For each active surface it owns a main-actor `VZVirtualMachineView` bound to a
/// guest that continues running on its own VM queue, and drives it entirely host-side — capturing the
/// guest **framebuffer** via `cacheDisplay` and injecting **keyboard/mouse HID** via synthesized
/// `NSEvent`s delivered to the
/// view. The guest grants nothing (no in-guest agent, no TCC, no SIP); these are ordinary virtual
/// hardware. Proven end-to-end by `macvm-spike`'s host-IO mode.
///
/// A VM is registered here at boot, but its AppKit surface is **lazy**: the
/// `VZVirtualMachineView` + off-screen window exist only while capture/HID/operator viewing is active,
/// then are released after a short idle grace period. This keeps headless VMs off the main-thread /
/// WindowServer render path entirely. While active, the view lives in an off-screen borderless window
/// so it renders without showing a VM window to the user. Everything runs on the main actor, as
/// `VZVirtualMachineView` requires.
@MainActor
final class MacVMComputerSurface: MacVMSurfaceHost {
    /// Guest logical display size in points (matches `MacVMEngine.makeGraphics` — a 3840×2400 @ 2×
    /// Retina panel that renders "looks like 1920×1200"). Screenshots are normalized to this so
    /// image pixels == input coordinates == guest points, all 1:1 regardless of the panel's density.
    static let fbWidth = 1920
    static let fbHeight = 1200

    /// The guest's **native panel resolution in pixels** (matches `MacVMEngine.makeGraphics`: a
    /// 3840×2400 @ 220 PPI display, i.e. the 1920×1200-pt desktop rendered @ 2×).
    ///
    /// This is the ceiling on how much real detail a framebuffer grab can carry, and the target the
    /// off-screen window is sized to hit — see ``offScreenContentSize(for:)``.
    static let guestPixelWidth = 3840
    static let guestPixelHeight = 2400

    /// Where the agent-driven HID window is parked so it renders (ordered-in) without showing to the
    /// user. Far off any plausible display arrangement; kept there by `pinnedOffScreen` +
    /// `KeyableWindow.constrainFrameRect`, and re-asserted by `reparkOffScreenWindows` after a display
    /// change.
    private static let offScreenOrigin = NSPoint(x: -30_000, y: -30_000)

    private struct Entry {
        let window: KeyableWindow
        let view: VZVirtualMachineView
    }
    /// Registered live guests. Registration is deliberately framework-light: it creates no view,
    /// window, layer, or WindowServer work until `activate` is called by real surface demand.
    private var machines: [String: VZVirtualMachine] = [:]
    private var entries: [String: Entry] = [:]
    /// Cursor state outlives an idle surface release, so a later drag still starts from the last point.
    private var cursors: [String: CGPoint] = [:]
    /// One reaper per materialized surface. Captures merely advance its deadline instead of creating a
    /// new sleeping task at monitor frame rate.
    private var idleReleaseTasks: [String: Task<Void, Never>] = [:]
    private var lastUse: [String: ContinuousClock.Instant] = [:]
    private static let idleReleaseDelay: Duration = .seconds(5)
    /// One global main-thread framebuffer budget shared by every VM. A single visible monitor caps its
    /// cadence here; multiple monitors divide the budget instead of multiplying cacheDisplay calls on the
    /// UI thread. `cacheDisplay` is a full software render of the VM view's layer tree at backing scale
    /// on the main actor, so 15 Hz — plenty for a live monitor thumbnail — halves that per-second
    /// main-thread cost versus a 30 Hz spin.
    private var lastFramebufferGrab: ContinuousClock.Instant?
    private static let minimumFramebufferGrabInterval: Duration =
        .nanoseconds(1_000_000_000 / 15)
    // Set once at init and read once at deinit (to unregister); `nonisolated(unsafe)` lets the
    // nonisolated deinit touch these non-Sendable tokens without a concurrency race.
    private nonisolated(unsafe) var screenObserver: NSObjectProtocol?
    private nonisolated(unsafe) var windowCloseObserver: NSObjectProtocol?

    init() {
        // Attaching or detaching a display makes the WindowServer relocate windows that lie entirely
        // off all screens onto a live display — which would surface a borderless 1920×1200
        // VZVirtualMachineView on the user's Mac (and, before the `ignoresMouseEvents` lock, let them
        // click into the guest). Re-park + re-lock every agent-driven surface whenever the screen
        // topology changes. See `reparkOffScreenWindows`.
        screenObserver = NotificationCenter.default.addObserver(
            forName: NSApplication.didChangeScreenParametersNotification, object: nil, queue: .main
        ) { [weak self] _ in
            MainActor.assumeIsolated { self?.reparkOffScreenWindows() }
        }
        // We only ever `orderOut` our windows programmatically, never `close` them, so a real close (the
        // only thing that posts `willCloseNotification`) means the user dismissed an on-screen viewer via
        // its close button. That's our signal to re-park the surface and let the UI flip its toggle. One
        // app-wide observer, filtered to our own windows — mirrors `screenObserver`'s no-per-window churn.
        windowCloseObserver = NotificationCenter.default.addObserver(
            forName: NSWindow.willCloseNotification, object: nil, queue: .main
        ) { [weak self] note in
            guard let window = note.object as? NSWindow else { return }
            MainActor.assumeIsolated { self?.handleWindowWillClose(window) }
        }
    }

    deinit {
        if let screenObserver { NotificationCenter.default.removeObserver(screenObserver) }
        if let windowCloseObserver { NotificationCenter.default.removeObserver(windowCloseObserver) }
    }

    /// A window is closing. If it's one of our on-screen viewers (diagnostic monitor / operator-assist),
    /// the user dismissed it via its close button — re-park the surface off-screen so headless capture +
    /// HID keep working, and broadcast the surface name so the Settings "Show/Hide VM screen" toggle can
    /// flip back to "Show". Ignores unrelated app windows.
    private func handleWindowWillClose(_ window: NSWindow) {
        guard let name = entries.first(where: { $0.value.window === window })?.key else { return }
        NotificationCenter.default.post(name: .macVMObserverWindowClosed, object: name)
        // Re-park after the close settles (reconfiguring the window mid-close is unsafe); capture resumes
        // off-screen a runloop tick later. Idempotent with the "Hide" path.
        Task { @MainActor [weak self] in self?.lockOffScreen(name) }
    }

    /// Re-assert the off-screen lockdown for every agent-driven surface after a display-topology change.
    ///
    /// The lockdown normally relies on the HID window sitting far off any display, but a display
    /// connect/disconnect makes the WindowServer relocate off-screen windows onto a valid screen.
    /// `pinnedOffScreen` + `KeyableWindow.constrainFrameRect` block that move up front; this observer is
    /// the backstop that re-parks and re-locks anything that still slipped on-screen. Windows
    /// deliberately on-screen for a consented hand-off (`pinnedOffScreen == false`) are left untouched.
    private func reparkOffScreenWindows() {
        for e in entries.values {
            let w = e.window
            guard w.pinnedOffScreen else { continue }
            w.isKeyable = false
            w.ignoresMouseEvents = true
            e.view.capturesSystemKeys = false
            if w.styleMask != [.borderless] { w.styleMask = [.borderless] }
            // Re-derive from THIS window's backing scale: the display change that triggered this may
            // have moved it between a 1× and a 2× screen, which changes the point size that yields the
            // guest's native pixels (see `offScreenContentSize`).
            w.setContentSize(offScreenContentSize(for: w))
            w.setFrameOrigin(Self.offScreenOrigin)
            w.orderFrontRegardless()
        }
    }

    /// The off-screen HID window's content size, in **points**, chosen so that `cacheDisplay` renders
    /// the guest at its native ``guestPixelWidth``×``guestPixelHeight`` pixels on this host.
    ///
    /// `bitmapImageRepForCachingDisplay` allocates at the view's *backing scale*, so the pixels a grab
    /// can contain are `points × backingScaleFactor` — and the backing scale belongs to the **host's**
    /// display, not the guest's. A 1920×1200-pt view therefore yielded the guest's native 3840×2400
    /// only on a Retina host; on a 1× host every grab was a 2:1 downsample of the guest's panel before
    /// anything else touched it. That is invisible in a screenshot and fatal to OCR, and it made the
    /// MDM approval loop's reliability depend on which display the user happened to be running on.
    /// Sizing in the opposite direction removes the host from the equation: 1920 pt @ 2× and 3840 pt
    /// @ 1× both grab 3840 px.
    ///
    /// Input coordinates are unaffected — `guestPoint` maps the 1920×1200 input space through the
    /// view's *live* bounds — and ``capture(name:)`` still normalizes to 1920×1200, so the public
    /// computer-use contract is unchanged either way.
    private func offScreenContentSize(for window: NSWindow) -> NSSize {
        // `backingScaleFactor` is the host display's; an off-screen window reports the main screen's.
        // Clamp so a 0/garbage value can never inflate the window without bound.
        let scale = min(max(window.backingScaleFactor, 1), 2)
        return NSSize(
            width: CGFloat(Self.guestPixelWidth) / scale,
            height: CGFloat(Self.guestPixelHeight) / scale)
    }

    // MARK: - MacVMSurfaceHost

    func attach(name: String, virtualMachine box: UncheckedSendableBox<AnyObject>) async {
        guard let vm = box.value as? VZVirtualMachine else { return }
        // A reboot can reuse the same logical name. Tear down any old materialized surface, then retain
        // only the new VM reference; capture/HID/viewing will activate it on demand.
        releaseSurface(name)
        machines[name] = vm
        cursors[name] = CGPoint(x: Self.fbWidth / 2, y: Self.fbHeight / 2)
    }

    /// Materialize the AppKit surface for a registered VM. Idempotent and intentionally the only place
    /// that creates an ordered-in window, so a headless VM never enters the main-thread render path.
    private func activate(_ name: String) async -> Entry? {
        if let entry = entries[name] {
            markUsed(name)
            return entry
        }
        guard let vm = machines[name] else { return nil }
        let frame = NSRect(x: 0, y: 0, width: Self.fbWidth, height: Self.fbHeight)
        let view = VZVirtualMachineView(frame: frame)
        view.virtualMachine = vm
        // Off-screen (agent-driven) the view must NEVER capture the user's physical keyboard: the agent
        // injects HID by handing synthesized events straight to the view's responder (`postStroke` /
        // `postMouse`), which needs neither a key window nor system-key capture. `capturesSystemKeys` is
        // turned on ONLY while the window is deliberately on-screen for the diagnostic monitor /
        // operator-assist hand-off, where the user IS driving the guest (see `setWindowOnScreen`).
        view.capturesSystemKeys = false
        // Scale with the window so the diagnostic monitor can present at a smaller size (the view
        // letterboxes the guest to fit); off-screen it stays at native 1920×1200 for capture/HID.
        view.autoresizingMask = [.width, .height]

        // Off-screen host window: ordered-in (so the view's Metal layer renders) but positioned far
        // off any display. It must never become key while off-screen — a `VZVirtualMachineView` in a key
        // window routes the user's real keyboard (system keys included) into the guest, so an off-screen
        // window winning key focus on app activation is exactly what would "capture" the user's typing.
        // `KeyableWindow.isKeyable` stays `false` here (so `canBecomeKey` is `false`); it's flipped on
        // only when the window is brought on-screen for the diagnostic monitor / operator-assist
        // hand-off, the sole cases where the user should type into the guest. If a future macOS ever
        // refuses to render an off-screen window, host this view in the VM monitor instead.
        let window = KeyableWindow(
            contentRect: frame, styleMask: [.borderless], backing: .buffered, defer: false)
        window.contentView = view
        window.isReleasedWhenClosed = false
        // Belt-and-suspenders input lock: while the agent drives, the window must NEVER accept the
        // user's real mouse — even if the WindowServer relocates it onto a live display after a monitor
        // is attached/detached. Real clicks pass through to whatever is beneath it; the agent's
        // synthesized events are handed straight to the view (`sendEvent`/responder calls) and bypass
        // hit-testing, so they're unaffected. Flipped off only for a consented interactive hand-off.
        window.ignoresMouseEvents = true
        // Keep AppKit from constraining this window onto a valid screen when the display topology
        // changes (see `KeyableWindow.constrainFrameRect` and `reparkOffScreenWindows`).
        window.pinnedOffScreen = true
        // Size for a native-resolution framebuffer grab now that the window exists and can report its
        // backing scale (the view autoresizes with the content view).
        window.setContentSize(offScreenContentSize(for: window))
        window.setFrameOrigin(Self.offScreenOrigin)
        window.orderFrontRegardless()
        window.makeFirstResponder(view)

        let entry = Entry(window: window, view: view)
        entries[name] = entry
        markUsed(name)
        // Let the newly ordered view commit one frame before its first cacheDisplay. Without this,
        // the first computer-use screenshot after a long headless stretch can race the Metal layer and
        // come back blank; later captures reuse the warm entry and pay no delay.
        try? await Task.sleep(for: .milliseconds(16))
        guard let active = entries[name], active.window === window else { return nil }
        return active
    }

    func detach(name: String) async {
        machines[name] = nil
        cursors[name] = nil
        lastUse[name] = nil
        idleReleaseTasks.removeValue(forKey: name)?.cancel()
        releaseSurface(name)
    }

    /// Release only the AppKit portion while retaining the registered VM for a later on-demand
    /// reactivation. Safe for the idle reaper and for full `detach`.
    private func releaseSurface(_ name: String) {
        guard let e = entries.removeValue(forKey: name) else { return }
        if e.window.isKeyWindow { e.window.resignKey() }
        e.view.virtualMachine = nil
        e.window.orderOut(nil)
    }

    /// Advance this surface's idle deadline and ensure exactly one reaper is watching it. A live monitor
    /// calls this at frame rate, so avoiding one Task allocation per touch is important.
    private func markUsed(_ name: String) {
        lastUse[name] = .now
        guard idleReleaseTasks[name] == nil else { return }
        idleReleaseTasks[name] = Task { @MainActor [weak self] in
            while !Task.isCancelled {
                try? await Task.sleep(for: Self.idleReleaseDelay)
                guard !Task.isCancelled, let self, let used = self.lastUse[name] else { break }
                guard let entry = self.entries[name] else { break }
                // A diagnostic/operator window is deliberately on screen and must remain live even when
                // no programmatic capture is happening.
                if !entry.window.pinnedOffScreen { continue }
                if ContinuousClock.now - used < Self.idleReleaseDelay { continue }
                self.releaseSurface(name)
                self.lastUse[name] = nil
                break
            }
            self?.idleReleaseTasks[name] = nil
        }
    }

    func setObserverVisible(name: String, visible: Bool) async {
        if visible { guard await activate(name) != nil else { return } }
        // The base-build diagnostic monitor is an explicit, operator-driven hand-off (watch — and, if
        // needed, click into — a misbehaving base build), so it opts into user control.
        setWindowOnScreen(
            name, visible: visible, title: "Nucleic base VM — diagnostic monitor", interactive: true)
    }

    func presentOperatorAssist(name: String, visible: Bool) async {
        if visible { guard await activate(name) != nil else { return } }
        // Same on-screen mechanism as the diagnostic monitor, but titled for the user-facing hand-off
        // (`mac_vm_request_operator`): the user drives the guest by hand to clear a captcha / login.
        setWindowOnScreen(
            name, visible: visible, title: "macOS VM — you're driving (agent needs help)",
            interactive: true)
    }

    /// Bring the surface's live `VZVirtualMachineView` on-screen in a titled window (or send it back
    /// off-screen). Shared by the base-build diagnostic monitor and the operator-assist viewer.
    ///
    /// `interactive` is the ONLY thing that ever hands the guest's keyboard/mouse to the user, and it's
    /// deliberately decoupled from mere visibility: showing the window never grants control on its own.
    /// The agent-driven default (off-screen) AND any non-interactive on-screen use keep the window
    /// unkeyable with system-key capture off, so the user can't type or click into the VM — only the
    /// two explicit, user-consented hand-offs (`setObserverVisible`, `presentOperatorAssist`) pass
    /// `interactive: true`. The agent's synthesized HID goes straight to the view's responder and is
    /// unaffected by any of this.
    private func setWindowOnScreen(
        _ name: String, visible: Bool, title: String, interactive: Bool = false
    ) {
        guard let e = entries[name] else { return }
        markUsed(name)
        let w = e.window
        if visible {
            // Give the (normally off-screen, borderless) HID window real chrome and bring it on-screen.
            // The VM view scales to fit (autoresizing), so a 1280×800 window shows the whole 1920×1200
            // guest. Hand the user the keyboard/mouse ONLY for an explicit `interactive` hand-off —
            // where they're deliberately driving the guest; a non-interactive show stays observe-only
            // (unkeyable, no system-key capture), so the guest still can't take the user's input.
            e.view.capturesSystemKeys = interactive
            w.isKeyable = interactive
            // On-screen for a consented hand-off, so it may leave its off-screen pin. The user may only
            // click into the guest for an explicit `interactive` hand-off; a non-interactive show stays
            // observe-only (mouse ignored), matching the key/system-key lock.
            w.pinnedOffScreen = false
            w.ignoresMouseEvents = !interactive
            w.styleMask = [.titled, .closable, .resizable, .miniaturizable]
            w.title = title
            w.setContentSize(NSSize(width: 1280, height: 800))
            w.center()
            if interactive {
                w.makeKeyAndOrderFront(nil)
                w.makeFirstResponder(e.view)
            } else {
                w.orderFrontRegardless()
            }
            NSApp.activate(ignoringOtherApps: true)
        } else {
            lockOffScreen(name)
        }
    }

    /// Composite the surface's view on a real display so its framebuffer actually renders (recent
    /// guests don't drive the Metal layer for a truly off-screen window — `cacheDisplay` then returns
    /// blank), but keep it **invisible**: fully transparent, click-through, unkeyable. No VM window
    /// appears and the guest can't take the user's input. Used for recoveryOS OCR, where there is no
    /// in-guest agent to capture through. `enabled: false` sends it back to the parked off-screen state.
    func setHeadlessRendering(name: String, enabled: Bool) async {
        guard enabled else {
            if let e = entries[name] { e.window.alphaValue = 1 }
            lockOffScreen(name)
            return
        }
        guard let e = await activate(name) else { return }
        let w = e.window
        w.isKeyable = false
        e.view.capturesSystemKeys = false
        w.ignoresMouseEvents = true
        // Not "pinned off-screen": that flag both re-parks the window off any display AND lets the idle
        // reaper release it. We want the opposite — stay on a display, and stay alive through the long
        // recovery-navigation pauses.
        w.pinnedOffScreen = false
        w.alphaValue = 0                       // composited (so it renders) but shows nothing
        w.styleMask = [.borderless]
        w.setContentSize(offScreenContentSize(for: w))
        // On a real display so the WindowServer composites it, and ABOVE other windows so it can't be
        // occlusion-culled (an occluded window stops rendering) — safe because it's fully transparent
        // and ignores mouse events, so nothing is visible and clicks pass straight through.
        if let screen = NSScreen.main ?? NSScreen.screens.first {
            w.setFrameOrigin(screen.frame.origin)
        } else {
            w.setFrameOrigin(.zero)
        }
        w.level = .floating
        w.orderFrontRegardless()               // never makes it key (isKeyable == false)
        w.makeFirstResponder(e.view)
        markUsed(name)
    }

    /// Return a surface's window to the invisible, native-size, borderless HID/capture configuration and
    /// lock it back down so it can never again become key or capture the user's keyboard while the agent
    /// drives. Shared by the "Hide the monitor" path (`setWindowOnScreen(visible: false)`) and the
    /// user-closed-the-window handler (``windowWillClose(_:)``). Idempotent.
    private func lockOffScreen(_ name: String) {
        guard let e = entries[name] else { return }
        let w = e.window
        if w.isKeyWindow { w.resignKey() }
        w.isKeyable = false
        w.ignoresMouseEvents = true
        w.pinnedOffScreen = true
        w.alphaValue = 1  // undo any headless-render transparency before re-parking
        w.level = .normal
        e.view.capturesSystemKeys = false
        w.orderOut(nil)
        w.styleMask = [.borderless]
        w.setContentSize(offScreenContentSize(for: w))
        w.setFrameOrigin(Self.offScreenOrigin)
        w.orderFrontRegardless()
        markUsed(name)
    }

    func cursorPosition(name: String) async -> Point? {
        guard machines[name] != nil, let cursor = cursors[name] else { return nil }
        return Point(x: Int(cursor.x), y: Int(cursor.y))
    }

    /// Wait for the app-wide framebuffer slot. The loop re-checks after sleeping because actor
    /// reentrancy lets another capture claim the slot while this caller is suspended.
    private func awaitFramebufferBudget() async -> Bool {
        while let last = lastFramebufferGrab {
            if Task.isCancelled { return false }
            let elapsed = ContinuousClock.now - last
            guard elapsed < Self.minimumFramebufferGrabInterval else { break }
            do { try await Task.sleep(for: Self.minimumFramebufferGrabInterval - elapsed) }
            catch { return false }
        }
        guard !Task.isCancelled else { return false }
        lastFramebufferGrab = .now
        return true
    }

    /// Capture the framebuffer and normalize to a 1920×1200 JPEG (`cacheDisplay` returns the view's
    /// backing-scale bitmap; downscaling keeps the 1:1 coordinate contract).
    ///
    /// Only the `cacheDisplay` framebuffer grab must run on the main actor — it's an AppKit view op. The
    /// expensive part (the high-quality downscale + JPEG encode) is handed to a background task via
    /// ``encode(_:)`` so it never touches the main thread. The grabbed `NSBitmapImageRep` is freshly
    /// allocated per call and touched nowhere else once filled, so moving it off-main is a safe hand-off
    /// (boxed because `NSBitmapImageRep` isn't `Sendable`).
    func capture(name: String) async -> Data? {
        guard let boxed = await grabFramebuffer(name) else { return nil }
        let width = Self.fbWidth, height = Self.fbHeight  // read the main-actor constants here, pre-hop
        return await Task.detached(priority: .userInitiated) {
            Self.encode(boxed.value, width: width, height: height)
        }.value
    }

    /// The OCR path: the SAME framebuffer grab, encoded **as-is** — no downscale to the 1920×1200
    /// coordinate space and no lossy compression.
    ///
    /// Both of the steps `capture` performs are actively harmful to text recognition. The downscale
    /// halves every glyph (macOS body labels render ~13 pt, so they arrive at ~13 px — below where
    /// Vision reads reliably), and JPEG at 0.7 rings the subpixel-antialiased edges that are the only
    /// thing separating similar glyphs at that size. Handing Vision the untouched backing-scale bitmap
    /// costs one PNG encode and removes both.
    func captureForRecognition(name: String) async -> Data? {
        guard let boxed = await grabFramebuffer(name) else { return nil }
        let width = Self.fbWidth, height = Self.fbHeight
        return await Task.detached(priority: .userInitiated) {
            // Lossless, at whatever resolution the grab carried. Falls back to the normalized JPEG
            // rather than returning nothing, so a rep PNG can't encode still yields a usable frame.
            boxed.value.representation(using: .png, properties: [:])
                ?? Self.encode(boxed.value, width: width, height: height)
        }.value
    }

    /// Grab the guest framebuffer into a fresh `NSBitmapImageRep`, respecting the app-wide main-thread
    /// budget. Boxed for the hop off the main actor: the rep is freshly allocated per call and touched
    /// nowhere else once filled, so the hand-off is safe even though `NSBitmapImageRep` isn't
    /// `Sendable`. Only this step must run on the main actor — every encode is a background task.
    private func grabFramebuffer(_ name: String) async -> UncheckedSendableBox<NSBitmapImageRep>? {
        guard let e = await activate(name) else { return nil }
        markUsed(name)
        guard await awaitFramebufferBudget() else { return nil }
        // The budget wait yields the main actor; a concurrent VM stop may have detached this entry.
        guard let active = entries[name], active.window === e.window else { return nil }
        let view = active.view
        guard let rep = view.bitmapImageRepForCachingDisplay(in: view.bounds) else { return nil }
        view.cacheDisplay(in: view.bounds, to: rep)
        return UncheckedSendableBox(value: rep)
    }

    /// Downscale a raw backing-scale framebuffer bitmap to a `width`×`height` JPEG. `nonisolated` so it
    /// runs on the caller's background task, off the main actor. Drawing into an offscreen
    /// `NSBitmapImageRep` via a per-thread `NSGraphicsContext` is safe off-main (the bitmaps are unshared
    /// and created here). Dimensions are passed in because the `fbWidth`/`fbHeight` constants are
    /// main-actor-isolated.
    nonisolated private static func encode(_ rep: NSBitmapImageRep, width: Int, height: Int) -> Data? {
        let target = NSSize(width: CGFloat(width), height: CGFloat(height))
        guard let out = NSBitmapImageRep(
            bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height,
            bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
            colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0)
        else { return nil }
        out.size = target
        NSGraphicsContext.saveGraphicsState()
        NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: out)
        NSGraphicsContext.current?.imageInterpolation = .high
        let img = NSImage(size: target)
        img.addRepresentation(rep)
        img.draw(in: NSRect(origin: .zero, size: target))
        NSGraphicsContext.restoreGraphicsState()

        return out.representation(using: .jpeg, properties: [.compressionFactor: 0.7])
    }

    func send(name: String, _ input: MacVMSurfaceInput) async {
        guard let e = await activate(name) else { return }
        markUsed(name)
        let view = e.view, window = e.window
        switch input {
        case let .move(x, y):
            await postMouseSequence(
                [.init(type: .mouseMoved, point: guestPoint(x, y, in: view))], window: window)
            cursors[name] = CGPoint(x: x, y: y)

        case let .click(x, y, button, count):
            let p = guestPoint(x, y, in: view)
            let (down, up): (NSEvent.EventType, NSEvent.EventType) =
                button == .right ? (.rightMouseDown, .rightMouseUp) : (.leftMouseDown, .leftMouseUp)
            // Move FIRST, as its own posted event, and let the guest actually reposition its pointer
            // before the button goes down. Posting the move and the press back-to-back races: the guest
            // can process the button-down while its pointer is still at the PREVIOUS location, so the
            // click lands on whatever was under the old position. That is how clicks aimed at an
            // inactive dialog kept activating the window behind it instead — and why the same click
            // "sometimes worked if lucky". The settle is short enough to stay imperceptible per action.
            await postMouseSequence([.init(type: .mouseMoved, point: p)], window: window)
            try? await Task.sleep(for: .milliseconds(pointerSettleMillis))
            var steps: [MouseStep] = []
            // A double click is two complete gestures whose second pair carries clickCount=2. Sending
            // one pair marked as count 2 skips the first click and is not AppKit's double-click shape.
            for click in 1...max(1, count) {
                steps.append(MouseStep(type: down, point: p, clickCount: click))
                steps.append(MouseStep(type: up, point: p, clickCount: click))
            }
            await postMouseSequence(steps, window: window)
            cursors[name] = CGPoint(x: x, y: y)

        case let .drag(fromX, fromY, toX, toY):
            let from = guestPoint(fromX, fromY, in: view), to = guestPoint(toX, toY, in: view)
            await postMouseSequence(
                [
                    .init(type: .mouseMoved, point: from),
                    .init(type: .leftMouseDown, point: from),
                    .init(type: .leftMouseDragged, point: to),
                    .init(type: .leftMouseUp, point: to),
                ],
                window: window)
            cursors[name] = CGPoint(x: toX, y: toY)

        case let .scroll(x, y, dx, dy):
            // 1. Put the guest's pointer over the target. A wheel event carries no coordinates of its
            // own — neither VZ nor the guest window server takes them from the event — so the guest
            // delivers the scroll to whatever view its OWN pointer is over. Without this, a scroll after
            // clicking in a sidebar scrolled the sidebar. Skipped when the pointer is already there, so
            // the common case pays no pointer settle and no spurious hover.
            if cursors[name] != CGPoint(x: x, y: y) {
                await postMouseSequence(
                    [.init(type: .mouseMoved, point: guestPoint(x, y, in: view))], window: window)
                try? await Task.sleep(for: .milliseconds(pointerSettleMillis))
                cursors[name] = CGPoint(x: x, y: y)
            }
            // 2. Deliver the distance as a paced stream of small notches rather than one big delta.
            // Apps with smooth scrolling animate per event and coalesce anything that arrives mid-flight,
            // so a single 30-line event moved about one notch — see `MacVMEngine.scrollLinesPerTick`.
            var firstTick = true
            for tick in MacVMEngine.scrollTicks(dx: dx, dy: dy) {
                if !firstTick {
                    try? await Task.sleep(for: .milliseconds(MacVMEngine.scrollTickIntervalMillis))
                }
                firstTick = false
                postScroll(dx: tick.dx, dy: tick.dy, view: view)
            }

        case let .key(chord):
            if let s = MacVMKeyMap.stroke(forChord: chord) { postStroke(s, view: view, name: name) }

        case let .text(text):
            // PACED, deliberately. Each stroke lands as USB HID reports on the guest's virtual
            // keyboard, whose interrupt endpoint has a finite queue. Synthesizing a whole payload in
            // one tight loop overruns it: the guest silently coalesces away the reports it can't
            // take, so the TAIL of the burst vanishes while the send still reports success. Observed
            // on Linux guests as a chunk's tail dropping (`narOS VM input-in` + the next chunk), and
            // as a shifted character surviving its dropped keyDown — a stray capital — when the
            // overrun split a `flagsChanged` from the key it modified. The mouse path pays the same
            // tax deliberately (see `postMouseSequence`); this one had no pacing at all.
            //
            // Linux guests feel it and macOS ones don't because `typeLongSurfaceText` routes macOS to
            // the in-guest agent's `type` op (CGEvents synthesized guest-side); Linux has no such
            // agent, so every Linux `type` arrives here.
            var first = true
            for ch in text {
                guard let s = MacVMKeyMap.stroke(forCharacter: ch) else { continue }
                if !first { try? await Task.sleep(for: .milliseconds(Self.interStrokeMillis)) }
                first = false
                postStroke(s, view: view, name: name)
            }
        }
    }

    /// Gap between synthesized keystrokes in a `.text` payload, so the burst stays under the guest
    /// virtual keyboard's HID report rate instead of overrunning its endpoint queue (see `.text`
    /// above). Small enough that typing stays responsive (~200 ms for a 70-character string), large
    /// enough to clear the endpoint between strokes. Each sleep also yields the main actor, so a long
    /// payload interleaves with host work rather than monopolizing it.
    static let interStrokeMillis = 3

    /// How long to let the guest's pointer arrive at a new location before pressing the button. The
    /// guest's virtual trackpad processes the move as its own HID report; pressing in the same batch
    /// can be handled while the pointer is still at its previous position, sending the click to the
    /// wrong window entirely.
    let pointerSettleMillis = 180

    // MARK: - NSEvent synthesis (delivered to the view; no system event posting ⇒ no permissions)

    /// Guest (top-left origin, 1920×1200 logical) → window point (AppKit bottom-left origin), **scaled
    /// to the view's current size**.
    ///
    /// Off-screen the HID window is a native 1920×1200, so this is the identity flip. But when the
    /// diagnostic monitor / operator-assist viewer is shown, the window is resized (1280×800) and the
    /// `VZVirtualMachineView` autoresizes to fit — so an event location computed for 1920×1200 lands in
    /// the wrong place (a base-build double-click on the enrollment row hit the desktop instead). The
    /// event's `locationInWindow` must be in the *current* window/view space, so scale by the view's
    /// live bounds; VZ maps that back to the guest. Reduces to `(x, 1200−y)` when the view is 1920×1200.
    private func guestPoint(_ x: Int, _ y: Int, in view: NSView) -> NSPoint {
        let w = view.bounds.width, h = view.bounds.height
        guard w > 0, h > 0 else { return NSPoint(x: CGFloat(x), y: CGFloat(Self.fbHeight - y)) }
        return NSPoint(
            x: CGFloat(x) / CGFloat(Self.fbWidth) * w,
            y: (1 - CGFloat(y) / CGFloat(Self.fbHeight)) * h)
    }

    private struct MouseStep {
        let type: NSEvent.EventType
        let point: NSPoint
        var clickCount = 1
    }

    /// Queue a COMPLETE mouse gesture through AppKit rather than synchronously calling
    /// `window.sendEvent` for each piece. `VZVirtualMachineView.mouseDown(with:)` may enter AppKit's
    /// mouse-tracking loop and wait for the matching mouse-up/drag event. With synchronous dispatch the
    /// down call therefore never returned, the following up call was never reached, and the main actor
    /// (including the VM monitor and MCP reply) wedged. Posting the entire sequence first lets that
    /// tracking loop consume its release event normally.
    private func postMouseSequence(_ steps: [MouseStep], window: NSWindow) async {
        var posted = false
        for step in steps {
            guard let event = NSEvent.mouseEvent(
                with: step.type, location: step.point, modifierFlags: [],
                timestamp: ProcessInfo.processInfo.systemUptime, windowNumber: window.windowNumber,
                context: nil, eventNumber: 0, clickCount: step.clickCount,
                pressure: step.type.isMouseDown ? 1 : 0)
            else { continue }
            NSApp.postEvent(event, atStart: false)
            posted = true
        }
        // `send` is awaited immediately before framebuffer capture. Suspend the main actor briefly so
        // NSApplication can drain the queued gesture and the returned screenshot reflects the action.
        if posted { try? await Task.sleep(for: .milliseconds(20)) }
    }

    /// Deliver ONE wheel notch. Callers pace a gesture across several of these (see `.scroll` above);
    /// this must not be handed a whole gesture's delta in one call.
    private func postScroll(dx: Int, dy: Int, view: NSView) {
        // NSEvent has no scroll constructor; build a line-unit scroll CGEvent and wrap it (we deliver
        // it to the view directly, never posting it to the system, so no accessibility grant needed).
        guard let cg = CGEvent(
            scrollWheelEvent2Source: nil, units: .line, wheelCount: 2,
            wheel1: Int32(dy), wheel2: Int32(dx), wheel3: 0),
            let e = NSEvent(cgEvent: cg)
        else { return }
        view.scrollWheel(with: e)
    }

    /// Append the keyboard-injection preconditions for the base-build VM to a host-readable log, so a
    /// stuck provisioning run can be diagnosed without eyes on the guest: is the VM window key, is the
    /// VZ view first responder, is the app active? Provisioning-only (keyed off the base surface name)
    /// and best-effort — never throws into the input path.
    /// Append one line to the base-VM HID diagnostic log (host-readable at
    /// `$TMPDIR/nucleic-hid-diag.log`). Provisioning-only (keyed off the base surface name) and
    /// best-effort — never throws into the input path.
    private func diagWrite(_ name: String, _ line: String) {
        guard name == MacVMEngine.baseProvisionSurfaceName else { return }
        let url = URL(fileURLWithPath: NSTemporaryDirectory())
            .appendingPathComponent("nucleic-hid-diag.log")
        guard let data = "\(Date()) \(line)\n".data(using: .utf8) else { return }
        if let fh = try? FileHandle(forWritingTo: url) {
            defer { try? fh.close() }
            fh.seekToEndOfFile()
            fh.write(data)
        } else {
            try? data.write(to: url)
        }
    }

    private func postStroke(_ s: MacVMKeyStroke, view: NSView, name: String) {
        // Deliver keystrokes to the guest in the BACKGROUND, exactly like the mouse path — hand the
        // events straight to the VZVirtualMachineView's responder instead of routing them through
        // `NSApp`/key-window dispatch. That routing is what forced the app to activate and steal focus
        // (AppKit sends key events only to the *key* window); calling the view's methods directly
        // bypasses it, so the surface window never needs to be key or on-screen.
        //
        // Two subtleties:
        //  • CGEvent backing — VZVirtualMachineView derives the guest HID scancode from the event's
        //    underlying CGEvent (a hand-built `NSEvent.keyEvent` has none and types nothing).
        //  • Modifiers are their OWN `flagsChanged` events — the view tracks the guest's modifier state
        //    from those, NOT from a `.command` flag on a keyDown. So ⌘Space must be: press ⌘
        //    (flagsChanged) → Space down/up → release ⌘, or it arrives as a bare Space.

        // (virtualKey, flag) for each held modifier, in a stable press order. Each flag combines the
        // device-INDEPENDENT mask (.maskCommand …) with the device-DEPENDENT left-key bit (NX_DEVICE*
        // masks: LCMD 0x8, LSHIFT 0x2, LALT 0x20, LCTL 0x1). A real keypress carries both; when we hand
        // events straight to the view (rather than posting them through the system, which would fill
        // these in), VZVirtualMachineView needs the device bit to recognize the modifier — with only
        // the independent mask, ⌘Space arrives as a bare Space.
        func flag(_ mask: CGEventFlags, _ deviceBit: UInt64) -> CGEventFlags {
            CGEventFlags(rawValue: mask.rawValue | deviceBit)
        }
        var mods: [(UInt16, CGEventFlags)] = []
        if s.command { mods.append((0x37, flag(.maskCommand, 0x8))) }    // kVK_Command  + NX_DEVICELCMD
        if s.shift { mods.append((0x38, flag(.maskShift, 0x2))) }        // kVK_Shift    + NX_DEVICELSHIFT
        if s.option { mods.append((0x3A, flag(.maskAlternate, 0x20))) }  // kVK_Option   + NX_DEVICELALT
        if s.control { mods.append((0x3B, flag(.maskControl, 0x1))) }    // kVK_Control  + NX_DEVICELCTL
        if s.function { mods.append((0x3F, .maskSecondaryFn)) }          // kVK_Function

        var trace: [String] = []
        var flags: CGEventFlags = []
        // Press modifiers: accumulate the flag and emit a flagsChanged for each.
        for (code, flag) in mods {
            flags.insert(flag)
            trace.append("fcDown(\(code))=\(postCGKey(virtualKey: code, keyDown: true, flags: flags, type: .flagsChanged, to: view))")
        }
        // The key itself, down then up, with the modifiers held.
        trace.append("down=\(postCGKey(virtualKey: s.keyCode, keyDown: true, flags: flags, type: .keyDown, to: view))")
        trace.append("up=\(postCGKey(virtualKey: s.keyCode, keyDown: false, flags: flags, type: .keyUp, to: view))")
        // Release modifiers in reverse: clear the flag and emit a flagsChanged for each.
        for (code, flag) in mods.reversed() {
            flags.remove(flag)
            trace.append("fcUp(\(code))=\(postCGKey(virtualKey: code, keyDown: false, flags: [], type: .flagsChanged, to: view))")
        }
        if !mods.isEmpty {
            diagWrite(name, "stroke key=0x\(String(s.keyCode, radix: 16)) mods=\(mods.count) \(trace.joined(separator: " "))")
        }
    }

    /// Build one CGEvent-backed key/modifier event and hand it straight to the VM view's responder.
    /// Returns whether an `NSEvent` was actually produced and delivered (for diagnostics).
    @discardableResult
    private func postCGKey(
        virtualKey: UInt16, keyDown: Bool, flags: CGEventFlags, type: CGEventType, to view: NSView
    ) -> Bool {
        guard let cg = CGEvent(keyboardEventSource: nil, virtualKey: virtualKey, keyDown: keyDown)
        else { return false }
        cg.flags = flags
        cg.type = type  // a modifier press is a flagsChanged, not a keyDown
        guard let e = NSEvent(cgEvent: cg) else { return false }
        switch type {
        case .flagsChanged: view.flagsChanged(with: e)
        case .keyUp: view.keyUp(with: e)
        default: view.keyDown(with: e)
        }
        return true
    }
}

extension NSEvent.EventType {
    fileprivate var isMouseDown: Bool { self == .leftMouseDown || self == .rightMouseDown }
}

/// A borderless window whose ability to become key/main is opt-in via ``isKeyable``, defaulting to
/// `false`. This matters for input isolation: a `VZVirtualMachineView` in a key window routes the
/// host's real keyboard into the guest, so the normally off-screen, agent-driven HID window must NOT be
/// able to take key — otherwise it can win key focus on app activation and silently "capture" the
/// user's typing. Background agent input needs no key window (keystrokes go straight to the view's
/// responder). Only when the window is deliberately brought on-screen for the diagnostic monitor /
/// operator-assist hand-off — where the user drives the guest by hand — is ``isKeyable`` flipped `true`
/// so it can take key. Plain `.borderless` windows return `false` for both unconditionally.
private final class KeyableWindow: NSWindow {
    /// When `true`, the window may become key/main (on-screen, user-driven). `false` off-screen so the
    /// guest can never capture the user's keyboard while the agent has exclusive control.
    var isKeyable = false
    /// When `true`, the window is deliberately parked off-screen (agent-driven) and must stay there.
    /// AppKit calls `constrainFrameRect(_:to:)` to pull windows lying outside all displays back onto a
    /// valid screen — notably when the display arrangement changes (a monitor is attached/detached).
    /// Honoring that would surface the borderless VM view to the user, so while pinned we return the
    /// requested frame unconstrained. Cleared only when the window is intentionally brought on-screen.
    var pinnedOffScreen = false
    override var canBecomeKey: Bool { isKeyable }
    override var canBecomeMain: Bool { isKeyable }
    override func constrainFrameRect(_ frameRect: NSRect, to screen: NSScreen?) -> NSRect {
        pinnedOffScreen ? frameRect : super.constrainFrameRect(frameRect, to: screen)
    }
}
#endif
