/**
 * TaskDependencyRepository - CRUD + list_for_task, list_dependents for task_dependencies table (§8)
 *
 * Implements Repository<TaskDependencyRecord, TaskDependencyInsert, TaskDependencyUpdate>
 * per contracts §6.
 *
 * @module packages/runtime/src/storage/repositories/TaskDependencyRepository
 */

import type {
  Repository,
  TransactionHandle,
  SessionID,
  TaskID,
  UUID,
  ISOTimeString,
} from '@aircoding/contracts'

import { DatabaseHandle } from '../MigrationRunner.js'
import { assertEnumValues } from '../assertEnum.js'

// =============================================================================
// Types - per db-schema §8
// =============================================================================

export type TaskDependencyType = 'hard' | 'soft' | 'conflict' | 'serialization'

export interface TaskDependencyRecord {
  id: UUID
  session_id: SessionID
  task_id: TaskID
  depends_on_task_id: TaskID
  dependency_type: TaskDependencyType
  reason?: string
  created_at: ISOTimeString
}

export type TaskDependencyInsert = Omit<TaskDependencyRecord, 'id'> & {
  id?: UUID
}

export type TaskDependencyUpdate = Partial<Omit<TaskDependencyRecord, 'id' | 'session_id' | 'task_id' | 'depends_on_task_id' | 'created_at'>>

// =============================================================================
// TaskDependencyRepository
// =============================================================================

export class TaskDependencyRepository implements Repository<TaskDependencyRecord, TaskDependencyInsert, TaskDependencyUpdate> {
  private db: DatabaseHandle

  constructor(db: DatabaseHandle) {
    this.db = db
  }

  /**
   * Get a task dependency by ID.
   */
  async get(id: UUID, tx?: TransactionHandle): Promise<TaskDependencyRecord | undefined> {
    const stmt = (tx?.db ?? this.db).prepare('SELECT * FROM task_dependencies WHERE id = ?')
    const row = stmt.get(id) as TaskDependencyRecord | undefined
    return row
  }

  /**
   * Insert a new task dependency.
   */
  async insert(record: TaskDependencyInsert, tx?: TransactionHandle): Promise<void> {
    // Validate enum columns
    assertEnumValues('task_dependencies', {
      dependency_type: record.dependency_type,
    })

    const stmt = (tx?.db ?? this.db).prepare(`
      INSERT INTO task_dependencies (
        id, session_id, task_id, depends_on_task_id,
        dependency_type, reason, created_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?)
    `)

    stmt.run(
      record.id,
      record.session_id,
      record.task_id,
      record.depends_on_task_id,
      record.dependency_type,
      record.reason ?? null,
      record.created_at,
    )
  }

  /**
   * Update an existing task dependency.
   */
  async update(id: UUID, patch: TaskDependencyUpdate, tx?: TransactionHandle): Promise<void> {
    // Validate enum columns if present
    if (patch.dependency_type !== undefined) {
      assertEnumValues('task_dependencies', { dependency_type: patch.dependency_type })
    }

    const fields: string[] = []
    const values: unknown[] = []

    if (patch.dependency_type !== undefined) {
      fields.push('dependency_type = ?')
      values.push(patch.dependency_type)
    }
    if (patch.reason !== undefined) {
      fields.push('reason = ?')
      values.push(patch.reason)
    }

    if (fields.length === 0) {
      return // Nothing to update
    }

    values.push(id)
    const stmt = (tx?.db ?? this.db).prepare(`UPDATE task_dependencies SET ${fields.join(', ')} WHERE id = ?`)
    stmt.run(...values)
  }

  // =============================================================================
  // Extra methods
  // =============================================================================

  /**
   * List all dependencies for a task (what this task depends on).
   */
  async list_for_task(task_id: TaskID): Promise<TaskDependencyRecord[]> {
    const stmt = this.db.prepare(
      'SELECT * FROM task_dependencies WHERE task_id = ? ORDER BY created_at ASC',
    )
    return stmt.all(task_id) as TaskDependencyRecord[]
  }

  /**
   * List all dependents of a task (tasks that depend on this one).
   */
  async list_dependents(depends_on_task_id: TaskID): Promise<TaskDependencyRecord[]> {
    const stmt = this.db.prepare(
      'SELECT * FROM task_dependencies WHERE depends_on_task_id = ? ORDER BY created_at ASC',
    )
    return stmt.all(depends_on_task_id) as TaskDependencyRecord[]
  }
}