/**
 * Agent Module Types
 *
 * Port interface for agent lifecycle management.
 * AgentManager is the PORT. Implementations are ADAPTERS.
 */

export type AgentStatus = 'idle' | 'running' | 'waiting_for_input' | 'stopped' | 'crashed';

/**
 * Agent operation mode.
 *
 * - execute: Standard task execution (default)
 * - discuss: Gather context through questions, output decisions
 * - plan: Plan initiative into phases
 * - detail: Detail phase into individual tasks
 */
export type AgentMode = 'execute' | 'discuss' | 'plan' | 'detail' | 'refine' | 'chat' | 'errand';

/**
 * Context data written as input files in agent workdir before spawn.
 */
export interface AgentInputContext {
  initiative?: import('../db/schema.js').Initiative;
  pages?: import('./content-serializer.js').PageForSerialization[];
  phase?: import('../db/schema.js').Phase;
  task?: import('../db/schema.js').Task;
  /** All phases for the initiative (read-only context for agents) */
  phases?: Array<import('../db/schema.js').Phase & { dependsOn?: string[] }>;
  /** All tasks for the initiative (read-only context for agents) */
  tasks?: import('../db/schema.js').Task[];
  /** Agent ID for inter-agent communication */
  agentId?: string;
  /** Agent name for inter-agent communication */
  agentName?: string;
}

/**
 * Options for spawning a new agent
 */
export interface SpawnAgentOptions {
  /** Human-readable name/alias for the agent (auto-generated if omitted) */
  name?: string;
  /** Task ID to assign to agent (optional for architect modes) */
  taskId?: string | null;
  /** Initial prompt/instruction for the agent */
  prompt: string;
  /** Optional working directory (defaults to worktree path) */
  cwd?: string;
  /** Agent operation mode (defaults to 'execute') */
  mode?: AgentMode;
  /** Provider name (defaults to 'claude') */
  provider?: string;
  /** Initiative ID — when set, worktrees are created for all linked projects */
  initiativeId?: string;
  /** Phase ID — used by dispatch for branch-aware spawning */
  phaseId?: string;
  /** Base branch for worktree creation (defaults to 'main') */
  baseBranch?: string;
  /** Explicit branch name for worktree (overrides 'agent/<alias>') */
  branchName?: string;
  /** Context data to write as input files in agent workdir */
  inputContext?: AgentInputContext;
}

/**
 * Represents a Claude agent instance
 */
export interface AgentInfo {
  /** Unique identifier for this agent */
  id: string;
  /** Human-readable alias for the agent (e.g. 'jolly-penguin') */
  name: string;
  /** Task this agent is working on (null for architect agents) */
  taskId: string | null;
  /** Initiative this agent is linked to (null if standalone) */
  initiativeId: string | null;
  /** CLI session ID for resumption (null until first run completes) */
  sessionId: string | null;
  /** Agent alias / worktree key (deterministic path: agent-workdirs/<alias>/) */
  worktreeId: string;
  /** Current status (waiting_for_input = paused on AskUserQuestion) */
  status: AgentStatus;
  /** Current operation mode */
  mode: AgentMode;
  /** Provider name (e.g. 'claude', 'codex', 'gemini') */
  provider: string;
  /** Account ID used for this agent (null if no account management) */
  accountId: string | null;
  /** When the agent was created */
  createdAt: Date;
  /** Last activity timestamp */
  updatedAt: Date;
  /** When the user dismissed this agent (null if not dismissed) */
  userDismissedAt?: Date | null;
}

/**
 * Result from agent execution
 */
export interface AgentResult {
  /** Whether the task completed successfully */
  success: boolean;
  /** Result message or error description */
  message: string;
  /** Files modified during execution */
  filesModified?: string[];
}

/**
 * Individual question item with unique ID for answer matching
 */
export interface QuestionItem {
  /** Unique identifier for matching answers */
  id: string;
  /** The question being asked */
  question: string;
  /** Optional predefined options for the question */
  options?: Array<{ label: string; description?: string }>;
  /** Whether multiple options can be selected */
  multiSelect?: boolean;
}

/**
 * Pending questions when agent is waiting for input
 */
export interface PendingQuestions {
  /** Array of questions the agent is asking */
  questions: QuestionItem[];
}

/**
 * AgentManager Port Interface
 *
 * Manages Claude agent lifecycle - spawn, stop, list, resume.
 *
 * Covers requirements:
 * - AGENT-01: Spawn new agent with task assignment
 * - AGENT-02: Stop running agent
 * - AGENT-03: List all agents with status
 * - AGENT-04: Resume agent session
 * - AGENT-05: Background mode (implementation detail)
 */
export interface AgentManager {
  /**
   * Spawn a new agent to work on a task.
   *
   * Creates isolated worktree, starts Claude SDK session,
   * and begins executing the prompt.
   *
   * @param options - Spawn configuration
   * @returns Agent info with session ID for later resumption
   */
  spawn(options: SpawnAgentOptions): Promise<AgentInfo>;

  /**
   * Stop a running agent.
   *
   * Gracefully stops the agent's work. Worktree is preserved
   * for potential resumption.
   *
   * @param agentId - Agent to stop
   */
  stop(agentId: string): Promise<void>;

  /**
   * List all agents with their current status.
   *
   * @returns Array of all agents
   */
  list(): Promise<AgentInfo[]>;

  /**
   * Get a specific agent by ID.
   *
   * @param agentId - Agent ID
   * @returns Agent if found, null otherwise
   */
  get(agentId: string): Promise<AgentInfo | null>;

  /**
   * Get a specific agent by name.
   *
   * @param name - Agent name (human-readable)
   * @returns Agent if found, null otherwise
   */
  getByName(name: string): Promise<AgentInfo | null>;

  /**
   * Resume an agent that's waiting for input.
   *
   * Used when agent paused on questions and user provides responses.
   * Uses stored session ID to continue with full context.
   * Agent must be in 'waiting_for_input' status.
   *
   * @param agentId - Agent to resume
   * @param answers - Map of question ID to user's answer
   */
  resume(agentId: string, answers: Record<string, string>): Promise<void>;

  /**
   * Get the result of an agent's work.
   *
   * Only available after agent completes or stops.
   *
   * @param agentId - Agent ID
   * @returns Result if available, null if agent still running
   */
  getResult(agentId: string): Promise<AgentResult | null>;

  /**
   * Get pending questions for an agent waiting for input.
   *
   * Only available when agent status is 'waiting_for_input'.
   *
   * @param agentId - Agent ID
   * @returns Pending questions if available, null otherwise
   */
  getPendingQuestions(agentId: string): Promise<PendingQuestions | null>;

  /**
   * Delete an agent and clean up all associated resources.
   *
   * Tears down worktrees, branches, logs, and removes the DB record.
   * If the agent is still running, kills the process first.
   *
   * @param agentId - Agent to delete
   */
  delete(agentId: string): Promise<void>;

  /**
   * Dismiss an agent.
   *
   * Marks the agent as dismissed by the user, which excludes it from
   * active agent queries. The agent record and worktree are preserved.
   *
   * @param agentId - Agent to dismiss
   */
  dismiss(agentId: string): Promise<void>;

  /**
   * Resume an idle agent to answer an inter-agent conversation.
   *
   * When Agent A asks Agent B a question via `cw ask` and Agent B is idle,
   * this resumes B's session with a prompt to answer via `cw answer` and
   * drain any remaining pending conversations via `cw listen`.
   *
   * @param agentId - The idle agent to resume
   * @param conversationId - The conversation that triggered the resume
   * @param question - The question being asked
   * @param fromAgentId - The agent asking the question
   * @returns true if resume was initiated, false if not possible
   */
  resumeForConversation(
    agentId: string,
    conversationId: string,
    question: string,
    fromAgentId: string,
  ): Promise<boolean>;

  /**
   * Deliver a user message to a running errand agent.
   * Does not use the conversations table — the message is injected directly
   * into the agent's Claude Code session as a resume prompt.
   *
   * @param agentId - The errand agent to message
   * @param message - The user's message text
   */
  sendUserMessage(agentId: string, message: string): Promise<void>;
}
