import ForgejoKit
import Foundation
import Testing
@testable import Forji

@MainActor
struct MultiInstanceManagerTests {

    // MARK: - Initial State

    @Test func initialStateIsDisconnected() {
        let manager = MultiInstanceManager()
        #expect(!manager.isConnected)
        #expect(manager.connections.isEmpty)
        #expect(manager.failedInstances.isEmpty)
        #expect(!manager.isConnecting)
    }

    // MARK: - Display Name

    @Test func displayNameReturnsNameWhenNotEmpty() {
        let manager = MultiInstanceManager()
        let instance = ForgejoInstance(serverURL: "https://forgejo.example.com", username: "user", name: "Work")
        #expect(manager.displayName(for: instance) == "Work")
    }

    @Test func displayNameFallsBackToServerURL() {
        let manager = MultiInstanceManager()
        let instance = ForgejoInstance(serverURL: "https://forgejo.example.com", username: "user", name: "")
        #expect(manager.displayName(for: instance) == "https://forgejo.example.com")
    }

    // MARK: - Connect with no valid credentials returns empty

    @Test func connectWithNoStoredCredentialsFails() async {
        let manager = MultiInstanceManager()
        let instance = ForgejoInstance(
            serverURL: "https://nonexistent.invalid", username: "nobody"
        )

        await manager.connect(instances: [instance])

        #expect(!manager.isConnected)
        #expect(manager.connections.isEmpty)
        #expect(manager.failedInstances.count == 1)
        #expect(!manager.isConnecting)
    }

    // MARK: - Disconnect

    @Test func disconnectAfterFailedConnectClearsState() async {
        let manager = MultiInstanceManager()
        let instance = ForgejoInstance(
            serverURL: "https://nonexistent.invalid", username: "nobody"
        )

        await manager.connect(instances: [instance])
        #expect(!manager.failedInstances.isEmpty)

        manager.disconnect()
        #expect(manager.connections.isEmpty)
        #expect(manager.failedInstances.isEmpty)
    }

    // MARK: - Connection Sources

    @Test func connectionSourcesReturnsEmptyWhenNoConnections() {
        let manager = MultiInstanceManager()
        let sources = manager.connectionSources()
        #expect(sources.isEmpty)
    }

    @Test func bootstrappedConnectionMapKeepsAccountsWithSameServerURL() async throws {
        let serverURL = "https://forgejo.example.com/"
        let normalizedServerURL = ForgejoClient.normalizeServerURL(serverURL)
        let suffix = UUID().uuidString
        let firstUsername = "alice-\(suffix)"
        let secondUsername = "bob-\(suffix)"
        let first = ForgejoInstance(
            serverURL: serverURL,
            username: firstUsername,
            useTokenAuth: true,
        )
        let second = ForgejoInstance(
            serverURL: serverURL,
            username: secondUsername,
            useTokenAuth: true,
        )

        try await KeychainManager.shared.saveToken(
            "token-\(firstUsername)",
            for: normalizedServerURL,
            username: firstUsername,
        )
        try await KeychainManager.shared.saveToken(
            "token-\(secondUsername)",
            for: normalizedServerURL,
            username: secondUsername,
        )

        let manager = MultiInstanceManager()
        manager.bootstrap(instances: [first, second])
        let bootstrapped = manager.bootstrappedConnectionsByAccountKey()

        #expect(manager.connections.count == 2)
        #expect(bootstrapped.count == 2)
        #expect(
            bootstrapped[manager.accountKey(for: first)]?.instance.username == firstUsername
        )
        #expect(
            bootstrapped[manager.accountKey(for: second)]?.instance.username == secondUsername
        )

        try await KeychainManager.shared.deleteToken(
            for: normalizedServerURL,
            username: firstUsername,
        )
        try await KeychainManager.shared.deleteToken(
            for: normalizedServerURL,
            username: secondUsername,
        )
    }
}
