import XCTest

final class SessionReviewTests: XCTestCase {
    func testSavedFixtureChartsFilterAndReopen() {
        let app = XCUIApplication()
        app.launchArguments = ["--uitest-motion", "--uitest-review"]
        app.launch()
        XCTAssertTrue(app.staticTexts["savedSession"].waitForExistence(timeout: 10))
        XCTAssertTrue(app.staticTexts["savedEventCount"].label.contains("2 events"))
        reveal(app.switches["analysisFilter"], in: app)
        XCTAssertTrue(app.staticTexts["analysisConfiguration"].waitForExistence(timeout: 10))
        XCTAssertTrue(app.staticTexts["analysisConfiguration"].label.contains("n=601"))
        app.switches["analysisFilter"].tap()
        app.buttons["recomputeAnalysis"].tap()
        expectation(for:NSPredicate(format:"label CONTAINS 'localPolynomial'"),evaluatedWith:app.staticTexts["analysisConfiguration"])
        waitForExpectations(timeout:10)
        XCTAssertTrue(app.staticTexts["analysisConfiguration"].label.contains("n=601"))
        for (kind, title) in [("angle", "Relative angle (°)"), ("velocity", "Gyro angular velocity (rad/s)"), ("angularAcceleration", "Angular acceleration (rad/s²)"), ("userAcceleration", "User acceleration (g)")] {
            let chart = app.descendants(matching:.any)["timeline_"+kind]
            let heading = app.staticTexts[title]
            reveal(heading, in:app)
            XCTAssertTrue(heading.isHittable)
            XCTAssertTrue(chart.exists)
            let attachment = XCTAttachment(screenshot:app.screenshot())
            attachment.name = "review-"+kind; attachment.lifetime = .keepAlways; add(attachment)
        }
        app.buttons["sessions"].tap()
        app.descendants(matching:.any).matching(identifier:"sessionRow").firstMatch.tap()
        XCTAssertTrue(app.staticTexts["savedSession"].waitForExistence(timeout:10))
        reveal(app.staticTexts["analysisConfiguration"], in:app)
        XCTAssertTrue(app.staticTexts["analysisConfiguration"].label.contains("n=601"))
    }
    func testDiagnosticsWithoutCalibrationAndEarlyStopExplicitlyUnavailable() {
        let app = XCUIApplication()
        app.launchArguments = ["--uitest-motion"]
        app.launch()
        app.buttons["diagnostics"].tap()
        app.buttons["startDiagnostics"].tap()
        XCTAssertTrue(app.staticTexts["diagnosticInstruction"].waitForExistence(timeout:5))
        XCTAssertTrue(app.staticTexts["diagnosticInstruction"].label.contains("30 seconds"))
        app.buttons["stopDiagnostics"].tap()
        XCTAssertTrue(app.staticTexts["savedSession"].waitForExistence(timeout:10))
        XCTAssertTrue(app.staticTexts["analysisUnavailable"].exists)
        XCTAssertTrue(app.descendants(matching:.any)["diagnosticSummary"].exists)
        XCTAssertTrue(app.staticTexts["savedEventCount"].label.contains("2 events"))
    }
    func testThirtySecondProtocolPersistsAllMovementInstructions() {
        let app = XCUIApplication()
        app.launchArguments = ["--uitest-motion"]
        app.launch()
        app.buttons["diagnostics"].tap()
        app.buttons["startDiagnostics"].tap()
        let next = app.buttons["nextDiagnosticDrill"]
        XCTAssertTrue(next.waitForExistence(timeout: 35))
        let drills = ["SLOW LEFT", "RETURN CENTER", "SLOW RIGHT", "RETURN CENTER", "SLOW FORWARD", "RETURN CENTER", "RAPID LEFT", "RETURN CENTER", "RAPID RIGHT", "RETURN CENTER", "RAPID FORWARD", "RETURN CENTER"]
        for drill in drills {
            XCTAssertEqual(app.staticTexts["diagnosticInstruction"].label, drill)
            next.tap()
        }
        XCTAssertTrue(app.staticTexts["savedSession"].waitForExistence(timeout: 10))
        XCTAssertTrue(app.staticTexts["savedEventCount"].label.contains("15 events"))
        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "diagnostics-30-second-synthetic"; attachment.lifetime = .keepAlways; add(attachment)
    }
    private func reveal(_ element: XCUIElement, in app: XCUIApplication) {
        for _ in 0..<20 {
            if element.isHittable { return }
            let labels = ["analysisConfiguration", "Relative angle (°)", "Gyro angular velocity (rad/s)", "Angular acceleration (rad/s²)", "User acceleration (g)"]
            let anchor = labels.map { app.staticTexts[$0] }.filter {
                $0.isHittable && (0.25...0.9).contains($0.frame.midY / app.frame.height)
            }.max { $0.frame.midY < $1.frame.midY }
            // Start on text: dragging a plot selects its timeline instead of scrolling.
            let start = anchor.map { $0.frame.midY / app.frame.height } ?? 0.75
            app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: start))
                .press(forDuration: 0.05,
                       thenDragTo: app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: max(0.16, start - 0.25))),
                       withVelocity: .slow, thenHoldForDuration: 0.2)
        }
    }
}
