// ── Backward-compat re-exports (all types moved to domain files) ─────────────
export type * from './session-types.js';
export type * from './project-types.js';
export type * from './coder-types.js';
export type * from './analytics-types.js';
export type * from './memory-types.js';
// ── end backward-compat re-exports ──────────────────────────────────────────

// WorktreeRiskReport single-sourced in @boocode/contracts — edit the package, not here.
export type { WorktreeRiskReport } from '@boocode/contracts/worktree-risk';

// Arena types single-sourced in @boocode/contracts; edit the package, not here.
import type { ArenaState, BattleShape, ContestantShape, CrossExaminationShape, BattleType, BattleStatus, ContestantStatus, ContestantLane } from '@boocode/contracts/arena';
export type { ArenaState, BattleShape, ContestantShape, CrossExaminationShape, BattleType, BattleStatus, ContestantStatus, ContestantLane };

// ── BooControl fleet frames ─────────────────────────────────────────────────

import type {
  ControlFleetFrameType,
  ControlActivityFrameType,
  ControlPerfFrameType,
  ControlLogFrameType,
  ControlJobFrameType,
} from '@boocode/contracts/ws-frames';

export type ControlFleetFrame = ControlFleetFrameType;
export type ControlActivityFrame = ControlActivityFrameType;
export type ControlPerfFrame = ControlPerfFrameType;
export type ControlLogFrame = ControlLogFrameType;
export type ControlJobFrame = ControlJobFrameType;

// ── end BooControl fleet frames ─────────────────────────────────────────────

import type { Message, ToolCall, MessageRole } from './session-types.js';
import type { ErrorReason, MessageMetadata } from '@boocode/contracts/message-metadata';

export type WsFrame =
  | { type: 'snapshot'; messages: Message[] }
  | { type: 'message_started'; message_id: string; chat_id?: string; role: MessageRole; compare_group_id?: string }
  | { type: 'delta'; message_id: string; chat_id?: string; content: string; compare_group_id?: string }
  | { type: 'reasoning_delta'; message_id: string; chat_id?: string; content: string }
  | { type: 'tool_call'; message_id: string; chat_id?: string; tool_call: ToolCall }
  | {
      type: 'tool_result';
      tool_message_id: string;
      chat_id?: string;
      tool_call_id: string;
      output: unknown;
      truncated: boolean;
      error?: string;
      diff?: string;
    }
  | {
      type: 'message_complete';
      message_id: string;
      chat_id?: string;
      tokens_used?: number | null;
      ctx_used?: number | null;
      ctx_max?: number | null;
      cache_tokens?: number | null;
      reasoning_tokens?: number | null;
      started_at?: string | null;
      finished_at?: string | null;
      // model-attribution: the model that produced this assistant message.
      model?: string | null;
      // piggybacks the persisted metadata onto the terminal frame so cap-hit
      // sentinels (and any future stamped-on-complete metadata) flow to the
      // client without a refetch.
      metadata?: MessageMetadata | null;
      // terminal status of the assistant message. Absent on the normal path
      // (reducer defaults to 'complete'); the BooCoder dispatcher stamps it
      // 'cancelled' on a user Stop / stall and 'failed' on a thrown error so
      // the reducer renders a muted "Stopped" / failed state — no new frame type.
      status?: 'complete' | 'cancelled' | 'failed';
      compare_group_id?: string;
    }
  // live throughput frame, published mid-stream every ~500ms with the latest
  // token + ctx counts so ChatThroughput can render tok/s and ctx_used while
  // the model is still generating.
  | {
      type: 'usage';
      message_id: string;
      chat_id?: string;
      completion_tokens: number | null;
      ctx_used: number | null;
      ctx_max: number | null;
    }
  | { type: 'messages_deleted'; message_ids: string[]; chat_id?: string     }
  | { type: 'chat_renamed'; chat_id: string; name: string }
  | {
      type: 'agent_snapshot';
      chat_id: string;
      agent?: string | null;
      model: string;
      mode?: string | null;
      turn_number: number;
    }
  // published by services/compaction.ts after the new anchored summary row
  // lands. Carries the new summary row id for diagnostics; the session-stream
  // handler ignores the id and re-fetches the full message list (the cohort of
  // compacted_at-stamped rows changed too).
  | { type: 'compacted'; session_id: string; chat_id: string; summary_message_id: string }
  // `reason` discriminates structured failures (the UI prefers it over `error`
  // text when present).
  | { type: 'error'; message_id?: string; chat_id?: string; error: string; reason?: ErrorReason; compare_group_id?: string }
  // agent-status-normalize (#10): BooCoder publishes a normalized per-(chat,agent)
  // lifecycle status for external coding agents on the per-session channel. The
  // CoderPane tracks the latest status per (chat_id, agent) and resets on chat
  // switch; AgentComposerBar renders the dot (distinct from the WS-liveness dot).
  | {
      type: 'agent_status_updated';
      chat_id: string;
      agent: string;
      status: 'working' | 'blocked' | 'idle' | 'error';
      reason?: string;
      at: string;
    }
  // orchestrator frames ([D-6]): run lifecycle. The per-agent content stream
  // reuses existing delta/tool_call/message_complete frames keyed by chat_id.
  | {
      type: 'flow_run_started';
      run_id: string;
      flow_name: string;
      band: 'small' | 'medium' | 'large';
      steps: Array<{
        step_id: string;
        agent: string;
        kind: 'agent' | 'code';
        chat_id: string;
        label: string;
      }>;
    }
  | {
      type: 'flow_run_step_updated';
      run_id: string;
      step_id: string;
      status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'cancelled';
      run_status?: 'running' | 'completed' | 'failed' | 'cancelled';
      report?: string;
    }
  // inter-agent message frame
  | {
      type: 'agent_message';
      run_id: string;
      sender_step_id: string;
      content: string;
      channel?: string;
    }
  // tool trace frames: per-tool-call lifecycle tracking
  | {
      type: 'tool_trace_start';
      trace_id: string;
      message_id: string;
      chat_id: string;
      tool_name: string;
      tool_input: Record<string, unknown>;
      started_at: string;
    }
  | {
      type: 'tool_trace_finish';
      trace_id: string;
      message_id: string;
      chat_id: string;
      tool_name: string;
      tool_output?: string | null;
      latency_ms?: number;
      tokens_used?: number | null;
      cache_tokens?: number | null;
      reasoning_tokens?: number | null;
      error?: string;
      outcome?: string;
      finished_at: string;
    }
  | {
      type: 'collision_warning';
      file_path: string;
      worktrees: string[];
      agents: string[];
      severity: 'same_line' | 'adjacent_line' | 'different_area';
    }
  // arena frames: battle lifecycle + per-contestant streaming
  | {
      type: 'battle_started';
      battle_id: string;
      battle_type: 'coding' | 'qa';
      prompt: string;
      contestants: Array<{ id: string; identity: string; model: string; lane: 'local' | 'cloud' }>;
    }
  | {
      type: 'contestant_updated';
      battle_id: string;
      contestant_id: string;
      status?: 'queued' | 'running' | 'done' | 'error';
      duration_ms?: number;
      tokens_per_sec?: number;
      battle_status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
      delta?: string;
      error?: string;
    }
  | {
      type: 'battle_updated';
      battle_id: string;
      status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
      winner_contestant_id?: string | null;
      analysis_ready?: boolean;
      cross_exam_id?: string;
    }
  // streaming v2: channel-delta frames. Each carries a monotonic seq for
  // out-of-order buffering and a channel discriminator; per-channel payloads
  // map to the equivalent legacy frame types after reordering.
  | {
      type: 'channel_delta';
      seq: number;
      channel: 'text' | 'tool_call' | 'tool_result' | 'status' | 'error';
      message_id?: string;
      chat_id?: string;
      content?: string;
      compare_group_id?: string;
      tool_call?: ToolCall;
      tool_message_id?: string;
      tool_call_id?: string;
      output?: unknown;
      truncated?: boolean;
      diff?: string;
      error?: string;
      reason?: string;
      status?: 'running' | 'complete' | 'cancelled' | 'failed';
      tokens_used?: number | null;
      ctx_used?: number | null;
      ctx_max?: number | null;
      cache_tokens?: number | null;
      reasoning_tokens?: number | null;
      started_at?: string | null;
      finished_at?: string | null;
      model?: string | null;
      metadata?: MessageMetadata | null;
    }
  // BooControl fleet frames
  | ControlFleetFrame
  | ControlActivityFrame
  | ControlPerfFrame
  | ControlLogFrame
  | ControlJobFrame;
