/**
 * MockAgentManager Tests
 *
 * Comprehensive test suite for the MockAgentManager adapter covering
 * all scenario types: success, crash, waiting_for_input.
 */

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { MockAgentManager, type MockAgentScenario } from './mock-manager.js';
import type { EventBus, DomainEvent, AgentStoppedEvent } from '../events/types.js';

// =============================================================================
// Test Helpers
// =============================================================================

/**
 * Create a mock EventBus that captures emitted events.
 */
function createMockEventBus(): EventBus & { emittedEvents: DomainEvent[] } {
  const emittedEvents: DomainEvent[] = [];

  return {
    emittedEvents,
    emit<T extends DomainEvent>(event: T): void {
      emittedEvents.push(event);
    },
    on: vi.fn(),
    off: vi.fn(),
    once: vi.fn(),
  };
}

// =============================================================================
// Tests
// =============================================================================

describe('MockAgentManager', () => {
  let manager: MockAgentManager;
  let eventBus: ReturnType<typeof createMockEventBus>;

  beforeEach(() => {
    vi.useFakeTimers();
    eventBus = createMockEventBus();
    manager = new MockAgentManager({ eventBus });
  });

  afterEach(() => {
    manager.clear();
    vi.useRealTimers();
  });

  // ===========================================================================
  // spawn() with default scenario (immediate success)
  // ===========================================================================

  describe('spawn with default scenario', () => {
    it('should create agent with running status', async () => {
      const agent = await manager.spawn({
        name: 'test-agent',
        taskId: 'task-1',
        prompt: 'Do something',
      });

      expect(agent.name).toBe('test-agent');
      expect(agent.taskId).toBe('task-1');
      expect(agent.status).toBe('running');
      expect(agent.id).toBeDefined();
      expect(agent.sessionId).toBeDefined();
      expect(agent.worktreeId).toBeDefined();
    });

    it('should emit agent:spawned event', async () => {
      await manager.spawn({
        name: 'spawned-test',
        taskId: 'task-1',
        prompt: 'Do something',
      });

      expect(eventBus.emittedEvents.length).toBeGreaterThanOrEqual(1);
      const spawnedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:spawned');
      expect(spawnedEvent).toBeDefined();
      expect((spawnedEvent as any).payload.name).toBe('spawned-test');
      expect((spawnedEvent as any).payload.taskId).toBe('task-1');
    });

    it('should complete with success after timer fires', async () => {
      const agent = await manager.spawn({
        name: 'success-test',
        taskId: 'task-1',
        prompt: 'Do something',
      });

      // Timer hasn't fired yet
      expect(agent.status).toBe('running');

      // Advance timers
      await vi.advanceTimersByTimeAsync(0);

      // Check status changed
      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('idle');

      // Check result available
      const result = await manager.getResult(agent.id);
      expect(result).not.toBeNull();
      expect(result?.success).toBe(true);
      expect(result?.message).toBe('Task completed successfully');
    });

    it('should emit agent:stopped event on success completion', async () => {
      await manager.spawn({
        name: 'stop-event-test',
        taskId: 'task-1',
        prompt: 'Do something',
      });

      await vi.advanceTimersByTimeAsync(0);

      const stoppedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:stopped');
      expect(stoppedEvent).toBeDefined();
      expect((stoppedEvent as any).payload.reason).toBe('task_complete');
    });
  });

  // ===========================================================================
  // spawn() with configured delay
  // ===========================================================================

  describe('spawn with configured delay', () => {
    it('should not complete before delay expires', async () => {
      manager.setScenario('delayed-agent', {
        status: 'done',
        delay: 100,
        result: 'Delayed completion',
      });

      const agent = await manager.spawn({
        name: 'delayed-agent',
        taskId: 'task-1',
        prompt: 'Do something slowly',
      });

      // Advance by less than delay
      await vi.advanceTimersByTimeAsync(50);

      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('running');
    });

    it('should complete after delay expires', async () => {
      manager.setScenario('delayed-agent', {
        status: 'done',
        delay: 100,
        result: 'Delayed completion',
      });

      const agent = await manager.spawn({
        name: 'delayed-agent',
        taskId: 'task-1',
        prompt: 'Do something slowly',
      });

      // Advance past delay
      await vi.advanceTimersByTimeAsync(100);

      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('idle');

      const result = await manager.getResult(agent.id);
      expect(result?.message).toBe('Delayed completion');
    });
  });

  // ===========================================================================
  // spawn() with crash scenario
  // ===========================================================================

  describe('spawn with error scenario', () => {
    it('should emit agent:crashed and set result.success=false', async () => {
      manager.setScenario('crash-agent', {
        status: 'error',
        delay: 0,
        error: 'Something went terribly wrong',
      });

      const agent = await manager.spawn({
        name: 'crash-agent',
        taskId: 'task-1',
        prompt: 'Do something risky',
      });

      await vi.advanceTimersByTimeAsync(0);

      // Check status
      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('crashed');

      // Check result
      const result = await manager.getResult(agent.id);
      expect(result?.success).toBe(false);
      expect(result?.message).toBe('Something went terribly wrong');

      // Check event
      const crashedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:crashed');
      expect(crashedEvent).toBeDefined();
      expect((crashedEvent as any).payload.error).toBe('Something went terribly wrong');
    });
  });

  // ===========================================================================
  // spawn() with question scenario
  // ===========================================================================

  describe('spawn with questions scenario', () => {
    it('should emit agent:waiting and set status to waiting_for_input', async () => {
      manager.setScenario('waiting-agent', {
        status: 'questions',
        delay: 0,
        questions: [{ id: 'q1', question: 'Should I continue?' }],
      });

      const agent = await manager.spawn({
        name: 'waiting-agent',
        taskId: 'task-1',
        prompt: 'Ask a question',
      });

      await vi.advanceTimersByTimeAsync(0);

      // Check status
      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('waiting_for_input');

      // Check event
      const waitingEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:waiting');
      expect(waitingEvent).toBeDefined();
      expect((waitingEvent as any).payload.questions[0].question).toBe('Should I continue?');
    });
  });

  // ===========================================================================
  // resume() after waiting_for_input
  // ===========================================================================

  describe('resume after questions', () => {
    it('should emit agent:resumed and continue with scenario', async () => {
      manager.setScenario('resume-agent', {
        status: 'questions',
        delay: 0,
        questions: [{ id: 'q1', question: 'Need your input' }],
      });

      const agent = await manager.spawn({
        name: 'resume-agent',
        taskId: 'task-1',
        prompt: 'Start working',
      });

      // Let agent reach waiting state
      await vi.advanceTimersByTimeAsync(0);

      const waitingAgent = await manager.get(agent.id);
      expect(waitingAgent?.status).toBe('waiting_for_input');

      // Resume the agent with answers map
      await manager.resume(agent.id, { q1: 'Continue with this input' });

      // Check agent:resumed event emitted
      const resumedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:resumed');
      expect(resumedEvent).toBeDefined();
      expect((resumedEvent as any).payload.agentId).toBe(agent.id);
      expect((resumedEvent as any).payload.sessionId).toBe(agent.sessionId);

      // Status should be running again
      const runningAgent = await manager.get(agent.id);
      expect(runningAgent?.status).toBe('running');

      // Let it complete
      await vi.advanceTimersByTimeAsync(0);

      const completedAgent = await manager.get(agent.id);
      expect(completedAgent?.status).toBe('idle');

      const result = await manager.getResult(agent.id);
      expect(result?.success).toBe(true);
    });

    it('should throw if agent not waiting for input', async () => {
      const agent = await manager.spawn({
        name: 'not-waiting',
        taskId: 'task-1',
        prompt: 'Work',
      });

      await expect(manager.resume(agent.id, { q1: 'input' })).rejects.toThrow(
        'is not waiting for input'
      );
    });

    it('should throw if agent not found', async () => {
      await expect(manager.resume('non-existent-id', { q1: 'input' })).rejects.toThrow(
        'not found'
      );
    });
  });

  // ===========================================================================
  // stop() kills scheduled completion
  // ===========================================================================

  describe('stop', () => {
    it('should cancel scheduled completion and emit agent:stopped', async () => {
      manager.setScenario('stoppable-agent', {
        status: 'done',
        delay: 1000,
        result: 'Should not see this',
      });

      const agent = await manager.spawn({
        name: 'stoppable-agent',
        taskId: 'task-1',
        prompt: 'Long running task',
      });

      // Stop before completion
      await manager.stop(agent.id);

      // Check status
      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('stopped');

      // Check event
      const stoppedEvent = eventBus.emittedEvents.find(
        (e) => e.type === 'agent:stopped' && (e as any).payload.reason === 'user_requested'
      );
      expect(stoppedEvent).toBeDefined();

      // Advance time - should not complete now
      await vi.advanceTimersByTimeAsync(1000);

      const stillStopped = await manager.get(agent.id);
      expect(stillStopped?.status).toBe('stopped');
    });

    it('should throw if agent not found', async () => {
      await expect(manager.stop('non-existent-id')).rejects.toThrow('not found');
    });
  });

  // ===========================================================================
  // list() returns all agents with correct status
  // ===========================================================================

  describe('list', () => {
    it('should return all agents', async () => {
      await manager.spawn({ name: 'agent-1', taskId: 't1', prompt: 'p1' });
      await manager.spawn({ name: 'agent-2', taskId: 't2', prompt: 'p2' });
      await manager.spawn({ name: 'agent-3', taskId: 't3', prompt: 'p3' });

      const agents = await manager.list();

      expect(agents.length).toBe(3);
      expect(agents.map((a) => a.name).sort()).toEqual(['agent-1', 'agent-2', 'agent-3']);
    });

    it('should return empty array when no agents', async () => {
      const agents = await manager.list();
      expect(agents).toEqual([]);
    });
  });

  // ===========================================================================
  // get() and getByName() lookups
  // ===========================================================================

  describe('get and getByName', () => {
    it('get should return agent by ID', async () => {
      const spawned = await manager.spawn({
        name: 'get-test',
        taskId: 't1',
        prompt: 'p1',
      });

      const found = await manager.get(spawned.id);
      expect(found).not.toBeNull();
      expect(found?.name).toBe('get-test');
    });

    it('get should return null for unknown ID', async () => {
      const found = await manager.get('unknown-id');
      expect(found).toBeNull();
    });

    it('getByName should return agent by name', async () => {
      await manager.spawn({ name: 'named-agent', taskId: 't1', prompt: 'p1' });

      const found = await manager.getByName('named-agent');
      expect(found).not.toBeNull();
      expect(found?.name).toBe('named-agent');
    });

    it('getByName should return null for unknown name', async () => {
      const found = await manager.getByName('unknown-name');
      expect(found).toBeNull();
    });
  });

  // ===========================================================================
  // setScenario() overrides for specific agent names
  // ===========================================================================

  describe('setScenario overrides', () => {
    it('should use scenario override for specific agent name', async () => {
      // Set error scenario for one agent
      manager.setScenario('crasher', {
        status: 'error',
        delay: 0,
        error: 'Intentional crash',
      });

      // Spawn two agents - one with override, one with default
      const crasher = await manager.spawn({
        name: 'crasher',
        taskId: 't1',
        prompt: 'p1',
      });
      const normal = await manager.spawn({
        name: 'normal',
        taskId: 't2',
        prompt: 'p2',
      });

      await vi.advanceTimersByTimeAsync(0);

      // Crasher should have crashed
      const crasherUpdated = await manager.get(crasher.id);
      expect(crasherUpdated?.status).toBe('crashed');

      // Normal should have succeeded
      const normalUpdated = await manager.get(normal.id);
      expect(normalUpdated?.status).toBe('idle');
    });

    it('should allow clearing scenario override', async () => {
      manager.setScenario('flip-flop', {
        status: 'error',
        delay: 0,
        error: 'Crash for test',
      });

      // First spawn crashes
      const first = await manager.spawn({
        name: 'flip-flop',
        taskId: 't1',
        prompt: 'p1',
      });
      await vi.advanceTimersByTimeAsync(0);
      expect((await manager.get(first.id))?.status).toBe('crashed');

      // Clear scenario and remove agent
      manager.clearScenario('flip-flop');
      manager.clear();

      // Second spawn succeeds (default scenario)
      const second = await manager.spawn({
        name: 'flip-flop',
        taskId: 't2',
        prompt: 'p2',
      });
      await vi.advanceTimersByTimeAsync(0);
      expect((await manager.get(second.id))?.status).toBe('idle');
    });
  });

  // ===========================================================================
  // Event emission order verification
  // ===========================================================================

  describe('event emission order', () => {
    it('should emit spawned before completion events', async () => {
      await manager.spawn({ name: 'order-test', taskId: 't1', prompt: 'p1' });
      await vi.advanceTimersByTimeAsync(0);

      const eventTypes = eventBus.emittedEvents.map((e) => e.type);

      const spawnedIndex = eventTypes.indexOf('agent:spawned');
      const stoppedIndex = eventTypes.indexOf('agent:stopped');

      expect(spawnedIndex).toBeLessThan(stoppedIndex);
    });

    it('should emit spawned before crashed', async () => {
      manager.setScenario('crash-order', { status: 'error', delay: 0, error: 'Crash' });
      await manager.spawn({ name: 'crash-order', taskId: 't1', prompt: 'p1' });
      await vi.advanceTimersByTimeAsync(0);

      const eventTypes = eventBus.emittedEvents.map((e) => e.type);

      const spawnedIndex = eventTypes.indexOf('agent:spawned');
      const crashedIndex = eventTypes.indexOf('agent:crashed');

      expect(spawnedIndex).toBeLessThan(crashedIndex);
    });

    it('should emit spawned before waiting', async () => {
      manager.setScenario('wait-order', {
        status: 'questions',
        delay: 0,
        questions: [{ id: 'q1', question: 'Test question' }],
      });
      await manager.spawn({ name: 'wait-order', taskId: 't1', prompt: 'p1' });
      await vi.advanceTimersByTimeAsync(0);

      const eventTypes = eventBus.emittedEvents.map((e) => e.type);

      const spawnedIndex = eventTypes.indexOf('agent:spawned');
      const waitingIndex = eventTypes.indexOf('agent:waiting');

      expect(spawnedIndex).toBeLessThan(waitingIndex);
    });
  });

  // ===========================================================================
  // Name uniqueness validation
  // ===========================================================================

  describe('name uniqueness', () => {
    it('should throw when spawning agent with duplicate name', async () => {
      await manager.spawn({ name: 'unique-name', taskId: 't1', prompt: 'p1' });

      await expect(
        manager.spawn({ name: 'unique-name', taskId: 't2', prompt: 'p2' })
      ).rejects.toThrow("Agent with name 'unique-name' already exists");
    });
  });

  // ===========================================================================
  // Constructor options
  // ===========================================================================

  describe('constructor options', () => {
    it('should work without eventBus', async () => {
      const noEventManager = new MockAgentManager();
      const agent = await noEventManager.spawn({
        name: 'no-events',
        taskId: 't1',
        prompt: 'p1',
      });

      expect(agent.name).toBe('no-events');
      noEventManager.clear();
    });

    it('should use provided default scenario', async () => {
      const customDefault: MockAgentScenario = {
        status: 'error',
        delay: 0,
        error: 'Default crash',
      };

      const customManager = new MockAgentManager({
        eventBus,
        defaultScenario: customDefault,
      });

      const agent = await customManager.spawn({
        name: 'custom-default',
        taskId: 't1',
        prompt: 'p1',
      });

      await vi.advanceTimersByTimeAsync(0);

      expect((await customManager.get(agent.id))?.status).toBe('crashed');
      customManager.clear();
    });
  });

  // ===========================================================================
  // clear() cleanup
  // ===========================================================================

  describe('clear', () => {
    it('should remove all agents and cancel pending timers', async () => {
      manager.setScenario('pending', { status: 'done', delay: 1000 });

      await manager.spawn({ name: 'pending', taskId: 't1', prompt: 'p1' });
      await manager.spawn({ name: 'another', taskId: 't2', prompt: 'p2' });

      expect((await manager.list()).length).toBe(2);

      manager.clear();

      expect((await manager.list()).length).toBe(0);
    });
  });

  // ===========================================================================
  // Agent modes (execute, discuss, plan)
  // ===========================================================================

  describe('agent modes', () => {
    it('should spawn agent with default execute mode', async () => {
      const agent = await manager.spawn({
        name: 'exec-agent',
        taskId: 't1',
        prompt: 'test',
      });
      expect(agent.mode).toBe('execute');
    });

    it('should spawn agent in discuss mode', async () => {
      manager.setScenario('discuss-agent', {
        status: 'done',
        delay: 0,
        result: 'Auth discussion complete',
      });

      const agent = await manager.spawn({
        name: 'discuss-agent',
        taskId: 't1',
        prompt: 'discuss auth',
        mode: 'discuss',
      });

      expect(agent.mode).toBe('discuss');
    });

    it('should spawn agent in plan mode', async () => {
      manager.setScenario('plan-agent', {
        status: 'done',
        delay: 0,
        result: 'Plan complete',
      });

      const agent = await manager.spawn({
        name: 'plan-agent',
        taskId: 't1',
        prompt: 'plan work',
        mode: 'plan',
      });

      expect(agent.mode).toBe('plan');
    });

    it('should emit stopped event with context_complete reason for discuss mode', async () => {
      manager.setScenario('discuss-done', {
        status: 'done',
        delay: 0,
        result: 'Done',
      });

      await manager.spawn({
        name: 'discuss-done',
        taskId: 't1',
        prompt: 'test',
        mode: 'discuss',
      });
      await vi.runAllTimersAsync();

      const stopped = eventBus.emittedEvents.find((e) => e.type === 'agent:stopped') as AgentStoppedEvent | undefined;
      expect(stopped?.payload.reason).toBe('context_complete');
    });

    it('should emit stopped event with plan_complete reason for plan mode', async () => {
      manager.setScenario('plan-done', {
        status: 'done',
        delay: 0,
        result: 'Plan complete',
      });

      await manager.spawn({
        name: 'plan-done',
        taskId: 't1',
        prompt: 'test',
        mode: 'plan',
      });
      await vi.runAllTimersAsync();

      const stopped = eventBus.emittedEvents.find((e) => e.type === 'agent:stopped') as AgentStoppedEvent | undefined;
      expect(stopped?.payload.reason).toBe('plan_complete');
    });
  });

  // ===========================================================================
  // Detail mode (phase to tasks)
  // ===========================================================================

  describe('detail mode', () => {
    it('should spawn agent in detail mode', async () => {
      const agent = await manager.spawn({
        name: 'detailer',
        taskId: 'plan-1',
        prompt: 'Detail this phase',
        mode: 'detail',
      });
      expect(agent.mode).toBe('detail');
    });

    it('should complete with detail_complete reason in detail mode', async () => {
      manager.setScenario('detailer', {
        status: 'done',
        result: 'Detail complete',
      });

      await manager.spawn({ name: 'detailer', taskId: 'plan-1', prompt: 'test', mode: 'detail' });
      await vi.advanceTimersByTimeAsync(100);

      // Verify agent:stopped event with detail_complete reason (derived from mode)
      const stoppedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:stopped') as AgentStoppedEvent | undefined;
      expect(stoppedEvent).toBeDefined();
      expect(stoppedEvent?.payload.reason).toBe('detail_complete');
    });

    it('should pause on questions in detail mode', async () => {
      manager.setScenario('detailer', {
        status: 'questions',
        questions: [{ id: 'q1', question: 'How many tasks?' }],
      });

      await manager.spawn({ name: 'detailer', taskId: 'plan-1', prompt: 'test', mode: 'detail' });
      await vi.advanceTimersByTimeAsync(100);

      // Verify agent pauses for questions
      const stoppedEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:waiting');
      expect(stoppedEvent).toBeDefined();

      // Check agent status
      const agent = await manager.getByName('detailer');
      expect(agent?.status).toBe('waiting_for_input');
    });

    it('should set result message for detail mode', async () => {
      manager.setScenario('detailer', {
        status: 'done',
        result: 'Detail complete',
      });

      const agent = await manager.spawn({ name: 'detailer', taskId: 'plan-1', prompt: 'test', mode: 'detail' });
      await vi.runAllTimersAsync();

      const result = await manager.getResult(agent.id);
      expect(result?.success).toBe(true);
      expect(result?.message).toBe('Detail complete');
    });
  });

  // ===========================================================================
  // Structured question data (new schema tests)
  // ===========================================================================

  describe('structured questions data', () => {
    it('emits agent:waiting with structured questions data', async () => {
      manager.setScenario('test-agent', {
        status: 'questions',
        questions: [
          {
            id: 'q1',
            question: 'Which database?',
            options: [
              { label: 'PostgreSQL', description: 'Full-featured' },
              { label: 'SQLite', description: 'Lightweight' },
            ],
            multiSelect: false,
          },
        ],
      });

      await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' });
      await vi.runAllTimersAsync();

      const events = eventBus.emittedEvents.filter((e) => e.type === 'agent:waiting');
      expect(events.length).toBe(1);
      expect((events[0] as any).payload.questions).toHaveLength(1);
      expect((events[0] as any).payload.questions[0].options).toHaveLength(2);
      expect((events[0] as any).payload.questions[0].options[0].label).toBe('PostgreSQL');
      expect((events[0] as any).payload.questions[0].multiSelect).toBe(false);
    });

    it('stores pending questions for retrieval', async () => {
      manager.setScenario('test-agent', {
        status: 'questions',
        questions: [
          {
            id: 'q1',
            question: 'Which database?',
            options: [{ label: 'PostgreSQL' }],
          },
        ],
      });

      const agent = await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' });
      await vi.runAllTimersAsync();

      const pending = await manager.getPendingQuestions(agent.id);
      expect(pending?.questions[0].question).toBe('Which database?');
      expect(pending?.questions[0].options).toHaveLength(1);
      expect(pending?.questions[0].options?.[0].label).toBe('PostgreSQL');
    });

    it('clears pending questions after resume', async () => {
      manager.setScenario('resume-test', {
        status: 'questions',
        questions: [
          {
            id: 'q1',
            question: 'Need your input',
            options: [{ label: 'Option A' }, { label: 'Option B' }],
          },
        ],
      });

      const agent = await manager.spawn({ name: 'resume-test', taskId: 'task-1', prompt: 'test' });
      await vi.runAllTimersAsync();

      // Verify questions are pending
      const pendingBefore = await manager.getPendingQuestions(agent.id);
      expect(pendingBefore).not.toBeNull();
      expect(pendingBefore?.questions[0].question).toBe('Need your input');

      // Resume the agent with answers map
      await manager.resume(agent.id, { q1: 'Option A' });

      // Pending questions should be cleared
      const pendingAfter = await manager.getPendingQuestions(agent.id);
      expect(pendingAfter).toBeNull();
    });

    it('returns null for non-existent agent pending questions', async () => {
      const pending = await manager.getPendingQuestions('non-existent-id');
      expect(pending).toBeNull();
    });

    it('returns null for agent not in waiting state', async () => {
      const agent = await manager.spawn({ name: 'running-agent', taskId: 'task-1', prompt: 'test' });

      // Agent is running, not waiting
      const pending = await manager.getPendingQuestions(agent.id);
      expect(pending).toBeNull();
    });

    it('handles multiple questions in single scenario', async () => {
      manager.setScenario('multi-q-agent', {
        status: 'questions',
        questions: [
          {
            id: 'q1',
            question: 'Which database should we use?',
            options: [
              { label: 'PostgreSQL', description: 'Full-featured relational DB' },
              { label: 'SQLite', description: 'Lightweight embedded DB' },
            ],
          },
          {
            id: 'q2',
            question: 'Which ORM do you prefer?',
            options: [
              { label: 'Drizzle', description: 'TypeScript-first ORM' },
              { label: 'Prisma', description: 'Popular Node.js ORM' },
            ],
          },
          {
            id: 'q3',
            question: 'Any additional notes?',
            // No options - free-form text question
          },
        ],
      });

      const agent = await manager.spawn({ name: 'multi-q-agent', taskId: 'task-1', prompt: 'test' });
      await vi.runAllTimersAsync();

      // Check status
      const updated = await manager.get(agent.id);
      expect(updated?.status).toBe('waiting_for_input');

      // Check event has all questions
      const waitingEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:waiting');
      expect(waitingEvent).toBeDefined();
      expect((waitingEvent as any).payload.questions).toHaveLength(3);
      expect((waitingEvent as any).payload.questions[0].id).toBe('q1');
      expect((waitingEvent as any).payload.questions[1].id).toBe('q2');
      expect((waitingEvent as any).payload.questions[2].id).toBe('q3');

      // Check pending questions retrieval
      const pending = await manager.getPendingQuestions(agent.id);
      expect(pending?.questions).toHaveLength(3);
      expect(pending?.questions[0].question).toBe('Which database should we use?');
      expect(pending?.questions[1].question).toBe('Which ORM do you prefer?');
      expect(pending?.questions[2].question).toBe('Any additional notes?');
      expect(pending?.questions[2].options).toBeUndefined();

      // Resume with answers to all questions
      await manager.resume(agent.id, { q1: 'PostgreSQL', q2: 'Drizzle', q3: 'Use WAL mode' });
      await vi.runAllTimersAsync();

      // Agent should complete
      const completed = await manager.get(agent.id);
      expect(completed?.status).toBe('idle');

      // Pending questions should be cleared
      const clearedPending = await manager.getPendingQuestions(agent.id);
      expect(clearedPending).toBeNull();
    });
  });
});
