import type { ProjectInfo, SessionLiveInfo, SubagentStatus, ToolLabel } from '@hermes/shared/gateway-events'

import type { SharedControl } from './canonicalGateway.js'

export interface ActiveTool {
  context?: string
  id: string
  labels?: ToolLabel[]
  name: string
  verboseArgs?: string
  startedAt?: number
}

export interface TodoItem {
  content: string
  id: string
  /** Optional id of another item — renders this as a nested subtask. */
  parent?: string
  status: 'cancelled' | 'completed' | 'in_progress' | 'pending'
}

export interface ActivityItem {
  id: number
  text: string
  tone: 'error' | 'info' | 'warn'
}

export interface SubagentProgress {
  apiCalls?: number
  costUsd?: number
  /** Batch (delegation) id — tags `[n/N]` rows so concurrent/nested fan-outs
   *  are distinguishable. Absent on older gateways. */
  delegationId?: string
  depth: number
  durationSeconds?: number
  filesRead?: string[]
  filesWritten?: string[]
  goal: string
  id: string
  index: number
  inputTokens?: number
  iteration?: number
  model?: string
  notes: string[]
  outputTail?: SubagentOutputEntry[]
  outputTokens?: number
  parentId: null | string
  reasoningTokens?: number
  startedAt?: number
  status: SubagentStatus
  summary?: string
  taskCount: number
  thinking: string[]
  toolCount: number
  tools: string[]
  toolsets?: string[]
}

export interface SubagentOutputEntry {
  isError: boolean
  preview: string
  tool: string
}

export interface SubagentNode {
  aggregate: SubagentAggregate
  children: SubagentNode[]
  item: SubagentProgress
}

export interface SubagentAggregate {
  activeCount: number
  costUsd: number
  descendantCount: number
  filesTouched: number
  hotness: number
  inputTokens: number
  maxDepthFromHere: number
  outputTokens: number
  totalDuration: number
  totalTools: number
}

export interface DelegationStatus {
  active: {
    depth?: number
    goal?: string
    model?: null | string
    parent_id?: null | string
    started_at?: number
    status?: string
    subagent_id?: string
    tool_count?: number
  }[]
  max_concurrent_children?: number
  max_spawn_depth?: number
  paused: boolean
}

export interface ApprovalReq {
  sharedControl?: SharedControl
  // false when the backend won't honor a permanent allow → hide "Always allow".
  allowPermanent?: boolean
  choices?: string[]
  command: string
  description: string
  /** Server→client request id; the answer is the response frame for it. */
  requestId: string
  smartDenied?: boolean
}

export interface ConfirmReq {
  cancelLabel?: string
  confirmLabel?: string
  danger?: boolean
  detail?: string
  onConfirm: () => void
  title: string
}

export interface ClarifyQuestion {
  choices: string[] | null
  multiSelect?: boolean
  qid: string
  question: string
}

export interface ClarifyReq {
  sharedControl?: SharedControl
  requestId: string
  questions: ClarifyQuestion[]
  /** Answers already locked server-side (qid → answer): seeded from the
   *  reconnect replay, updated as the user locks each question. */
  answers?: Record<string, string>
}

export interface Msg {
  info?: SessionInfo
  kind?: 'diff' | 'event' | 'intro' | 'panel' | 'slash' | 'trail'
  panelData?: PanelData
  role: Role
  text: string
  // Unix seconds the message was authored (persisted transcript timestamp on
  // rehydrate, wall clock at append time for live rows). Rendered as a dim
  // [HH:MM] label when `display.timestamps` is on (#41531).
  createdAt?: number
  thinking?: string
  // MoA reference-model output stored in `thinking` (see turnController's
  // recordMoaReference): unlike ordinary model reasoning, this is the
  // user-facing mixture-of-agents process the user opted into, so it stays
  // visible even when `display.sections.thinking` is hidden.
  isMoaReference?: boolean
  // True only while this trail segment's reasoning is being streamed live by
  // the current turn (see turnController's syncReasoningSegment). Sealed
  // reasoning segments from earlier in the turn carry no flag, so the TUI can
  // tell "the reasoning happening right now" apart from finished blocks.
  isLiveReasoning?: boolean
  thinkingTokens?: number
  toolTokens?: number
  tools?: string[]
  todos?: TodoItem[]
  todoIncomplete?: boolean
  todoCollapsedByDefault?: boolean
}

export type Role = 'assistant' | 'system' | 'tool' | 'user'
export type DetailsMode = 'hidden' | 'collapsed' | 'expanded'
export type ThinkingMode = 'collapsed' | 'truncated' | 'full'

// Per-section overrides for the agent details accordion.  Resolution order
// at lookup time is: explicit `display.sections.<name>` → built-in
// SECTION_DEFAULTS → global `details_mode`.  Today the built-in defaults
// expand `thinking`/`tools` and hide `activity`; `subagents` falls through
// to the global mode.  Any explicit value still wins for that one section.
export type SectionName = 'thinking' | 'tools' | 'subagents' | 'activity'
export type SectionVisibility = Partial<Record<SectionName, DetailsMode>>

export interface McpServerStatus {
  connected: boolean
  disabled?: boolean
  status?: 'configured' | 'connecting' | 'connected' | 'disabled' | 'failed' | 'lazy'
  name: string
  tools: number
  transport: string
}

/** The gateway's `session.info` / resume `info` block — generated from `tui_gateway/contracts`,
 *  plus the canonical-authority fields the legacy contract does not carry yet
 *  (`gateway/session_events.py` owner stamps and the durable admission FIFO). */
export interface SessionInfo extends SessionLiveInfo {
  execution_epoch?: string
  execution_generation?: number
  execution_state?: string
  install_warning?: string
  pending_submissions?: Array<{
    admission_id: string
    input_id?: string
    target_session_id: string
    target_profile_home: string
    status: string
    user: string
    outcome?: string | null
  }>
}
export type { ProjectInfo }

export interface SudoReq {
  requestId: string
}

export interface SecretReq {
  envVar: string
  prompt: string
  requestId: string
}

/** External password-manager unlock (1Password / Bitwarden) — masked master-password prompt. */
export interface VaultUnlockReq {
  backend: string
  displayName: string
  requestId: string
}

/**
 * `vault.save_login` server→client request — save a new website login from a
 * browser sign-in page. Two-step capture (identifier shown, password masked);
 * the answer goes only to the encrypted vault, never to the model.
 */
export interface VaultSaveLoginReq {
  origin: string
  requestId: string
  site: string
}

/** `vault.code` server→client request — a one-time sign-in code the user reads from their device. */
export interface VaultCodeReq {
  hint: string
  requestId: string
  site: string
}

export interface PanelData {
  sections: PanelSection[]
  title: string
}

export interface PanelSection {
  items?: string[]
  rows?: [string, string][]
  text?: string
  title?: string
}

export interface SlashCatalog {
  canon: Record<string, string>
  categories: SlashCategory[]
  pairs: [string, string][]
  skillCount: number
  sub: Record<string, string[]>
}

export interface SlashCategory {
  name: string
  pairs: [string, string][]
}
