import XCTest

final class MergedInstanceUITests: ForgejoUITestBase {

    private var serverURL2: String?

    override func setUpWithError() throws {
        try super.setUpWithError()
        serverURL2 = resolveSecondServerURL()
        // Clear SwiftData instances from previous test methods
        app.launchArguments = ["-dev_skipAutoLogin", "true", "-dev_resetData", "true"]
        app.launch()
        app.terminate()
    }

    // MARK: - Helpers

    /// Launches with skipAutoLogin, pre-filling the form with the given dev credentials.
    /// After tapping + then Login, the app goes to HomeView. We then relaunch with
    /// skipAutoLogin again so the instance list re-appears with the saved instance.
    private func addInstanceViaRelaunch(
        serverURL url: String,
        username: String = "testadmin",
        password: String = "admin1234",
    ) {
        // Launch with form pre-fill + skip auto-login
        app.launchArguments = [
            "-dev_serverURL", url,
            "-dev_username", username,
            "-dev_password", password,
            "-dev_skipAutoLogin", "true",
        ]
        app.launch()

        let addButton = app.buttons["instance-add-button"]
        XCTAssertTrue(addButton.waitForExistence(timeout: 15), "Instance list did not appear")
        addButton.tap()

        // Form is pre-filled from dev launch args, scroll and tap login
        app.swipeUp()

        let loginButton = app.buttons["login-button"]
        XCTAssertTrue(loginButton.waitForExistence(timeout: 5), "Login button not found")
        loginButton.tap()

        // Wait for HomeView to appear (login succeeded, instance saved to SwiftData)
        let reposTab = app.tabBars.buttons["Repositories"]
        XCTAssertTrue(reposTab.waitForExistence(timeout: 20), "HomeView did not appear after login")
    }

    /// Relaunches the app skipping auto-login to land on the instance list.
    private func relaunchToInstanceList() {
        app.launchArguments = ["-dev_skipAutoLogin", "true"]
        app.launch()

        let addButton = app.buttons["instance-add-button"]
        XCTAssertTrue(
            addButton.waitForExistence(timeout: 15)
                || app.collectionViews["instance-list"].waitForExistence(timeout: 5),
            "Instance list did not appear",
        )
    }

    /// Sets up two instances and relaunches to instance list.
    private func setupTwoInstances() throws {
        guard let url2 = serverURL2 else {
            throw XCTSkip("Second integration server not available")
        }

        // Add first instance
        addInstanceViaRelaunch(serverURL: serverURL)

        // Add second instance (relaunch adds to SwiftData)
        addInstanceViaRelaunch(serverURL: url2)

        // Relaunch to instance list with both instances persisted
        relaunchToInstanceList()
    }

    /// Enters merged mode from the instance list.
    private func enterMergedMode() {
        let allRow = app.buttons["all-instances-row"]
        XCTAssertTrue(allRow.waitForExistence(timeout: 10), "All Instances row not found")
        allRow.tap()

        let reposTab = app.tabBars.buttons["Repositories"]
        XCTAssertTrue(reposTab.waitForExistence(timeout: 20), "Merged HomeView did not load")
    }

    // MARK: - Tests

    @MainActor
    func testAllInstancesRowAppearsWithMultipleInstances() throws {
        try setupTwoInstances()

        let allRow = app.buttons["all-instances-row"]
        XCTAssertTrue(allRow.waitForExistence(timeout: 5), "All Instances row should appear with multiple instances")
    }

    @MainActor
    func testAllInstancesRowHiddenWithSingleInstance() throws {
        addInstanceViaRelaunch(serverURL: serverURL)
        relaunchToInstanceList()

        let allRow = app.buttons["all-instances-row"]
        XCTAssertFalse(allRow.exists, "All Instances row should not appear with single instance")
    }

    @MainActor
    func testDisconnectFromMergedMode() throws {
        try setupTwoInstances()
        enterMergedMode()

        app.tabBars.buttons["Settings"].tap()

        // Scroll down to reveal Switch Instance button
        app.swipeUp()

        let switchButton = app.buttons["home-switch-instance-button"]
        XCTAssertTrue(switchButton.waitForExistence(timeout: 5))
        switchButton.tap()

        let instanceList = app.collectionViews["instance-list"]
        XCTAssertTrue(instanceList.waitForExistence(timeout: 10), "Should return to instance list after disconnect")
    }

    @MainActor
    func testMergedNotificationSwipeMarkRead() throws {
        try setupTwoInstances()
        enterMergedMode()

        app.tabBars.buttons["Notifications"].tap()

        let notificationsList = app.collectionViews.firstMatch
        XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))

        let firstCell = notificationsList.cells.firstMatch
        XCTAssertTrue(firstCell.waitForExistence(timeout: 10), "Should have at least one notification")

        // Swipe right to mark as read (the only notification swipe action)
        firstCell.swipeRight()
        let markReadButton = app.buttons["Mark Read"]
        XCTAssertTrue(markReadButton.waitForExistence(timeout: 3), "Mark Read swipe action should appear")
        markReadButton.tap()
    }

    // MARK: - Server URL Helpers

    private func resolveSecondServerURL() -> String? {
        let deviceName = (ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] ?? "")
            .replacingOccurrences(of: " ", with: "_")
        let specificPath = "/tmp/forgejo_test_url2_\(deviceName).txt"
        let genericPath = "/tmp/forgejo_test_url2.txt"

        return ((try? String(contentsOfFile: specificPath, encoding: .utf8))
            ?? (try? String(contentsOfFile: genericPath, encoding: .utf8)))
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
    }
}
