namespace DodoSSH.Contracts;

/// <summary>
/// A request for permission to relay to a host.
/// </summary>
/// <remarks>
/// There is deliberately no address field. The server resolves the target from
/// <see cref="HostId"/>, which must belong to a vault the caller holds Connect on and must have
/// relay enabled. Accepting a client-supplied address would turn the relay into an
/// authenticated open TCP proxy into the operator's network; see ADR 0004.
/// </remarks>
/// <param name="HostId">The host to reach.</param>
/// <param name="PortForwardId">
/// A configured port forward to use instead of the host's own SSH port. Resolved server-side the
/// same way.
/// </param>
public sealed record RelayTicketRequest(
    Guid HostId,
    Guid? PortForwardId);

/// <summary>
/// A short-lived, single-use ticket authorising exactly one relay connection.
/// </summary>
/// <remarks>
/// The ticket grants no API access at all, which is why the WebSocket endpoint can accept it
/// alone. It is also the extraction seam: a standalone relay process needs only the data
/// protection key ring and the replay-guard table, no authorization code.
/// </remarks>
/// <param name="Ticket">
/// Opaque token. Sent as the <c>ticket.&lt;token&gt;</c> element of the
/// <c>Sec-WebSocket-Protocol</c> header, because constrained WebSocket clients cannot set
/// arbitrary headers.
/// </param>
/// <param name="WebSocketUrl">Absolute URL of the relay endpoint.</param>
/// <param name="SubProtocol">Required WebSocket subprotocol.</param>
/// <param name="SessionId">Correlates the ticket with the resulting session record.</param>
/// <param name="ExpiresAt">Expiry, at most 30 seconds out.</param>
public sealed record RelayTicketResponse(
    string Ticket,
    Uri WebSocketUrl,
    string SubProtocol,
    Guid SessionId,
    DateTimeOffset ExpiresAt);

/// <summary>Why a relay session ended.</summary>
public enum RelaySessionCloseReason
{
    /// <summary>Not a legal value.</summary>
    Unspecified = 0,

    /// <summary>The client closed the connection.</summary>
    ClientClosed = 1,

    /// <summary>The target closed the connection.</summary>
    TargetClosed = 2,

    /// <summary>No traffic within the idle timeout.</summary>
    IdleTimeout = 3,

    /// <summary>The maximum session duration was reached.</summary>
    DurationLimit = 4,

    /// <summary>The server is shutting down and drained the session.</summary>
    ServerShutdown = 5,

    /// <summary>The connection to the target failed.</summary>
    TargetUnreachable = 6,

    /// <summary>An error ended the session.</summary>
    Error = 7,
}

/// <summary>
/// An audit record of one relay session.
/// </summary>
/// <remarks>
/// Byte counts and duration are recorded; content never is. The relay forwards SSH ciphertext,
/// so session recording is impossible in this mode by construction — the compliance strength
/// and the limitation are the same fact.
/// </remarks>
/// <param name="SessionId">The session.</param>
/// <param name="HostId">Host that was reached.</param>
/// <param name="TargetHost">Resolved target hostname.</param>
/// <param name="TargetPort">Resolved target port.</param>
/// <param name="StartedAt">When the session opened.</param>
/// <param name="EndedAt">When it closed, or null while still open.</param>
/// <param name="BytesClientToTarget">Bytes forwarded from client to target.</param>
/// <param name="BytesTargetToClient">Bytes forwarded from target to client.</param>
/// <param name="CloseReason">Why it ended.</param>
public sealed record RelaySessionSummary(
    Guid SessionId,
    Guid HostId,
    string TargetHost,
    int TargetPort,
    DateTimeOffset StartedAt,
    DateTimeOffset? EndedAt,
    long BytesClientToTarget,
    long BytesTargetToClient,
    RelaySessionCloseReason CloseReason);
