import Testing
@testable import VNCCore
import Foundation
import CoreGraphics

@Suite struct SessionStateTests {
    @Test func idleEqualsIdle() {
        #expect(SessionState.idle == .idle)
    }

    @Test func connectedWithDifferentSizesDiffer() {
        let a = SessionState.connected(framebufferSize: FramebufferSize(width: 1920, height: 1080))
        let b = SessionState.connected(framebufferSize: FramebufferSize(width: 1280, height: 800))
        #expect(a != b)
    }

    @Test func disconnectReasonsDiffer() {
        #expect(DisconnectReason.userRequested != .authenticationFailed)
    }
}

@Suite struct ReconnectPolicyTests {
    @Test func userRequestedNeverReconnects() {
        let policy = ReconnectPolicy.default
        #expect(!policy.shouldReconnect(for: .userRequested))
        #expect(!policy.shouldReconnect(for: .authenticationFailed))
    }

    @Test func networkFailuresReconnect() {
        let policy = ReconnectPolicy.default
        #expect(policy.shouldReconnect(for: .networkError("oops")))
        #expect(policy.shouldReconnect(for: .remoteClosed))
    }

    @Test func policyDelaysGrowAndCap() {
        let policy = ReconnectPolicy(maxAttempts: 5,
                                     baseDelaySeconds: 1,
                                     maxDelaySeconds: 8,
                                     jitterFraction: 0)
        #expect(policy.delay(for: 1) == 1)
        #expect(policy.delay(for: 2) == 2)
        #expect(policy.delay(for: 3) == 4)
        #expect(policy.delay(for: 4) == 8)
        #expect(policy.delay(for: 5) == 8)
        #expect(policy.delay(for: 6) == nil)
    }

    @Test func zeroAttemptsDisablesReconnect() {
        let policy = ReconnectPolicy.none
        #expect(!policy.shouldReconnect(for: .networkError("x")))
    }
}

@Suite struct RemoteScreenTests {
    @Test func screensAreHashable() {
        let a = RemoteScreen(id: 1, frame: CGRect(x: 0, y: 0, width: 1920, height: 1080))
        let b = RemoteScreen(id: 1, frame: CGRect(x: 0, y: 0, width: 1920, height: 1080))
        let c = RemoteScreen(id: 2, frame: CGRect(x: 0, y: 0, width: 1920, height: 1080))
        #expect(a == b)
        #expect(a != c)
        #expect(Set([a, b, c]).count == 2)
    }
}

@Suite struct PasswordProviderTests {
    private final class StubKeychain: KeychainServicing, @unchecked Sendable {
        var stored: [String: String] = [:]
        func storePassword(_ password: String, account: String) throws {
            stored[account] = password
        }
        func loadPassword(account: String) throws -> String? {
            stored[account]
        }
        func deletePassword(account: String) throws {
            stored[account] = nil
        }
    }

    @Test func keychainBackedProviderReturnsStored() {
        let keychain = StubKeychain()
        try? keychain.storePassword("hunter2", account: "abc")
        let provider = DefaultPasswordProvider(keychain: keychain)
        #expect(provider.password(for: "abc") == "hunter2")
        #expect(provider.password(for: "missing") == nil)
    }

    @Test func staticProviderAlwaysReturnsSame() {
        let provider = StaticPasswordProvider(password: "fixed")
        #expect(provider.password(for: "anything") == "fixed")
    }
}
