/**
 * E2E Tests for Architect Workflow
 *
 * Tests the complete architect workflow from discussion through phase creation:
 * - Discuss mode: Gather context, answer questions, capture decisions
 * - Plan mode: Break initiative into phases
 * - Full workflow: Discuss -> Plan -> Phase persistence
 *
 * 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 } from '../../events/types.js';

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

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

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

  describe('discuss mode', () => {
    it('should spawn architect in discuss mode and complete with decisions', async () => {
      vi.useFakeTimers();

      // Create initiative
      const initiative = await harness.createInitiative('Auth System');

      // Set up discuss completion scenario
      harness.setArchitectDiscussComplete('auth-discuss', [
        { topic: 'Auth Method', decision: 'JWT', reason: 'Stateless, scalable' },
        { topic: 'Token Storage', decision: 'httpOnly cookie', reason: 'XSS protection' },
      ], 'Auth approach decided');

      // Spawn architect in discuss mode
      const agent = await harness.caller.spawnArchitectDiscuss({
        name: 'auth-discuss',
        initiativeId: initiative.id,
      });

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

      // Wait for completion
      await harness.advanceTimers();

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

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

      const initiative = await harness.createInitiative('Auth System');

      // First, agent asks questions
      harness.setArchitectDiscussQuestions('auth-discuss', [
        { id: 'q1', question: 'JWT or Session?', options: [{ label: 'JWT' }, { label: 'Session' }] },
        { id: 'q2', question: 'OAuth providers?' },
      ]);

      const agent = await harness.caller.spawnArchitectDiscuss({
        name: 'auth-discuss',
        initiativeId: initiative.id,
      });

      await harness.advanceTimers();

      // Agent should be waiting
      const waitingAgent = await harness.caller.getAgent({ name: 'auth-discuss' });
      expect(waitingAgent?.status).toBe('waiting_for_input');

      // Get pending questions
      const pending = await harness.mockAgentManager.getPendingQuestions(agent.id);
      expect(pending?.questions).toHaveLength(2);

      // Now set up completion scenario for after resume
      harness.setArchitectDiscussComplete('auth-discuss', [
        { topic: 'Auth', decision: 'JWT', reason: 'User chose' },
      ], 'Complete');

      // Resume with answers
      await harness.caller.resumeAgent({
        name: 'auth-discuss',
        answers: { q1: 'JWT', q2: 'Google, GitHub' },
      });

      await harness.advanceTimers();

      // Should complete
      const finalAgent = await harness.caller.getAgent({ name: 'auth-discuss' });
      expect(finalAgent?.status).toBe('idle');
    });
  });

  describe('plan mode', () => {
    it('should spawn architect in plan mode and create phases', async () => {
      vi.useFakeTimers();

      const initiative = await harness.createInitiative('Auth System');

      // Set up plan completion
      harness.setArchitectPlanComplete('auth-plan', [
        { number: 1, name: 'Database Setup', description: 'User table and auth schema', dependencies: [] },
        { number: 2, name: 'JWT Implementation', description: 'Token generation and validation', dependencies: [1] },
        { number: 3, name: 'Protected Routes', description: 'Middleware and route guards', dependencies: [2] },
      ]);

      const agent = await harness.caller.spawnArchitectPlan({
        name: 'auth-plan',
        initiativeId: initiative.id,
      });

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

      await harness.advanceTimers();

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

    it('should persist phases from plan output', async () => {
      const initiative = await harness.createInitiative('Auth System');

      const phasesData = [
        { name: 'Foundation' },
        { name: 'Features' },
      ];

      // Persist phases (simulating what would happen after plan)
      const created = await harness.createPhasesFromPlan(initiative.id, phasesData);

      expect(created).toHaveLength(2);

      // Verify retrieval
      const phases = await harness.getPhases(initiative.id);
      expect(phases).toHaveLength(2);
      expect(phases[0].name).toBe('Foundation');
      expect(phases[1].name).toBe('Features');
    });
  });

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

      const initiative = await harness.createInitiative('Auth System');

      // Set up a long-running plan agent (never completes during this test)
      harness.setArchitectPlanComplete('first-plan', [
        { number: 1, name: 'Phase 1', description: 'First', dependencies: [] },
      ]);
      // Use a delay so it stays running
      harness.setAgentScenario('first-plan', { status: 'done', delay: 999999 });

      await harness.caller.spawnArchitectPlan({
        name: 'first-plan',
        initiativeId: initiative.id,
      });

      // Agent should be running
      const agents = await harness.caller.listAgents();
      expect(agents.find(a => a.name === 'first-plan')?.status).toBe('running');

      // Second plan should be rejected
      await expect(
        harness.caller.spawnArchitectPlan({
          name: 'second-plan',
          initiativeId: initiative.id,
        }),
      ).rejects.toThrow(/already running/);
    });

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

      const initiative = await harness.createInitiative('Auth System');

      // Set up a plan agent that crashes immediately
      harness.setAgentScenario('stale-plan', { status: 'error', error: 'crashed' });

      await harness.caller.spawnArchitectPlan({
        name: 'stale-plan',
        initiativeId: initiative.id,
      });
      await harness.advanceTimers();

      // Should be crashed
      const agents = await harness.caller.listAgents();
      expect(agents.find(a => a.name === 'stale-plan')?.status).toBe('crashed');

      // New plan should succeed (stale one gets auto-dismissed)
      harness.setArchitectPlanComplete('new-plan', [
        { number: 1, name: 'Phase 1', description: 'First', dependencies: [] },
      ]);

      const agent = await harness.caller.spawnArchitectPlan({
        name: 'new-plan',
        initiativeId: initiative.id,
      });
      expect(agent.mode).toBe('plan');
    });

    it('should allow plan for different initiatives', async () => {
      vi.useFakeTimers();

      const init1 = await harness.createInitiative('Initiative 1');
      const init2 = await harness.createInitiative('Initiative 2');

      // Long-running agent on initiative 1
      harness.setAgentScenario('plan-1', { status: 'done', delay: 999999 });
      await harness.caller.spawnArchitectPlan({
        name: 'plan-1',
        initiativeId: init1.id,
      });

      // Plan on initiative 2 should succeed
      harness.setArchitectPlanComplete('plan-2', [
        { number: 1, name: 'Phase 1', description: 'First', dependencies: [] },
      ]);

      const agent = await harness.caller.spawnArchitectPlan({
        name: 'plan-2',
        initiativeId: init2.id,
      });
      expect(agent.mode).toBe('plan');
    });
  });

  describe('full workflow', () => {
    it('should complete discuss -> plan -> phases workflow', async () => {
      vi.useFakeTimers();

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

      // 2. Discuss phase
      harness.setArchitectDiscussComplete('discuss-agent', [
        { topic: 'Scope', decision: 'MVP only', reason: 'Time constraint' },
      ], 'Scope defined');

      await harness.caller.spawnArchitectDiscuss({
        name: 'discuss-agent',
        initiativeId: initiative.id,
      });
      await harness.advanceTimers();

      // 3. Plan phase
      harness.setArchitectPlanComplete('plan-agent', [
        { number: 1, name: 'Core', description: 'Core functionality', dependencies: [] },
        { number: 2, name: 'Polish', description: 'UI and UX', dependencies: [1] },
      ]);

      await harness.caller.spawnArchitectPlan({
        name: 'plan-agent',
        initiativeId: initiative.id,
        contextSummary: 'MVP scope defined',
      });
      await harness.advanceTimers();

      // 4. Persist phases
      await harness.createPhasesFromPlan(initiative.id, [
        { name: 'Core' },
        { name: 'Polish' },
      ]);

      // 5. Verify final state
      const phases = await harness.getPhases(initiative.id);
      expect(phases).toHaveLength(2);

      // Both agents should be idle
      const agents = await harness.caller.listAgents();
      expect(agents.filter(a => a.status === 'idle')).toHaveLength(2);
    });
  });
});
