// contracts §3 — Error Contracts
// File: error.ts — ErrorKind, ErrorSeverity, Retryability, AirError

import type { UUID, JsonObject } from "./ids.js"
import type { EntityRef } from "./event.js"

export type ErrorKind =
  | "user_error"
  | "project_error"
  | "env_error"
  | "dependency_error"
  | "permission_error"
  | "tool_error"
  | "command_error"
  | "build_error"
  | "test_error"
  | "static_analysis_error"
  | "debug_error"
  | "provider_error"
  | "model_capability_error"
  | "context_error"
  | "agent_error"
  | "scheduler_error"
  | "workspace_error"
  | "merge_error"
  | "architecture_error"
  | "policy_error"
  | "system_error"
  | "unknown_error"

export type ErrorSeverity = "info" | "warning" | "error" | "fatal"

export type Retryability = "retryable" | "retryable_after_change" | "not_retryable" | "unknown"

export interface AirError {
  error_id: UUID
  kind: ErrorKind
  severity: ErrorSeverity
  message: string
  detail?: string
  retryability: Retryability
  semantic_signature: string
  cause_ref?: EntityRef
  cause_refs?: EntityRef[]
  user_action?: string
  metadata?: JsonObject
}

/**
 * Pure type-guard for AirError. Dependency-free: only checks structural shape.
 * Returns true when the value looks like an AirError (has all required fields
 * with the expected types).
 */
export function is_air_error(value: unknown): value is AirError {
  if (typeof value !== "object" || value === null) return false
  const obj = value as Record<string, unknown>
  return (
    typeof obj["error_id"] === "string" &&
    typeof obj["kind"] === "string" &&
    typeof obj["severity"] === "string" &&
    typeof obj["message"] === "string" &&
    typeof obj["retryability"] === "string" &&
    typeof obj["semantic_signature"] === "string"
  )
}