import XCTest

/// The one narrow mobile behavior `BoardSession` adds beyond `BoardStore`'s own machinery (this
/// card, ruled 2026-08-09): a session opened against a board with no `CLAUDE.md` at all — the
/// shape every board predating the "install at creation" fix is left in, and the shape this
/// suite's own fixture is deliberately in — gets one written the moment its board screen
/// appears, with no dependency on the board ever touching a Mac.
///
/// This is the one piece of that wiring `KanbanTests` cannot reach: the write itself
/// (`AgentGuide.install`) is the Mac's own well-covered code (`AgentGuideTests.swift`), and
/// `BoardWriterCreateBoardTests.createBoardInstallsTheCurrentAgentGuide` already proves
/// `BoardWriter.createBoard` — the one path `KanbanMobile.BoardIndexStore.createBoard` also
/// calls — installs a current guide at birth. What only exists inside the `KanbanMobile` module,
/// and so can only be driven end to end from here, is `BoardSession.open()` firing the one-shot
/// `refreshAgentGuideOnce()` for a board that predates that guarantee. `KanbanMobileUITests`
/// black-boxes the app (plain `XCTest`, no `@testable import KanbanMobile`), so this asserts on
/// the marker prefix rather than `AgentGuide.version` — a version bump does not need to touch
/// this file, and the KanbanTests suite is what pins the exact version and byte content.
final class AgentGuideUITests: XCTestCase {

    /// Boards list → tap the fixture board → its lane screen appears — no need to drill into a
    /// lane or a card, which is what keeps this the cheapest possible proof of the wiring rather
    /// than a rerun of `navigateToFirstCard`'s own coverage: `BoardScreen`'s
    /// `.task { session.open() }` is what fires the refresh, and it fires the moment the lane
    /// list itself appears.
    @MainActor
    func testOpeningABoardWithNoGuideInstallsOne() throws {
        let (app, root) = XCUIApplication.launchedWithFixtureBoard()

        let boardRow = app.element(labelContaining: RichBoard.title)
        XCTAssertTrue(
            boardRow.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the \"\(RichBoard.title)\" row never appeared — check the fixture copy or the first scan"
        )
        boardRow.tap()

        XCTAssertTrue(
            waitForAgentGuide(under: root),
            "no CLAUDE.md carrying the app's marker ever appeared under \(root.path)"
        )
    }
}

/// `waitForFile(under:containing:)` only ever looks at files named `index.md` (every other test
/// in this bundle is asserting on a card's or a board's own content) — wrong shape for a file
/// named `CLAUDE.md`, so this polls the one path a guide install can land on directly instead of
/// walking the tree. Same 0.25s-poll shape as its sibling, for the same reason: the write reaches
/// disk asynchronously, well after `BoardScreen`'s `.task { session.open() }` returns.
private func waitForAgentGuide(under root: URL, timeout: TimeInterval = 15) -> Bool {
    let guideURL = root
        .appendingPathComponent(RichBoard.packageName, isDirectory: true)
        .appendingPathComponent("CLAUDE.md")
    let deadline = Date().addingTimeInterval(timeout)
    repeat {
        if let text = try? String(contentsOf: guideURL, encoding: .utf8), text.contains("lanework-agent-guide v") {
            return true
        }
        RunLoop.current.run(until: Date().addingTimeInterval(0.25))
    } while Date() < deadline
    return false
}
