/**
 * Test Fixtures for E2E Testing
 *
 * Provides fixture helpers that seed complete task hierarchies
 * for integration and E2E tests.
 */

import { nanoid } from 'nanoid';
import type { DrizzleDatabase } from '../db/index.js';
import {
  DrizzleInitiativeRepository,
  DrizzlePhaseRepository,
  DrizzleTaskRepository,
} from '../db/repositories/drizzle/index.js';
import { taskDependencies } from '../db/schema.js';

// =============================================================================
// Fixture Interfaces
// =============================================================================

/**
 * Task fixture definition.
 */
export interface TaskFixture {
  /** Unique identifier for this task (used for dependency references) */
  id: string;
  /** Task name */
  name: string;
  /** Task priority */
  priority?: 'low' | 'medium' | 'high';
  /** Task category */
  category?: 'execute' | 'research' | 'discuss' | 'plan' | 'detail' | 'refine' | 'verify' | 'merge' | 'review';
  /** Names of other tasks in same fixture this task depends on */
  dependsOn?: string[];
}

/**
 * Task group fixture definition (replaces Plan).
 * Tasks are grouped by parent task in the new model.
 */
export interface TaskGroupFixture {
  /** Group name (becomes a detail task) */
  name: string;
  /** Tasks in this group */
  tasks: TaskFixture[];
}

/**
 * Phase fixture definition.
 */
export interface PhaseFixture {
  /** Phase name */
  name: string;
  /** Task groups in this phase (each group becomes a parent detail task) */
  taskGroups: TaskGroupFixture[];
}

/**
 * Initiative fixture definition (top-level).
 */
export interface InitiativeFixture {
  /** Initiative name */
  name: string;
  /** Phases in this initiative */
  phases: PhaseFixture[];
}

/**
 * Result of seeding a fixture.
 * Maps names to IDs for all created entities.
 */
export interface SeededFixture {
  /** ID of the created initiative */
  initiativeId: string;
  /** Map of phase names to IDs */
  phases: Map<string, string>;
  /** Map of task group names to parent task IDs */
  taskGroups: Map<string, string>;
  /** Map of task names to IDs */
  tasks: Map<string, string>;
}

// =============================================================================
// Seed Function
// =============================================================================

/**
 * Seed a complete task hierarchy from a fixture definition.
 *
 * Creates initiative, phases, detail tasks (as parent), and child tasks.
 * Resolves task dependencies by name to actual task IDs.
 *
 * @param db - Drizzle database instance
 * @param fixture - The fixture definition to seed
 * @returns SeededFixture with all created entity IDs
 */
export async function seedFixture(
  db: DrizzleDatabase,
  fixture: InitiativeFixture
): Promise<SeededFixture> {
  // Create repositories
  const initiativeRepo = new DrizzleInitiativeRepository(db);
  const phaseRepo = new DrizzlePhaseRepository(db);
  const taskRepo = new DrizzleTaskRepository(db);

  // Result maps
  const phasesMap = new Map<string, string>();
  const taskGroupsMap = new Map<string, string>();
  const tasksMap = new Map<string, string>();

  // Collect all task dependencies to resolve after creation
  const pendingDependencies: Array<{ taskId: string; dependsOnNames: string[] }> = [];

  // Create initiative
  const initiative = await initiativeRepo.create({
    name: fixture.name,
    status: 'active',
  });

  // Create phases
  for (const phaseFixture of fixture.phases) {
    const phase = await phaseRepo.create({
      initiativeId: initiative.id,
      name: phaseFixture.name,
      status: 'pending',
    });
    phasesMap.set(phaseFixture.name, phase.id);

    // Create task groups as parent detail tasks
    let taskOrder = 0;
    for (const groupFixture of phaseFixture.taskGroups) {
      // Create parent detail task
      const parentTask = await taskRepo.create({
        phaseId: phase.id,
        initiativeId: initiative.id,
        name: groupFixture.name,
        description: `Test task group: ${groupFixture.name}`,
        category: 'detail',
        type: 'auto',
        priority: 'medium',
        status: 'completed', // Detail tasks are completed once child tasks are created
        order: taskOrder++,
      });
      taskGroupsMap.set(groupFixture.name, parentTask.id);

      // Create child tasks linked to parent
      let childOrder = 0;
      for (const taskFixture of groupFixture.tasks) {
        const task = await taskRepo.create({
          parentTaskId: parentTask.id,
          phaseId: phase.id,
          initiativeId: initiative.id,
          name: taskFixture.name,
          description: `Test task: ${taskFixture.name}`,
          category: taskFixture.category ?? 'execute',
          type: 'auto',
          priority: taskFixture.priority ?? 'medium',
          status: 'pending',
          order: childOrder++,
        });
        tasksMap.set(taskFixture.id, task.id);

        // Collect dependencies to resolve later
        if (taskFixture.dependsOn && taskFixture.dependsOn.length > 0) {
          pendingDependencies.push({
            taskId: task.id,
            dependsOnNames: taskFixture.dependsOn,
          });
        }
      }
    }
  }

  // Resolve and insert task dependencies
  for (const { taskId, dependsOnNames } of pendingDependencies) {
    for (const depName of dependsOnNames) {
      const dependsOnTaskId = tasksMap.get(depName);
      if (!dependsOnTaskId) {
        throw new Error(
          `Dependency resolution failed: task "${depName}" not found in fixture`
        );
      }

      // Insert into task_dependencies table
      await db.insert(taskDependencies).values({
        id: nanoid(),
        taskId,
        dependsOnTaskId,
        createdAt: new Date(),
      });
    }
  }

  return {
    initiativeId: initiative.id,
    phases: phasesMap,
    taskGroups: taskGroupsMap,
    tasks: tasksMap,
  };
}

// =============================================================================
// Convenience Fixtures
// =============================================================================

/**
 * Simple fixture: 1 initiative -> 1 phase -> 1 task group -> 3 tasks.
 *
 * Task dependency structure:
 * - Task A: no dependencies
 * - Task B: depends on Task A
 * - Task C: depends on Task A
 */
export const SIMPLE_FIXTURE: InitiativeFixture = {
  name: 'Simple Test Initiative',
  phases: [
    {
      name: 'Phase 1',
      taskGroups: [
        {
          name: 'Task Group 1',
          tasks: [
            { id: 'Task A', name: 'Task A', priority: 'high' },
            { id: 'Task B', name: 'Task B', priority: 'medium', dependsOn: ['Task A'] },
            { id: 'Task C', name: 'Task C', priority: 'medium', dependsOn: ['Task A'] },
          ],
        },
      ],
    },
  ],
};

/**
 * Parallel fixture: 1 initiative -> 1 phase -> 2 task groups (each with 2 independent tasks).
 *
 * Task structure:
 * - Group A: Task X, Task Y (independent)
 * - Group B: Task P, Task Q (independent)
 */
export const PARALLEL_FIXTURE: InitiativeFixture = {
  name: 'Parallel Test Initiative',
  phases: [
    {
      name: 'Parallel Phase',
      taskGroups: [
        {
          name: 'Group A',
          tasks: [
            { id: 'Task X', name: 'Task X', priority: 'high' },
            { id: 'Task Y', name: 'Task Y', priority: 'medium' },
          ],
        },
        {
          name: 'Group B',
          tasks: [
            { id: 'Task P', name: 'Task P', priority: 'high' },
            { id: 'Task Q', name: 'Task Q', priority: 'low' },
          ],
        },
      ],
    },
  ],
};

/**
 * Complex fixture: 1 initiative -> 2 phases -> 4 task groups with cross-group dependencies.
 *
 * Structure:
 * - Phase 1: Group 1 (Task 1A, 1B), Group 2 (Task 2A depends on 1A)
 * - Phase 2: Group 3 (Task 3A depends on 1B), Group 4 (Task 4A depends on 2A and 3A)
 */
export const COMPLEX_FIXTURE: InitiativeFixture = {
  name: 'Complex Test Initiative',
  phases: [
    {
      name: 'Phase 1',
      taskGroups: [
        {
          name: 'Group 1',
          tasks: [
            { id: 'Task 1A', name: 'Task 1A', priority: 'high' },
            { id: 'Task 1B', name: 'Task 1B', priority: 'medium' },
          ],
        },
        {
          name: 'Group 2',
          tasks: [
            { id: 'Task 2A', name: 'Task 2A', priority: 'high', dependsOn: ['Task 1A'] },
          ],
        },
      ],
    },
    {
      name: 'Phase 2',
      taskGroups: [
        {
          name: 'Group 3',
          tasks: [
            { id: 'Task 3A', name: 'Task 3A', priority: 'high', dependsOn: ['Task 1B'] },
          ],
        },
        {
          name: 'Group 4',
          tasks: [
            {
              id: 'Task 4A',
              name: 'Task 4A',
              priority: 'high',
              dependsOn: ['Task 2A', 'Task 3A'],
            },
          ],
        },
      ],
    },
  ],
};
