import Foundation

/// Client → server WS frames (frozen contract, plan §3.1; mirrors
/// `src/types.ts:87-92` `ClientMessage`). Immutable value type.
///
/// Server-side validation the caller must respect (the server SILENTLY DISCARDS
/// invalid frames, `src/protocol.ts:45-86` — no error reply comes back):
/// - `attach` must be the FIRST frame on a connection (src/server.ts:707-711).
/// - `resize` cols/rows must be integers in `WireConstants.resizeRange` (1...1000).
/// - `attach.cwd`, when present, must be an absolute path (`Validation.isAbsoluteCwd`).
/// - `input.data` is raw keyboard bytes, passed through verbatim — never filtered.
public enum ClientMessage: Sendable, Equatable {
    /// First frame. `sessionId == nil` spawns a new session (encoded as an
    /// explicit JSON `"sessionId":null` — the key is REQUIRED by the server,
    /// src/protocol.ts:132-134). `cwd` = "new tab here" spawn directory (M6).
    case attach(sessionId: UUID?, cwd: String?)
    /// Raw keyboard bytes, verbatim (invariant #9 — no content filtering).
    case input(data: String)
    /// Own message type so the server can `ioctl(TIOCSWINSZ)` → SIGWINCH.
    case resize(cols: Int, rows: Int)
    /// Resolve a held permission gate with allow. `mode` is only meaningful for
    /// a `plan` gate and is encoded as a TOP-LEVEL `mode` key — the server's WS
    /// wiring re-parses the raw frame for it (src/server.ts:91-102).
    case approve(mode: ApproveMode?)
    /// Resolve a held permission gate with deny.
    case reject
}

/// Permission mode written back when resolving a `plan` gate. Raw values mirror
/// the server whitelist `PERMISSION_MODES` (src/server.ts:76 / src/types.ts:365).
///
/// Note: the plan-gate three-way UI only ever sends `.acceptEdits` / `.default`
/// (mirroring public/tabs.ts:345-347). Raw `.auto` is gated by ALLOW_AUTO_MODE
/// (default false) and is server-downgraded to `default` otherwise
/// (src/server.ts:765-766); it is reserved for a future permission-mode switcher.
public enum ApproveMode: String, Sendable, CaseIterable {
    case `default`
    case acceptEdits
    case plan
    case auto
}
