/**
 * WavePlanner - Plans execution waves for tasks
 *
 * Implements DD §7.3.
 *
 * @module packages/runtime/src/scheduler/WavePlanner
 */

import { TaskGraph, type TaskNode, type DependencyType } from './TaskGraph.js'

export interface WavePlan {
  wave_id: number
  tasks: Array<{
    task_id: string
    workspace: string
    model?: string
    agent_type: string
  }>
  can_parallelize: boolean
  resource_cap: number
}

export interface WriteArea {
  area: string
  tasks: string[]
}

export class WavePlanner {
  private resource_cap: number

  constructor(resource_cap: number = 4) {
    this.resource_cap = resource_cap
  }

  /**
   * Plan next execution wave from runnable tasks.
   */
  plan(graph: TaskGraph): WavePlan[] {
    const runnable = graph.get_runnable_tasks()
    if (runnable.length === 0) return []

    // Group by write areas to detect conflicts
    const write_areas = this.group_by_write_area(runnable)

    // Assign workspaces
    const assignments = this.assign_workspaces(write_areas, runnable)

    // Detect conflicts — same uncertain area → serialize
    const can_parallelize = this.can_parallelize(write_areas)

    // Cap resources
    const capped = assignments.slice(0, this.resource_cap)

    return [{
      wave_id: Date.now(),
      tasks: capped,
      can_parallelize,
      resource_cap: this.resource_cap
    }]
  }

  /**
   * Group tasks by their write areas to detect potential conflicts.
   */
  group_by_write_area(tasks: TaskNode[]): WriteArea[] {
    // Extract write areas from task metadata (stub)
    const areas: Map<string, string[]> = new Map()

    for (const task of tasks) {
      const area = 'default' // Would be extracted from task spec
      if (!areas.has(area)) areas.set(area, [])
      areas.get(area)!.push(task.id)
    }

    return Array.from(areas.entries()).map(([area, tasks]) => ({ area, tasks }))
  }

  /**
   * Assign workspace to each task.
   * Different write areas → concurrent.
   * Same uncertain area → serialize.
   */
  assign_workspaces(areas: WriteArea[], tasks: TaskNode[]): Array<{ task_id: string; workspace: string; agent_type: string }> {
    return tasks.map((task, index) => ({
      task_id: task.id,
      workspace: `ws_${index}`,
      agent_type: 'executor' // Would be determined by task type
    }))
  }

  /**
   * Check if tasks can run in parallel （write areas don't conflict).
   */
  can_parallelize(areas: WriteArea[]): boolean {
    // Different write areas → concurrent
    return areas.length > 1
  }

  /**
   * Assign model for a task based on requirements.
   */
  assign_model(task: TaskNode): string {
    // Would consult capability matrix
    return 'claude-sonnet-4-6'
  }
}
