import Foundation

/// Represents the connection lifecycle of the remote client.
/// Transitions are validated by `canTransition(to:)` to enforce a strict state machine.
nonisolated enum ConnectionState: Equatable, Sendable {
    case disconnected
    case discovering
    case foundHost(String)
    case downloadingDB
    case connectingCommandChannel
    case connected(String)
    case connectionLost(String)

    /// Human-readable status message for display in the UI.
    var userMessage: String? {
        switch self {
        case .disconnected:
            nil
        case .discovering:
            "Searching for hosts..."
        case .foundHost(let host):
            "Found \(host)"
        case .downloadingDB:
            "Downloading library..."
        case .connectingCommandChannel:
            "Connecting..."
        case .connected(let host):
            "Connected to \(host)"
        case .connectionLost(let reason):
            "Connection lost — \(reason)"
        }
    }

    /// Whether the client is fully connected.
    var isConnected: Bool {
        if case .connected = self { return true }
        return false
    }

    /// Validates whether transitioning from the current state to `next` is allowed.
    ///
    /// Valid forward transitions follow the connection lifecycle:
    /// disconnected → discovering → foundHost → downloadingDB → connectingCommandChannel → connected → connectionLost → discovering
    ///
    /// Any state may transition to `.disconnected` (the user can always disconnect).
    func canTransition(to next: ConnectionState) -> Bool {
        // Any state can go to disconnected
        if case .disconnected = next { return true }

        switch self {
        case .disconnected:
            if case .discovering = next { return true }
        case .discovering:
            if case .foundHost = next { return true }
        case .foundHost:
            if case .downloadingDB = next { return true }
        case .downloadingDB:
            if case .connectingCommandChannel = next { return true }
        case .connectingCommandChannel:
            if case .connected = next { return true }
        case .connected:
            if case .connectionLost = next { return true }
        case .connectionLost:
            if case .discovering = next { return true }
        }

        return false
    }
}
