/**
 * Shared types for the workflow runtime.
 *
 * The runtime depends only on `SubagentRunner` — the adapter that wraps the
 * concrete child-agent factory lives in `subagent-runner.ts`. This keeps
 * `runtime.ts` free of any LLM-stack imports and makes alternate runners
 * (remote agents, test doubles) drop-in replacements.
 */

import type { Model, Api } from '@earendil-works/pi-ai';

/** Plain JSON Schema (no TypeBox brand). Mirrors the shape models emit verbatim. */
export interface JsonSchema {
  type?: string | string[];
  properties?: Record<string, JsonSchema>;
  items?: JsonSchema | JsonSchema[];
  required?: string[];
  additionalProperties?: boolean | JsonSchema;
  enum?: unknown[];
  const?: unknown;
  description?: string;
  [key: string]: unknown;
}

export interface WorkflowMetaPhase {
  title: string;
  detail?: string;
  /** Default model for this phase: `provider/model` or configured typed id. */
  model?: string;
}

export interface WorkflowMetaEstimatedAgents {
  min: number;
  max: number;
}

/** One-click starter text in the gateway start dialog; `field` is `goal` or an `args` key. */
export interface WorkflowMetaExamplePrompt {
  field: string;
  text: string;
}

/** Locale-specific copy overrides; top-level `description` / `whenToUse` / `examplePrompts` are English defaults. */
export interface WorkflowMetaLocale {
  description?: string;
  whenToUse?: string;
  examplePrompts?: WorkflowMetaExamplePrompt[];
}

export interface WorkflowMeta {
  name: string;
  description: string;
  whenToUse?: string;
  phases?: WorkflowMetaPhase[];
  /** Discovery tags, e.g. `['code-review', 'planning']`. */
  tags?: string[];
  /** Rough subagent count range for UX / cost hints. */
  estimatedAgents?: WorkflowMetaEstimatedAgents;
  /** English-default example prompts for the gateway start dialog. */
  examplePrompts?: WorkflowMetaExamplePrompt[];
  /** Non-English locale bundles keyed by BCP-47 language tag (e.g. `zh`). */
  i18n?: Record<string, WorkflowMetaLocale>;
}

export type WorkflowAgentStatus = 'queued' | 'running' | 'done' | 'error' | 'skipped';

export type WorkflowAgentStepStatus = 'running' | 'done' | 'error';

export interface WorkflowAgentStep {
  id: string;
  kind: 'tool' | 'llm' | 'thinking';
  /** Original tool name when `kind === 'tool'` (for chat UI reuse). */
  toolName?: string;
  label: string;
  detail?: string;
  status: WorkflowAgentStepStatus;
  startedAtMs?: number;
  durationMs?: number;
}

export interface WorkflowAgentSnapshot {
  id: number;
  label: string;
  phase?: string;
  prompt: string;
  status: WorkflowAgentStatus;
  resultPreview?: string;
  error?: string;
  startedAtMs?: number;
  durationMs?: number;
  steps?: WorkflowAgentStep[];
  /** One-line summary for inline agent rows. */
  currentStep?: string;
  iteration?: number;
  maxIterations?: number;
  /** Accumulated assistant/thinking text when subagentStream is `full`. */
  streamText?: string;
}

export interface WorkflowSnapshot {
  name: string;
  description?: string;
  phases: string[];
  currentPhase?: string;
  logs: string[];
  agents: WorkflowAgentSnapshot[];
  agentCount: number;
  runningCount: number;
  doneCount: number;
  errorCount: number;
  skippedCount: number;
  durationMs?: number;
  result?: unknown;
}

export interface SubagentRunOptions<T = unknown> {
  label: string;
  /** When set, the subagent must return a value matching the schema (validated via ajv). */
  schema?: JsonSchema;
  /** Per-agent overrides; defaults filled by the runner adapter. */
  allowedToolNames?: string[];
  maxIterations?: number;
  /** Resolved model. When omitted the adapter falls back to the workflow-level default. */
  model?: Model<Api>;
  signal?: AbortSignal;
  /** Extra guidance prepended to the subagent prompt. */
  instructions?: string;
  /** When false (default), failures resolve to `null`; when true, errors propagate. */
  rethrow?: boolean;
  /** Hint about which phase this agent belongs to (passed through for logging). */
  phase?: string;
  /** Live progress from the child agent loop (workflow tool binds per agent id). */
  onProgress?: (event: SubagentProgressEvent) => void;
  /** Pre-bound capture for structured output (internal: created by the adapter when schema present). */
  __capture?: { called: boolean; value?: T };
}

export type SubagentProgressEvent =
  | { type: 'tool_start'; toolCallId: string; toolName: string; args: Record<string, unknown> }
  | { type: 'tool_end'; toolCallId: string; toolName: string; isError: boolean }
  | { type: 'iteration'; count: number; max: number }
  | { type: 'text_delta'; delta: string }
  | { type: 'thinking_delta'; delta: string };

/**
 * Spawns a single fresh subagent and returns its result.
 *
 * - Without `schema`: returns the final assistant text (`string`).
 * - With `schema`: returns the value the subagent passed to the injected
 *   `structured_output` tool (validated, typed as `T`).
 *
 * Returns `null` when the subagent fails or aborts — runtime keeps going.
 */
export interface SubagentRunner {
  run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null>;
}

/** Options accepted by `agent()` inside a workflow script. */
export interface AgentScriptOptions {
  label?: string;
  phase?: string;
  schema?: JsonSchema;
  /**
   * Model ref: `provider/model` or a configured typed id (e.g. `small`, `@large`).
   */
  model?: string;
  /** Subagent tool allowlist override (forwarded to the runner). */
  toolset?: string[];
  /** Max tool iterations inside the subagent. */
  maxIterations?: number;
}

export interface WorkflowRunOptions {
  args?: unknown;
  cwd: string;
  signal?: AbortSignal;
  /** Hard upper bound on concurrent subagents (default min(16, cpu-2)). */
  concurrency?: number;
  /** Total token budget exposed to script via `budget`. `null` = unlimited. */
  tokenBudget?: number | null;
  /** Hard cap on total subagent count for one workflow run (default 1000). */
  maxSubagents?: number;
  onLog?: (message: string) => void;
  onPhase?: (title: string) => void;
  onAgentQueued?: (event: { id: number; label: string; phase?: string; prompt: string }) => void;
  onAgentStart?: (event: { id: number; label: string; phase?: string; prompt: string }) => void;
  onAgentEnd?: (event: { id: number; label: string; phase?: string; result: unknown; status: WorkflowAgentStatus }) => void;
  /** Merge extra subagent run options (e.g. progress callbacks) per agent id. */
  enhanceSubagentRun?: (ctx: {
    id: number;
    label: string;
    phase?: string;
    prompt: string;
  }) => Partial<SubagentRunOptions<unknown>>;
}

export interface WorkflowRunResult<T = unknown> {
  meta: WorkflowMeta;
  result: T;
  logs: string[];
  phases: string[];
  agentCount: number;
  durationMs: number;
}
