/**
 * Cascade Delete Tests
 *
 * Tests that cascade deletes work correctly through the repository layer.
 * Verifies the SQLite foreign key cascade behavior configured in schema.ts.
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { DrizzleInitiativeRepository } from './initiative.js';
import { DrizzlePhaseRepository } from './phase.js';
import { DrizzleTaskRepository } from './task.js';
import { createTestDatabase } from './test-helpers.js';
import type { DrizzleDatabase } from '../../index.js';

describe('Cascade Deletes', () => {
  let db: DrizzleDatabase;
  let initiativeRepo: DrizzleInitiativeRepository;
  let phaseRepo: DrizzlePhaseRepository;
  let taskRepo: DrizzleTaskRepository;

  beforeEach(() => {
    db = createTestDatabase();
    initiativeRepo = new DrizzleInitiativeRepository(db);
    phaseRepo = new DrizzlePhaseRepository(db);
    taskRepo = new DrizzleTaskRepository(db);
  });

  /**
   * Helper to create a full hierarchy for testing.
   * Uses parent tasks (detail category) to group child tasks.
   */
  async function createFullHierarchy() {
    const initiative = await initiativeRepo.create({
      name: 'Test Initiative',
    });

    const phase1 = await phaseRepo.create({
      initiativeId: initiative.id,
      name: 'Phase 1',
    });

    const phase2 = await phaseRepo.create({
      initiativeId: initiative.id,
      name: 'Phase 2',
    });

    // Create parent (detail) tasks that group child tasks
    const parentTask1 = await taskRepo.create({
      phaseId: phase1.id,
      initiativeId: initiative.id,
      name: 'Parent Task 1-1',
      category: 'detail',
      order: 1,
    });

    const parentTask2 = await taskRepo.create({
      phaseId: phase1.id,
      initiativeId: initiative.id,
      name: 'Parent Task 1-2',
      category: 'detail',
      order: 2,
    });

    const parentTask3 = await taskRepo.create({
      phaseId: phase2.id,
      initiativeId: initiative.id,
      name: 'Parent Task 2-1',
      category: 'detail',
      order: 1,
    });

    // Create child tasks under parent tasks
    const task1 = await taskRepo.create({
      parentTaskId: parentTask1.id,
      phaseId: phase1.id,
      initiativeId: initiative.id,
      name: 'Task 1-1-1',
      order: 1,
    });

    const task2 = await taskRepo.create({
      parentTaskId: parentTask1.id,
      phaseId: phase1.id,
      initiativeId: initiative.id,
      name: 'Task 1-1-2',
      order: 2,
    });

    const task3 = await taskRepo.create({
      parentTaskId: parentTask2.id,
      phaseId: phase1.id,
      initiativeId: initiative.id,
      name: 'Task 1-2-1',
      order: 1,
    });

    const task4 = await taskRepo.create({
      parentTaskId: parentTask3.id,
      phaseId: phase2.id,
      initiativeId: initiative.id,
      name: 'Task 2-1-1',
      order: 1,
    });

    return {
      initiative,
      phases: { phase1, phase2 },
      parentTasks: { parentTask1, parentTask2, parentTask3 },
      tasks: { task1, task2, task3, task4 },
    };
  }

  describe('delete initiative', () => {
    it('should cascade delete all phases and tasks', async () => {
      const { initiative, phases, parentTasks, tasks } = await createFullHierarchy();

      // Verify everything exists
      expect(await initiativeRepo.findById(initiative.id)).not.toBeNull();
      expect(await phaseRepo.findById(phases.phase1.id)).not.toBeNull();
      expect(await phaseRepo.findById(phases.phase2.id)).not.toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask1.id)).not.toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask2.id)).not.toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask3.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task1.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task2.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task3.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task4.id)).not.toBeNull();

      // Delete initiative
      await initiativeRepo.delete(initiative.id);

      // Verify everything is gone
      expect(await initiativeRepo.findById(initiative.id)).toBeNull();
      expect(await phaseRepo.findById(phases.phase1.id)).toBeNull();
      expect(await phaseRepo.findById(phases.phase2.id)).toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask1.id)).toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask2.id)).toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask3.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task1.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task2.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task3.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task4.id)).toBeNull();
    });
  });

  describe('delete phase', () => {
    it('should cascade delete tasks under that phase only', async () => {
      const { initiative, phases, parentTasks, tasks } = await createFullHierarchy();

      // Delete phase 1
      await phaseRepo.delete(phases.phase1.id);

      // Initiative still exists
      expect(await initiativeRepo.findById(initiative.id)).not.toBeNull();

      // Phase 1 and its tasks are gone
      expect(await phaseRepo.findById(phases.phase1.id)).toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask1.id)).toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask2.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task1.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task2.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task3.id)).toBeNull();

      // Phase 2 and its tasks still exist
      expect(await phaseRepo.findById(phases.phase2.id)).not.toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask3.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task4.id)).not.toBeNull();
    });
  });

  describe('delete parent task', () => {
    it('should cascade delete child tasks under that parent only', async () => {
      const { phases, parentTasks, tasks } = await createFullHierarchy();

      // Delete parent task 1
      await taskRepo.delete(parentTasks.parentTask1.id);

      // Phase still exists
      expect(await phaseRepo.findById(phases.phase1.id)).not.toBeNull();

      // Parent task 1 and its children are gone
      expect(await taskRepo.findById(parentTasks.parentTask1.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task1.id)).toBeNull();
      expect(await taskRepo.findById(tasks.task2.id)).toBeNull();

      // Other parent tasks and their children still exist
      expect(await taskRepo.findById(parentTasks.parentTask2.id)).not.toBeNull();
      expect(await taskRepo.findById(parentTasks.parentTask3.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task3.id)).not.toBeNull();
      expect(await taskRepo.findById(tasks.task4.id)).not.toBeNull();
    });
  });
});
