import XCTest

/// The read screen's comment thread, end to end: the fixture card's own posted comment renders
/// read-only, the composer posts a new comment through the draft-then-rename bracket, and the
/// context menu's Edit rewrites a posted body — each write asserted on disk, not just on screen.
final class CardCommentsUITests: XCTestCase {

    @MainActor
    func testCommentsReadAddAndEdit() throws {
        let (app, root) = XCUIApplication.launchedWithFixtureBoard()
        app.navigateToFirstCard()

        // Read mode first: the fixture card carries exactly one posted comment (author "rzen",
        // dated, never edited), so the header's count and the author line are both assertable
        // before this test writes anything.
        let header = app.element(labelContaining: "Comments · 1")
        XCTAssertTrue(
            header.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the comments header never appeared with the fixture's own count"
        )
        XCTAssertTrue(
            app.element(labelContaining: "rzen").exists,
            "the fixture comment's author line never rendered"
        )

        // Post a new comment. The Add button sits at the very bottom of the scroll view, below
        // the fixture card's body and footer.
        let addButton = app.buttons["Add Comment"]
        app.scrollUntilHittable(addButton)
        addButton.tap()

        let postButton = app.navigationBars.buttons["Post"]
        XCTAssertTrue(
            postButton.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the composer sheet never appeared"
        )

        let composer = app.textViews.firstMatch
        XCTAssertTrue(
            composer.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the composer's text editor never appeared"
        )
        let sentinel = "Posted from the phone by UI test"
        composer.tap()
        composer.typeText(sentinel)
        postButton.tap()

        // The sheet dismisses only on the perform's success, and the perform awaits its own
        // reload — so by the time the thread re-reads, both the screen and the disk carry it.
        XCTAssertTrue(
            app.element(labelContaining: "Comments · 2").waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the header never counted the posted comment"
        )
        XCTAssertTrue(
            app.staticTexts[sentinel].waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the posted comment's body never rendered in the thread"
        )
        XCTAssertTrue(
            waitForFile(under: root, containing: sentinel),
            "the posted comment never landed on disk under \(root.path)"
        )

        // Edit the comment just posted, through its row's context menu.
        let postedBody = app.staticTexts[sentinel]
        postedBody.press(forDuration: 1.0)

        let editAction = app.buttons["Edit Comment"]
        XCTAssertTrue(
            editAction.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the context menu's Edit Comment action never appeared"
        )
        editAction.tap()

        let saveButton = app.navigationBars.buttons["Save"]
        XCTAssertTrue(
            saveButton.waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the edit sheet never appeared"
        )
        let editor = app.textViews.firstMatch
        XCTAssertEqual(
            editor.value as? String, sentinel,
            "the edit sheet did not seed with the posted comment's body"
        )

        let rewritten = "Rewritten from the phone by UI test"
        editor.replaceAllText(with: rewritten)
        saveButton.tap()

        XCTAssertTrue(
            app.staticTexts[rewritten].waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the rewritten comment never rendered in the thread"
        )
        XCTAssertTrue(
            waitForFile(under: root, containing: rewritten),
            "the rewritten comment never landed on disk under \(root.path)"
        )
        XCTAssertTrue(
            fileDoesNotContain(under: root, substring: sentinel),
            "the pre-edit body survived on disk — the edit did not replace the body span"
        )
        // The edited indicator is `modified` differing from `created` — the save just made that
        // true, and the author line renders it as a trailing "· edited".
        XCTAssertTrue(
            app.element(labelContaining: "· edited").waitForExistence(timeout: XCUIApplication.uiTimeout),
            "the edited marker never appeared on the rewritten comment's author line"
        )
    }
}
