/**
 * E2E Tests for Detail Workflow
 *
 * Tests the complete detail workflow from phase through task creation:
 * - Detail mode: Break phase into executable tasks
 * - Q&A flow: Handle clarifying questions during detailing
 * - Task persistence: Save child tasks from detail output
 *
 * Uses TestHarness from src/test/ for full system wiring.
 */

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { createTestHarness, type TestHarness } from '../index.js';
import type { AgentStoppedEvent, AgentWaitingEvent } from '../../events/types.js';

describe('Detail Workflow E2E', () => {
  let harness: TestHarness;

  beforeEach(() => {
    harness = createTestHarness();
  });

  afterEach(() => {
    harness.cleanup();
    vi.useRealTimers();
  });

  describe('spawn detail agent', () => {
    it('should spawn agent in detail mode and complete with tasks', async () => {
      vi.useFakeTimers();

      // Setup: Create initiative -> phase -> plan
      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Auth Plan', 'Implement authentication');

      // Set detail scenario
      harness.setArchitectDetailComplete('detailer', [
        { number: 1, name: 'Create schema', content: 'User table', type: 'auto', dependencies: [] },
        { number: 2, name: 'Create endpoint', content: 'Login API', type: 'auto', dependencies: [1] },
      ]);

      // Spawn detail agent
      const agent = await harness.caller.spawnArchitectDetail({
        name: 'detailer',
        phaseId: phases[0].id,
      });

      expect(agent.mode).toBe('detail');

      // Advance timers for async completion
      await harness.advanceTimers();

      // Verify agent completed
      const events = harness.getEmittedEvents('agent:stopped') as AgentStoppedEvent[];
      expect(events).toHaveLength(1);
      expect(events[0].payload.name).toBe('detailer');
      expect(events[0].payload.reason).toBe('detail_complete');
    });

    it('should pause on questions and resume', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Complex Plan');

      // Set questions scenario
      harness.setArchitectDetailQuestions('detailer', [
        { id: 'q1', question: 'How granular should tasks be?' },
      ]);

      const agent = await harness.caller.spawnArchitectDetail({
        name: 'detailer',
        phaseId: phases[0].id,
      });

      await harness.advanceTimers();

      // Verify agent is waiting for input
      const waitingAgent = await harness.caller.getAgent({ name: 'detailer' });
      expect(waitingAgent?.status).toBe('waiting_for_input');

      // Verify paused on questions (emits agent:waiting, not agent:stopped)
      const waitingEvents = harness.getEmittedEvents('agent:waiting') as AgentWaitingEvent[];
      expect(waitingEvents).toHaveLength(1);
      expect(waitingEvents[0].payload.questions).toHaveLength(1);

      // Get pending questions
      const pending = await harness.mockAgentManager.getPendingQuestions(agent.id);
      expect(pending?.questions).toHaveLength(1);
      expect(pending?.questions[0].question).toBe('How granular should tasks be?');

      // Set completion scenario for resume
      harness.setArchitectDetailComplete('detailer', [
        { number: 1, name: 'Task 1', content: 'Single task', type: 'auto', dependencies: [] },
      ]);

      // Resume with answer
      await harness.caller.resumeAgent({
        name: 'detailer',
        answers: { q1: 'Very granular' },
      });
      await harness.advanceTimers();

      // Verify completed after resume
      const finalAgent = await harness.caller.getAgent({ name: 'detailer' });
      expect(finalAgent?.status).toBe('idle');
    });

    it('should handle multiple questions', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Multi-Q Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Complex Plan');

      // Set multiple questions scenario
      harness.setArchitectDetailQuestions('detailer', [
        { id: 'q1', question: 'What task granularity?', options: [{ label: 'Fine' }, { label: 'Coarse' }] },
        { id: 'q2', question: 'Include checkpoints?' },
        { id: 'q3', question: 'Any blocking dependencies?' },
      ]);

      const agent = await harness.caller.spawnArchitectDetail({
        name: 'detailer',
        phaseId: phases[0].id,
      });

      await harness.advanceTimers();

      // Verify all questions received
      const pending = await harness.mockAgentManager.getPendingQuestions(agent.id);
      expect(pending?.questions).toHaveLength(3);

      // Set completion scenario for resume
      harness.setArchitectDetailComplete('detailer', [
        { number: 1, name: 'Task 1', content: 'First task', type: 'auto', dependencies: [] },
        { number: 2, name: 'Task 2', content: 'Second task', type: 'auto', dependencies: [1] },
        { number: 3, name: 'Verify', content: 'Verify all', type: 'auto', dependencies: [2] },
      ]);

      // Resume with all answers
      await harness.caller.resumeAgent({
        name: 'detailer',
        answers: {
          q1: 'Fine',
          q2: 'Yes, add human verification',
          q3: 'Tasks 1 and 2 are sequential',
        },
      });
      await harness.advanceTimers();

      // Verify completed
      const finalAgent = await harness.caller.getAgent({ name: 'detailer' });
      expect(finalAgent?.status).toBe('idle');
    });
  });

  describe('detail conflict detection', () => {
    it('should reject if a detail agent is already running for the same phase', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);

      // Long-running detail agent
      harness.setAgentScenario('detailer-1', { status: 'done', delay: 999999 });

      await harness.caller.spawnArchitectDetail({
        name: 'detailer-1',
        phaseId: phases[0].id,
      });

      // Second detail for same phase should be rejected
      await expect(
        harness.caller.spawnArchitectDetail({
          name: 'detailer-2',
          phaseId: phases[0].id,
        }),
      ).rejects.toThrow(/already running/);
    });

    it('should auto-dismiss stale detail agents before checking', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);

      // Detail agent that crashes immediately
      harness.setAgentScenario('stale-detailer', { status: 'error', error: 'crashed' });

      await harness.caller.spawnArchitectDetail({
        name: 'stale-detailer',
        phaseId: phases[0].id,
      });
      await harness.advanceTimers();

      // New detail should succeed
      harness.setArchitectDetailComplete('new-detailer', [
        { number: 1, name: 'Task 1', content: 'Do it', type: 'auto', dependencies: [] },
      ]);

      const agent = await harness.caller.spawnArchitectDetail({
        name: 'new-detailer',
        phaseId: phases[0].id,
      });
      expect(agent.mode).toBe('detail');
    });

    it('should allow detail for different phases simultaneously', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
        { name: 'Phase 2' },
      ]);

      // Long-running agent on phase 1
      harness.setAgentScenario('detailer-p1', { status: 'done', delay: 999999 });
      await harness.caller.spawnArchitectDetail({
        name: 'detailer-p1',
        phaseId: phases[0].id,
      });

      // Detail on phase 2 should succeed
      harness.setArchitectDetailComplete('detailer-p2', [
        { number: 1, name: 'Task 1', content: 'Do it', type: 'auto', dependencies: [] },
      ]);

      const agent = await harness.caller.spawnArchitectDetail({
        name: 'detailer-p2',
        phaseId: phases[1].id,
      });
      expect(agent.mode).toBe('detail');
    });
  });

  describe('task persistence', () => {
    it('should create tasks from detail output', async () => {
      const initiative = await harness.createInitiative('Test Project');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Auth Plan');

      // Create tasks from detail output
      await harness.caller.createChildTasks({
        parentTaskId: detailTask.id,
        tasks: [
          { number: 1, name: 'Schema', description: 'Create tables', type: 'auto', dependencies: [] },
          { number: 2, name: 'API', description: 'Create endpoints', type: 'auto', dependencies: [1] },
          { number: 3, name: 'Verify', description: 'Test flow', type: 'auto', dependencies: [2] },
        ],
      });

      // Verify tasks created
      const tasks = await harness.getChildTasks(detailTask.id);
      expect(tasks).toHaveLength(3);
      expect(tasks[0].name).toBe('Schema');
      expect(tasks[1].name).toBe('API');
      expect(tasks[2].name).toBe('Verify');
      expect(tasks[2].type).toBe('auto');
    });

    it('should create tasks with auto type', async () => {
      const initiative = await harness.createInitiative('Task Types Test');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Mixed Tasks');

      await harness.caller.createChildTasks({
        parentTaskId: detailTask.id,
        tasks: [
          { number: 1, name: 'Auto Task', description: 'Automated work', type: 'auto' },
          { number: 2, name: 'Second Task', description: 'More work', type: 'auto', dependencies: [1] },
          { number: 3, name: 'Third Task', description: 'Even more', type: 'auto', dependencies: [2] },
          { number: 4, name: 'Final Task', description: 'Last step', type: 'auto', dependencies: [3] },
        ],
      });

      const tasks = await harness.getChildTasks(detailTask.id);
      expect(tasks).toHaveLength(4);
      for (const task of tasks) {
        expect(task.type).toBe('auto');
      }
    });

    it('should create task dependencies', async () => {
      const initiative = await harness.createInitiative('Dependencies Test');
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Phase 1' },
      ]);
      const detailTask = await harness.createDetailTask(phases[0].id, 'Dependent Tasks');

      // Create tasks with complex dependencies
      await harness.caller.createChildTasks({
        parentTaskId: detailTask.id,
        tasks: [
          { number: 1, name: 'Task A', description: 'No deps', type: 'auto' },
          { number: 2, name: 'Task B', description: 'Depends on A', type: 'auto', dependencies: [1] },
          { number: 3, name: 'Task C', description: 'Depends on A', type: 'auto', dependencies: [1] },
          { number: 4, name: 'Task D', description: 'Depends on B and C', type: 'auto', dependencies: [2, 3] },
        ],
      });

      const tasks = await harness.getChildTasks(detailTask.id);
      expect(tasks).toHaveLength(4);

      // All tasks should be created with correct names
      expect(tasks.map(t => t.name)).toEqual(['Task A', 'Task B', 'Task C', 'Task D']);
    });
  });

  describe('full detail workflow', () => {
    it('should complete initiative -> phase -> plan -> detail -> tasks workflow', async () => {
      vi.useFakeTimers();

      // 1. Create initiative
      const initiative = await harness.createInitiative('Full Workflow Test');

      // 2. Create phase
      const phases = await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Auth Phase' },
      ]);

      // 3. Create plan
      const detailTask = await harness.createDetailTask(phases[0].id, 'Auth Plan', 'Implement JWT auth');

      // 4. Spawn detail agent
      harness.setArchitectDetailComplete('detailer', [
        { number: 1, name: 'Create user schema', content: 'Define User model', type: 'auto', dependencies: [] },
        { number: 2, name: 'Implement JWT', content: 'Token generation', type: 'auto', dependencies: [1] },
        { number: 3, name: 'Protected routes', content: 'Middleware', type: 'auto', dependencies: [2] },
        { number: 4, name: 'Verify auth', content: 'Test login flow', type: 'auto', dependencies: [3] },
      ]);

      await harness.caller.spawnArchitectDetail({
        name: 'detailer',
        phaseId: phases[0].id,
      });
      await harness.advanceTimers();

      // 5. Verify agent completed
      const events = harness.getEmittedEvents('agent:stopped') as AgentStoppedEvent[];
      expect(events).toHaveLength(1);
      expect(events[0].payload.reason).toBe('detail_complete');

      // 6. Persist tasks (simulating what orchestrator would do after detail)
      await harness.caller.createChildTasks({
        parentTaskId: detailTask.id,
        tasks: [
          { number: 1, name: 'Create user schema', description: 'Define User model', type: 'auto', dependencies: [] },
          { number: 2, name: 'Implement JWT', description: 'Token generation', type: 'auto', dependencies: [1] },
          { number: 3, name: 'Protected routes', description: 'Middleware', type: 'auto', dependencies: [2] },
          { number: 4, name: 'Verify auth', description: 'Test login flow', type: 'auto', dependencies: [3] },
        ],
      });

      // 7. Verify final state
      const tasks = await harness.getChildTasks(detailTask.id);
      expect(tasks).toHaveLength(4);
      expect(tasks[0].name).toBe('Create user schema');
      expect(tasks[3].type).toBe('auto');

      // Agent should be idle
      const finalAgent = await harness.caller.getAgent({ name: 'detailer' });
      expect(finalAgent?.status).toBe('idle');
    });
  });
});
