// Types for the WebSocket bridge between Claude Code CLI and the browser

// ─── Queue Types ──────────────────────────────────────────────────────────────

export interface QueuedMessage {
  id: string;
  content: string;
  images?: { media_type: string; data: string }[];
  queuedAt: number;
}

// ─── Initialize Response Types ───────────────────────────────────────────────

export interface InitializeModel {
  value: string;
  displayName: string;
  description: string;
}

export interface InitializeAccount {
  email?: string;
  organization?: string;
  subscriptionType?: string;
  apiKeySource?: string;
}

export interface InitializeCommand {
  name: string;
  description: string;
  argumentHint?: string;
}

export interface InitializeResponseData {
  commands: InitializeCommand[];
  output_style: string;
  available_output_styles: string[];
  models: InitializeModel[];
  account: InitializeAccount;
  fast_mode?: boolean;
}

// ─── CLI Message Types (NDJSON from Claude Code CLI) ──────────────────────────

export interface CLISystemInitMessage {
  type: "system";
  subtype: "init";
  cwd: string;
  session_id: string;
  tools: string[];
  mcp_servers: { name: string; status: string }[];
  model: string;
  permissionMode: string;
  apiKeySource: string;
  claude_code_version: string;
  slash_commands: string[];
  agents?: string[];
  skills?: string[];
  output_style: string;
  uuid: string;
}

export interface CLISystemStatusMessage {
  type: "system";
  subtype: "status";
  status: "compacting" | null;
  permissionMode?: string;
  uuid: string;
  session_id: string;
}

export interface CLICompactBoundaryMessage {
  type: "system";
  subtype: "compact_boundary";
  compact_metadata: {
    trigger: "manual" | "auto";
    pre_tokens: number;
  };
  uuid: string;
  session_id: string;
}

export interface CLITaskNotificationMessage {
  type: "system";
  subtype: "task_notification";
  task_id: string;
  status: "completed" | "failed" | "stopped";
  output_file: string;
  summary: string;
  uuid: string;
  session_id: string;
}

// ─── Background Task Types ──────────────────────────────────────────────────

export interface Teammate {
  id: string;
  name: string;
  status: "idle" | "running" | "completed" | "failed";
  task?: string;
  taskDescription?: string;
  teamName?: string;
  agentType?: string;
  startedAt: number;
  completedAt?: number;
}

export interface BackgroundTask {
  task_id: string;
  status: "running" | "completed" | "failed" | "stopped";
  summary?: string;
  output_file?: string;
  started_at: number;
  completed_at?: number;
}

export interface CLIFilesPersistedMessage {
  type: "system";
  subtype: "files_persisted";
  files: { filename: string; file_id: string }[];
  failed: { filename: string; error: string }[];
  processed_at: string;
  uuid: string;
  session_id: string;
}

export interface CLIHookStartedMessage {
  type: "system";
  subtype: "hook_started";
  hook_id: string;
  hook_name: string;
  hook_event: string;
  uuid: string;
  session_id: string;
}

export interface CLIHookProgressMessage {
  type: "system";
  subtype: "hook_progress";
  hook_id: string;
  hook_name: string;
  hook_event: string;
  stdout: string;
  stderr: string;
  output: string;
  uuid: string;
  session_id: string;
}

export interface CLIHookResponseMessage {
  type: "system";
  subtype: "hook_response";
  hook_id: string;
  hook_name: string;
  hook_event: string;
  output: string;
  stdout: string;
  stderr: string;
  exit_code?: number;
  outcome: "success" | "error" | "cancelled";
  uuid: string;
  session_id: string;
}

export interface CLISystemRateLimitMessage {
  type: "system";
  subtype: "rate_limit";
  utilization_percent: number;
  reset_at: number;
  window_duration_mins: number;
  uuid: string;
  session_id: string;
}

export type CLISystemMessage =
  | CLISystemInitMessage
  | CLISystemStatusMessage
  | CLICompactBoundaryMessage
  | CLITaskNotificationMessage
  | CLIFilesPersistedMessage
  | CLIHookStartedMessage
  | CLIHookProgressMessage
  | CLIHookResponseMessage
  | CLISystemRateLimitMessage;

export interface CLIAssistantMessage {
  type: "assistant";
  message: {
    id: string;
    type: "message";
    role: "assistant";
    model: string;
    content: ContentBlock[];
    stop_reason: string | null;
    usage: {
      input_tokens: number;
      output_tokens: number;
      cache_creation_input_tokens: number;
      cache_read_input_tokens: number;
    };
  };
  parent_tool_use_id: string | null;
  error?: string;
  uuid: string;
  session_id: string;
}

export interface CLIResultMessage {
  type: "result";
  subtype: "success" | "error_during_execution" | "error_max_turns" | "error_max_budget_usd" | "error_max_structured_output_retries";
  is_error: boolean;
  result?: string;
  errors?: string[];
  duration_ms: number;
  duration_api_ms: number;
  num_turns: number;
  total_cost_usd: number;
  stop_reason: string | null;
  usage: {
    input_tokens: number;
    output_tokens: number;
    cache_creation_input_tokens: number;
    cache_read_input_tokens: number;
  };
  modelUsage?: Record<string, {
    inputTokens: number;
    outputTokens: number;
    cacheReadInputTokens: number;
    cacheCreationInputTokens: number;
    contextWindow: number;
    maxOutputTokens: number;
    costUSD: number;
  }>;
  total_lines_added?: number;
  total_lines_removed?: number;
  uuid: string;
  session_id: string;
}

export interface CLIStreamEventMessage {
  type: "stream_event";
  event: unknown;
  parent_tool_use_id: string | null;
  uuid: string;
  session_id: string;
}

export interface CLIToolProgressMessage {
  type: "tool_progress";
  tool_use_id: string;
  tool_name: string;
  parent_tool_use_id: string | null;
  elapsed_time_seconds: number;
  uuid: string;
  session_id: string;
}

export interface CLIToolUseSummaryMessage {
  type: "tool_use_summary";
  summary: string;
  preceding_tool_use_ids: string[];
  uuid: string;
  session_id: string;
}

// ─── Hook Callback Types ─────────────────────────────────────────────────────

/** Input payload delivered with a hook_callback control_request from the CLI. */
export interface HookCallbackInput {
  hook_event_name: string;
  session_id?: string;
  transcript_path?: string;
  cwd?: string;
  permission_mode?: string;
  tool_name?: string;
  tool_input?: Record<string, unknown>;
  tool_result?: unknown;
  [key: string]: unknown;
}

/** Hook-event-specific output included in the sync response. */
export interface HookSpecificOutput {
  hookEventName: "PreToolUse" | "PostToolUse" | "PermissionRequest";
  permissionDecision?: "allow" | "deny" | "ask";
  permissionDecisionReason?: string;
  updatedInput?: Record<string, unknown>;
  additionalContext?: string;
  decision?: { behavior: "allow" | "deny"; [key: string]: unknown };
}

/** Sync response data for a hook_callback control_request. */
export interface HookCallbackResponseData {
  continue?: boolean;
  suppressOutput?: boolean;
  stopReason?: string;
  decision?: "approve" | "block";
  reason?: string;
  systemMessage?: string;
  hookSpecificOutput?: HookSpecificOutput;
}

export interface CLIControlRequestMessage {
  type: "control_request";
  request_id: string;
  request:
    | {
        subtype: "can_use_tool";
        tool_name: string;
        input: Record<string, unknown>;
        permission_suggestions?: PermissionUpdate[];
        description?: string;
        tool_use_id: string;
        agent_id?: string;
      }
    | {
        subtype: "hook_callback";
        callback_id: string;
        input: HookCallbackInput;
        tool_use_id?: string;
      }
    | {
        subtype: "mcp_message";
        server_name: string;
        message: Record<string, unknown>;
      };
}

export interface CLIKeepAliveMessage {
  type: "keep_alive";
}

export interface CLIAuthStatusMessage {
  type: "auth_status";
  isAuthenticating: boolean;
  output: string[];
  error?: string;
  uuid: string;
  session_id: string;
}

export interface CLIControlCancelRequestMessage {
  type: "control_cancel_request";
  request_id: string;
}

export interface CLIControlResponseMessage {
  type: "control_response";
  response: {
    subtype: "success" | "error";
    request_id: string;
    response?: Record<string, unknown>;
    error?: string;
  };
}

export type CLIMessage =
  | CLISystemMessage
  | CLIAssistantMessage
  | CLIResultMessage
  | CLIStreamEventMessage
  | CLIToolProgressMessage
  | CLIToolUseSummaryMessage
  | CLIControlRequestMessage
  | CLIControlCancelRequestMessage
  | CLIControlResponseMessage
  | CLIKeepAliveMessage
  | CLIAuthStatusMessage;

// ─── Content Block Types ──────────────────────────────────────────────────────

export type ContentBlock =
  | { type: "text"; text: string }
  | { type: "tool_use"; id: string; name: string; input: Record<string, unknown> }
  | { type: "tool_result"; tool_use_id: string; content: string | ContentBlock[]; is_error?: boolean }
  | { type: "thinking"; thinking: string; budget_tokens?: number };

// ─── Browser Message Types (browser <-> bridge) ──────────────────────────────

/** Messages the browser sends to the bridge */
export type BrowserOutgoingMessage =
  | { type: "user_message"; content: string; session_id?: string; images?: { media_type: string; data: string }[]; client_msg_id?: string }
  | { type: "permission_response"; request_id: string; behavior: "allow" | "deny"; updated_input?: Record<string, unknown>; updated_permissions?: PermissionUpdate[]; message?: string; client_msg_id?: string }
  | { type: "session_subscribe"; last_seq: number }
  | { type: "session_ack"; last_seq: number }
  | { type: "interrupt"; client_msg_id?: string }
  | { type: "set_model"; model: string; client_msg_id?: string }
  | { type: "set_permission_mode"; mode: string; client_msg_id?: string }
  | { type: "mcp_get_status"; client_msg_id?: string }
  | { type: "mcp_toggle"; serverName: string; enabled: boolean; client_msg_id?: string }
  | { type: "mcp_reconnect"; serverName: string; client_msg_id?: string }
  | { type: "mcp_set_servers"; servers: Record<string, McpServerConfig>; client_msg_id?: string }
  | { type: "set_max_thinking_tokens"; maxThinkingTokens: number | null; client_msg_id?: string }
  | { type: "set_output_style"; outputStyle: string; client_msg_id?: string }
  | { type: "set_fast_mode"; fastMode: boolean; client_msg_id?: string }
  | { type: "queue_add"; content: string; images?: { media_type: string; data: string }[]; client_msg_id?: string }
  | { type: "queue_remove"; messageId: string; client_msg_id?: string }
  | { type: "queue_clear"; client_msg_id?: string }
  | { type: "queue_resume"; client_msg_id?: string }
  | { type: "queue_reorder"; orderedIds: string[]; client_msg_id?: string }
  | { type: "queue_edit"; messageId: string; content: string; images?: { media_type: string; data: string }[]; client_msg_id?: string }
  | { type: "rewind_files"; userMessageId: string; dryRun?: boolean; client_msg_id?: string }
  | { type: "mcp_message"; serverName: string; message: Record<string, unknown>; client_msg_id?: string }
  | { type: "permission_cancel"; request_id: string; client_msg_id?: string }
  | { type: "update_env"; variables: Record<string, string>; client_msg_id?: string }
  | { type: "stop_task"; task_id: string; client_msg_id?: string };

/** Messages the bridge sends to the browser */
export type BrowserIncomingMessageBase =
  | { type: "session_init"; session: SessionState }
  | { type: "session_update"; session: Partial<SessionState> }
  | { type: "assistant"; message: CLIAssistantMessage["message"]; parent_tool_use_id: string | null; timestamp?: number }
  | { type: "stream_event"; event: unknown; parent_tool_use_id: string | null }
  | {
    type: "system_event";
    event:
      | Pick<CLICompactBoundaryMessage, "subtype" | "compact_metadata" | "uuid" | "session_id">
      | Pick<CLITaskNotificationMessage, "subtype" | "task_id" | "status" | "output_file" | "summary" | "uuid" | "session_id">
      | Pick<CLIFilesPersistedMessage, "subtype" | "files" | "failed" | "processed_at" | "uuid" | "session_id">
      | Pick<CLIHookStartedMessage, "subtype" | "hook_id" | "hook_name" | "hook_event" | "uuid" | "session_id">
      | Pick<CLIHookProgressMessage, "subtype" | "hook_id" | "hook_name" | "hook_event" | "stdout" | "stderr" | "output" | "uuid" | "session_id">
      | Pick<CLIHookResponseMessage, "subtype" | "hook_id" | "hook_name" | "hook_event" | "output" | "stdout" | "stderr" | "exit_code" | "outcome" | "uuid" | "session_id">;
    timestamp?: number;
  }
  | { type: "result"; data: CLIResultMessage }
  | { type: "permission_request"; request: PermissionRequest }
  | { type: "permission_cancelled"; request_id: string }
  | { type: "tool_progress"; tool_use_id: string; tool_name: string; elapsed_time_seconds: number }
  | { type: "tool_use_summary"; summary: string; tool_use_ids: string[] }
  | { type: "status_change"; status: "compacting" | "idle" | "running" | null }
  | { type: "auth_status"; isAuthenticating: boolean; output: string[]; error?: string }
  | { type: "error"; message: string }
  | { type: "cli_disconnected" }
  | { type: "cli_connected" }
  | { type: "user_message"; content: string; timestamp: number; id?: string }
  | { type: "message_history"; messages: BrowserIncomingMessage[] }
  | { type: "event_replay"; events: BufferedBrowserEvent[] }
  | { type: "session_name_update"; name: string }
  | { type: "pr_status_update"; pr: import("./github-pr.js").GitHubPRInfo | null; available: boolean }
  | { type: "mcp_status"; servers: McpServerDetail[] }
  | { type: "queue_update"; sessionId: string; queue: QueuedMessage[]; paused: boolean }
  | { type: "rewind_result"; result: { canRewind: boolean; error?: string; filesChanged?: string[]; insertions?: number; deletions?: number } }
  | { type: "session_initialized"; data: InitializeResponseData }
  | { type: "hook_callback"; callback_id: string; input: HookCallbackInput; tool_use_id?: string; timestamp: number }
  | { type: "mcp_message"; server_name: string; message: Record<string, unknown> }
  | { type: "background_tasks_update"; tasks: BackgroundTask[] }
  | { type: "teammates_update"; teammates: Teammate[] }
  | { type: "file_conflict"; sessionId: string; conflictingSessionId: string; conflictingSessionName: string; files: string[] };

export type BrowserIncomingMessage = BrowserIncomingMessageBase & { seq?: number };

export type ReplayableBrowserIncomingMessage = Exclude<BrowserIncomingMessageBase, { type: "event_replay" }>;

export interface BufferedBrowserEvent {
  seq: number;
  message: ReplayableBrowserIncomingMessage;
}

// ─── Session State ────────────────────────────────────────────────────────────

export type BackendType = "claude" | "codex";

export interface SessionState {
  session_id: string;
  backend_type?: BackendType;
  model: string;
  cwd: string;
  tools: string[];
  permissionMode: string;
  claude_code_version: string;
  mcp_servers: { name: string; status: string }[];
  agents: string[];
  slash_commands: string[];
  skills: string[];
  total_cost_usd: number;
  num_turns: number;
  context_used_percent: number;
  input_tokens: number;
  output_tokens: number;
  cache_read_tokens: number;
  cache_creation_tokens: number;
  context_window: number;
  is_compacting: boolean;
  git_branch: string;
  is_worktree: boolean;
  is_containerized: boolean;
  repo_root: string;
  git_ahead: number;
  git_behind: number;
  total_lines_added: number;
  total_lines_removed: number;
  /** Optional USD budget cap set at session creation. */
  budget_usd?: number;
  /** Whether the 80% budget warning has already been sent. */
  budget_warning_sent?: boolean;
  // Initialize data (from initialize control_request response)
  available_models?: InitializeModel[];
  account?: InitializeAccount;
  available_commands?: InitializeCommand[];
  available_output_styles?: string[];
  output_style?: string;
  fast_mode?: boolean;
  // Codex-specific token details (forwarded from thread/tokenUsage/updated)
  codex_token_details?: {
    inputTokens: number;
    outputTokens: number;
    cachedInputTokens: number;
    reasoningOutputTokens: number;
    modelContextWindow: number;
  };
  // Codex-specific rate limits (forwarded from account/rateLimits/updated)
  codex_rate_limits?: {
    primary: { usedPercent: number; windowDurationMins: number; resetsAt: number } | null;
    secondary: { usedPercent: number; windowDurationMins: number; resetsAt: number } | null;
  };
  // SDK rate limits (from CLI system rate_limit events)
  sdk_rate_limits?: {
    utilization_percent: number;
    reset_at: number;
    window_duration_mins: number;
  } | null;
  /** If this session was spawned by a cron job */
  cronJobId?: string;
  /** Human-readable name of the cron job that spawned this session */
  cronJobName?: string;
  /** If this session was spawned by an agent */
  agentId?: string;
  /** Human-readable name of the agent that spawned this session */
  agentName?: string;
  /** Background tasks tracked from task_notification events */
  background_tasks?: BackgroundTask[];
  /** Teammates tracked from agent team hook events */
  teammates?: Teammate[];
}

// ─── MCP Types ───────────────────────────────────────────────────────────────

export interface McpServerConfig {
  type: "stdio" | "sse" | "http" | "sdk";
  command?: string;
  args?: string[];
  env?: Record<string, string>;
  url?: string;
}

export interface McpServerDetail {
  name: string;
  status: "connected" | "failed" | "disabled" | "connecting";
  serverInfo?: unknown;
  error?: string;
  config: { type: string; url?: string; command?: string; args?: string[] };
  scope: string;
  tools?: { name: string; annotations?: { readOnly?: boolean; destructive?: boolean; openWorld?: boolean } }[];
}

// ─── Permission Request ──────────────────────────────────────────────────────

// ─── Permission Rule Types ───────────────────────────────────────────────────

export type PermissionDestination = "userSettings" | "projectSettings" | "localSettings" | "session" | "cliArg";

export type PermissionUpdate =
  | { type: "addRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
  | { type: "replaceRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
  | { type: "removeRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
  | { type: "setMode"; mode: string; destination: PermissionDestination }
  | { type: "addDirectories"; directories: string[]; destination: PermissionDestination }
  | { type: "removeDirectories"; directories: string[]; destination: PermissionDestination };

export interface PermissionRequest {
  request_id: string;
  tool_name: string;
  input: Record<string, unknown>;
  permission_suggestions?: PermissionUpdate[];
  description?: string;
  tool_use_id: string;
  agent_id?: string;
  timestamp: number;
}

// ─── Session Creation Progress (SSE streaming) ──────────────────────────────

export type CreationStepId =
  | "resolving_env"
  | "fetching_git"
  | "checkout_branch"
  | "pulling_git"
  | "creating_worktree"
  | "pulling_image"
  | "building_image"
  | "creating_container"
  | "copying_workspace"
  | "running_init_script"
  | "launching_cli";

export interface CreationProgressEvent {
  step: CreationStepId;
  label: string;
  status: "in_progress" | "done" | "error";
  detail?: string;
}

// ─── SDK Session Info (launcher-managed session state) ──────────────────────

export interface SdkSessionInfo {
  sessionId: string;
  pid?: number;
  state: "starting" | "connected" | "running" | "exited";
  exitCode?: number | null;
  model?: string;
  permissionMode?: string;
  cwd: string;
  createdAt: number;
  /** The CLI's internal session ID (from system.init), used for --resume */
  cliSessionId?: string;
  archived?: boolean;
  /** User-facing session name */
  name?: string;
  /** Which backend this session uses */
  backendType?: BackendType;
  /** Git branch from bridge state (enriched by REST API) */
  gitBranch?: string;
  /** Git ahead count (enriched by REST API) */
  gitAhead?: number;
  /** Git behind count (enriched by REST API) */
  gitBehind?: number;
  /** Total lines added (enriched by REST API) */
  totalLinesAdded?: number;
  /** Total lines removed (enriched by REST API) */
  totalLinesRemoved?: number;
  /** Whether internet/web search is enabled for Codex sessions */
  codexInternetAccess?: boolean;
  /** Sandbox mode selected for Codex sessions */
  codexSandbox?: "workspace-write" | "danger-full-access";
  /** If this session was spawned by a cron job */
  cronJobId?: string;
  /** Human-readable name of the cron job that spawned this session */
  cronJobName?: string;
  /** If this session was spawned by an agent */
  agentId?: string;
  /** Human-readable name of the agent that spawned this session */
  agentName?: string;
  /** If session was created from an existing Claude thread/session. */
  resumeSessionAt?: string;
  /** Whether the resumed session used --fork-session. */
  forkSession?: boolean;

  /** System prompt if explicitly set in launch options */
  systemPrompt?: string;
  /** Append system prompt if explicitly set in launch options */
  appendSystemPrompt?: string;

  // Container fields
  /** Docker container ID when session runs inside a container */
  containerId?: string;
  /** Docker container name */
  containerName?: string;
  /** Docker image used for the container */
  containerImage?: string;
  /** Runtime cwd inside container for agent RPC calls (e.g. "/workspace"). */
  containerCwd?: string;
}

export interface LaunchOptions {
  model?: string;
  permissionMode?: string;
  cwd?: string;
  claudeBinary?: string;
  codexBinary?: string;
  allowedTools?: string[];
  env?: Record<string, string>;
  backendType?: BackendType;
  /** Codex sandbox mode. */
  codexSandbox?: "workspace-write" | "danger-full-access";
  /** Whether Codex internet/web search should be enabled for this session. */
  codexInternetAccess?: boolean;
  /** Optional override for CODEX_HOME used by Codex sessions. */
  codexHome?: string;
  /** Docker container ID — when set, CLI runs inside container via docker exec */
  containerId?: string;
  /** Docker container name */
  containerName?: string;
  /** Docker image used for the container */
  containerImage?: string;
  /** Runtime cwd inside the container (typically "/workspace"). */
  containerCwd?: string;
  /** Start from a specific prior Claude session/thread point. */
  resumeSessionAt?: string;
  /** Fork a new Claude session when resuming from prior context. */
  forkSession?: boolean;
  /** Enable file checkpointing (required for file rewind). */
  enableFileCheckpointing?: boolean;
  /** Maximum conversation turns before auto-stop. */
  maxTurns?: number;
  /** Maximum spend in USD before auto-stop. */
  maxBudgetUsd?: number;
  /** Override the default system prompt. */
  systemPrompt?: string;
  /** Append text to the default system prompt. */
  appendSystemPrompt?: string;
  /** Thinking mode configuration. */
  thinking?: { type: "adaptive" } | { type: "enabled"; budgetTokens: number } | { type: "disabled" };
  /** Effort level for responses. */
  effort?: "low" | "medium" | "high" | "max";
  /** Tools to explicitly disallow. */
  disallowedTools?: string[];
  /** Additional directories to include in context. */
  additionalDirectories?: string[];
  /** Beta features to enable (e.g., "interleaved-thinking"). */
  betas?: string[];
  /** Language/locale setting for the CLI. */
  language?: string;
}
