import AppKit
import Testing
@testable import Kanban

/// Per-board frame memory has one rule that is not "put it back where it was": a frame saved on a
/// display that is no longer attached must land somewhere visible (02-architecture.md § Windows).
/// That rule is untestable against real hardware — the interesting case *is* the monitor that is not
/// plugged in — which is why the decision takes its screens as an argument.

@MainActor
@Suite("Window placement")
struct WindowPlacementTests {

    private let laptop = NSRect(x: 0, y: 0, width: 1512, height: 916)
    private let external = NSRect(x: 1512, y: 0, width: 2560, height: 1415)

    @Test("A frame on an attached screen is restored exactly")
    func aVisibleFrameIsUntouched() {
        let saved = WindowFrame(x: 120, y: 80, width: 1200, height: 700)
        let placed = HostedWindowController.placement(for: saved, onScreens: [laptop, external], fallback: laptop)
        #expect(placed == NSRect(x: 120, y: 80, width: 1200, height: 700))
    }

    @Test("A frame straddling two screens is still where the user left it")
    func aStraddlingFrameIsUntouched() {
        // AppKit's own `constrainFrameRect(_:to:)` nudges the remainder into view when the frame is
        // set, so intersection — not containment — is the right test: a window hanging slightly off
        // an edge is a place, not a problem.
        let saved = WindowFrame(x: 1400, y: 100, width: 900, height: 600)
        let placed = HostedWindowController.placement(for: saved, onScreens: [laptop, external], fallback: laptop)
        #expect(placed.origin.x == 1400)
    }

    @Test("A frame on a screen that is gone keeps its size and centers on the fallback")
    func aVanishedScreenRelocates() {
        let saved = WindowFrame(x: 3000, y: 200, width: 1000, height: 600)
        let placed = HostedWindowController.placement(for: saved, onScreens: [laptop], fallback: laptop)

        // Size is a preference and survives; position is a place, and the place stopped existing.
        #expect(placed.size == NSSize(width: 1000, height: 600))
        #expect(placed.midX == laptop.midX)
        #expect(placed.midY == laptop.midY)
        #expect(laptop.intersects(placed))
    }

    @Test("With no screens at all the fallback still produces a frame")
    func noScreensStillPlaces() {
        // Not a real state, but the accessor's `NSScreen.screens` can be empty during a display
        // reconfiguration, and returning something sane beats a window at the saved coordinates of a
        // display nobody has.
        let saved = WindowFrame(x: 4000, y: 4000, width: 800, height: 500)
        let placed = HostedWindowController.placement(for: saved, onScreens: [], fallback: laptop)
        #expect(placed.size == NSSize(width: 800, height: 500))
        #expect(laptop.contains(placed.origin))
    }
}
