package wang.yaojia.webterm.api.routes

/**
 * Typed failures for [ApiClient] calls (explicit error handling, plan §4). Transport-level errors
 * thrown by `HttpTransport.send` propagate UNWRAPPED (the pairing classifier reads their shape).
 *
 * [userMessage] is UI-ready copy (matches the iOS `APIClientError.message` 话术). The no-arg cases
 * are singletons (`object`) so tests can assert by identity/equality; [UnexpectedStatus] carries the
 * offending code.
 */
public sealed class ApiClientError(public val userMessage: String) : Exception(userMessage) {
    /** The request could not be built from the endpoint (malformed base URL — should not happen for
     *  a validated `HostEndpoint`; surfaced instead of crashing). */
    public data object InvalidRequest : ApiClientError("无法构造请求（主机地址异常）。")

    /** A 2xx arrived but the body is not the endpoint's shape. For `/live-sessions` this is the
     *  pairing probe's "the port speaks HTTP but is not web-terminal" signal. */
    public data object InvalidResponseBody : ApiClientError("服务器响应不是预期格式——端口对吗？")

    /** 404 on a `/live-sessions/:id/…` sub-route — the session is gone (exited / reaped / killed). */
    public data object SessionNotFound : ApiClientError("会话已不存在（可能已退出或被清理）。")

    /** 403 from a G route's Origin guard (CSWSH defence). */
    public data object Forbidden : ApiClientError("服务器拒绝了此来源（Origin 校验未通过）。")

    /** 403 from `POST /hook/decision`: the capability token is missing / mismatched / STALE —
     *  tokens are single-use and expiring by design. */
    public data object DecisionRejected : ApiClientError("审批令牌已过期或已被处理——请回到终端里直接批准/拒绝。")

    /** 429: the endpoint is rate-limited per IP by fixed server policy. */
    public data object RateLimited : ApiClientError("操作过于频繁，服务器已限流，请稍后再试。")

    /** The FCM registration token failed the client-side charset/length check, or the server echoed
     *  a 400. */
    public data object InvalidFcmToken : ApiClientError("推送注册令牌格式异常，请重启 App 重新注册推送。")

    /** 400 from `GET /projects/detail` — the `path` query parameter is missing/empty. Also raised
     *  client-side for an empty path, before any network I/O. */
    public data object ProjectPathInvalid : ApiClientError("项目路径为空或不合法。")

    /** 404 from `GET /projects/detail` — no project at that path (moved/deleted/not a directory). */
    public data object ProjectNotFound : ApiClientError("项目不存在（路径可能已移动或删除）。")

    /** 500 from `GET /projects/detail` — the server failed reading the repo. */
    public data object ProjectDetailUnavailable : ApiClientError("读取项目详情失败，请稍后再试。")

    /** 500 from `GET /projects/log` — the server failed reading the git log. */
    public data object GitLogUnavailable : ApiClientError("读取提交记录失败，请稍后再试。")

    /** Any other non-success status code. */
    public data class UnexpectedStatus(val status: Int) : ApiClientError("服务器返回了意外状态码 $status。")
}
