import XCTest

/// Base class for read-only UI tests that share a single app launch per class.
/// The app is launched once in `class setUp()` and reused across all test methods,
/// avoiding the overhead of repeated app launches for tests that don't mutate data.
class ForgejoReadOnlyUITestBase: XCTestCase, UITestNavigating {

    static var sharedApp: XCUIApplication!
    static var sharedServerURL: String!

    override class func setUp() {
        super.setUp()

        guard let url = ForgejoUITestBase.resolveTestServerURL(),
            !url.isEmpty
        else {
            // Can't XCTSkip from class setUp, individual tests will skip
            return
        }
        sharedServerURL = url

        let app = XCUIApplication()
        app.launchArguments += [
            "-dev_serverURL", url,
            "-dev_username", "testadmin",
            "-dev_password", "admin1234",
        ]
        app.launch()

        let reposTab = app.tabBars.buttons["Repositories"]
        guard reposTab.waitForExistence(timeout: 15) else {
            XCTFail("HomeView did not appear after auto-login in class setUp")
            return
        }
        sharedApp = app
    }

    override class func tearDown() {
        sharedApp = nil
        sharedServerURL = nil
        super.tearDown()
    }

    // MARK: - Instance setup

    /// Non-optional convenience accessor (instance-level).
    var app: XCUIApplication! { Self.sharedApp }
    var serverURL: String! { Self.sharedServerURL }

    override func setUpWithError() throws {
        continueAfterFailure = true

        guard Self.sharedServerURL != nil, Self.sharedApp != nil else {
            throw XCTSkip("Integration server not running")
        }

        // Force portrait orientation
        XCUIDevice.shared.orientation = .portrait

        // Ensure we're at the home screen (Repositories tab as anchor)
        let reposTab = app.tabBars.buttons["Repositories"]
        if !reposTab.waitForExistence(timeout: 5) {
            // Recovery: app may have crashed or navigated away, relaunch
            let freshApp = XCUIApplication()
            freshApp.launchArguments += [
                "-dev_serverURL", Self.sharedServerURL,
                "-dev_username", "testadmin",
                "-dev_password", "admin1234",
            ]
            freshApp.launch()
            guard freshApp.tabBars.buttons["Repositories"].waitForExistence(timeout: 15) else {
                XCTFail("Could not recover app to home screen")
                return
            }
            Self.sharedApp = freshApp
        }
    }

    // MARK: - Helpers

    func navigateBackToHome() {
        guard app != nil else { return }

        // Switch to Repositories tab first
        let reposTab = app.tabBars.buttons["Repositories"]
        if reposTab.exists && reposTab.isHittable {
            reposTab.tap()
        }

        // Pop any navigation stack on the Repositories tab back to root
        let repoList = app.collectionViews["repo-list"]
        for _ in 0..<10 {
            if repoList.waitForExistence(timeout: 1) { break }
            let navBarButtons = app.navigationBars.buttons
            guard navBarButtons.count > 0 else { break }
            let backButton = navBarButtons.element(boundBy: 0)
            guard backButton.exists && backButton.isHittable else { break }
            backButton.tap()
        }
    }

    func navigateToRepoDetail(_ repoName: String = "test-repo") {
        app.tabBars.buttons["Repositories"].tap()

        // Ensure we're at the repo list root, not deep in navigation
        let repoList = app.collectionViews["repo-list"]
        if !repoList.waitForExistence(timeout: 3) {
            for _ in 0..<5 {
                let navBarButtons = app.navigationBars.buttons
                guard navBarButtons.count > 0 else { break }
                let backButton = navBarButtons.element(boundBy: 0)
                guard backButton.exists && backButton.isHittable else { break }
                backButton.tap()
                if repoList.waitForExistence(timeout: 1) { break }
            }
        }

        let repoCell = app.staticTexts[repoName].firstMatch
        XCTAssertTrue(repoCell.waitForExistence(timeout: 10))
        repoCell.tap()
    }

}
