// v2.8.0: Dynamic Workflow Engine — types for the sandboxed multi-agent
// orchestration runtime. All types are exported for testing.

/**
 * The expected shape of a workflow script module.
 * Workflow files are plain .js files that export `meta` and `default`:
 *
 * ```js
 * export const meta = {
 *   name: 'my-workflow',
 *   description: 'Does something useful in phases',
 *   phases: [
 *     { title: 'Research', detail: 'Gather context' },
 *     { title: 'Implement', detail: 'Make changes' },
 *   ],
 * };
 *
 * export default async function main(args) {
 *   const result = await agent('...');
 *   return result;
 * }
 * ```
 */
export interface WorkflowScriptMeta {
  name: string;
  description: string;
  phases?: Array<{ title: string; detail?: string }>;
}

export interface WorkflowScript {
  meta: WorkflowScriptMeta;
  default: (args?: Record<string, unknown>) => Promise<unknown>;
}

/**
 * Specification for dispatching a single agent task within a workflow.
 */
export interface AgentTaskSpec {
  /** The instruction prompt for the agent. */
  prompt: string;
  /** Optional human-readable label for this task (shown in UI). */
  label?: string;
  /** Phase identifier for grouping tasks. */
  phase?: string;
  /** Model override (defaults to session/chat model). */
  model?: string;
  /** Zod-style JSON schema for structured output validation. */
  schema?: Record<string, unknown>;
  /** Required capabilities the agent must have. */
  capabilities?: string[];
  /** Per-agent tool-call budget ceiling. */
  max_tool_calls?: number;
  /** Per-agent step cap for the inference loop. */
  max_tool_iters?: number;
}

/**
 * Result returned after an agent task completes.
 */
export interface AgentTaskResult {
  ok: boolean;
  output: unknown;
  error?: string;
  token_usage?: { prompt: number; completion: number };
  /** True when this result was served from the resumability cache
   *  rather than re-executing the agent task. */
  cached?: boolean;
}

/**
 * Runtime context passed into every workflow script's default function.
 * Mirrors the Claude Code-compatible API surface.
 */
export interface WorkflowContext {
  /** Dispatch a single agent prompt. Returns the assistant's reply content. */
  agent: (prompt: string, opts?: AgentTaskSpec) => Promise<unknown>;
  /** Run multiple independent tasks concurrently. Returns results in order. */
  parallel: (thunks: Array<() => Promise<unknown>>) => Promise<unknown[]>;
  /** Pass items through a sequence of transform stages. */
  pipeline: (
    items: unknown[],
    ...stages: Array<(item: unknown) => Promise<unknown>>
  ) => Promise<unknown[]>;
  /** Announce the current execution phase (for UI progress). */
  phase: (title: string) => void;
  /** Emit a log message for this workflow run. */
  log: (message: string) => void;
  /** Token budget tracker for the current run. */
  budget: {
    total: number | null;
    spent: () => number;
    remaining: () => number;
  };
  /** The arguments passed when this workflow was started. */
  args: Record<string, unknown>;
  /** Call another workflow from within a workflow (nested). */
  workflow: (name: string, args?: Record<string, unknown>) => Promise<unknown>;
}

/**
 * Status of a workflow execution run.
 */
export type WorkflowRunStatus = 'running' | 'completed' | 'failed' | 'cancelled';

/**
 * Persistent record of a workflow run.
 */
export interface WorkflowRun {
  id: string;
  name: string;
  status: WorkflowRunStatus;
  started_at: string;
  finished_at?: string;
  error?: string;
}

/**
 * Event emitted by the workflow manager for subscribers.
 */
export type WorkflowEvent =
  | { type: 'run_started'; runId: string; name: string }
  | { type: 'run_completed'; runId: string; name: string }
  | { type: 'run_failed'; runId: string; name: string; error: string }
  | { type: 'run_cancelled'; runId: string; name: string }
  | { type: 'phase'; runId: string; title: string }
  | { type: 'log'; runId: string; message: string }
  | { type: 'agent_task_started'; runId: string; label?: string }
  | { type: 'agent_task_completed'; runId: string; label?: string };
