/**
 * Worker entrypoint — Child-process main
 * Reads agent.start, dispatches to role, returns worker.result.
 *
 * @module packages/workers/src/main
 */

import { WorkerRuntime } from './WorkerRuntime.js'
import { ExecutorRole } from './roles/ExecutorRole.js'
import { ReviewerRole } from './roles/ReviewerRole.js'
import { DebuggerRole } from './roles/DebuggerRole.js'
import { CompactorRole } from './roles/CompactorRole.js'
import { ExperienceMinerRole } from './roles/ExperienceMinerRole.js'

const PROTOCOL_VERSION = 1
const WORKER_VERSION = '1.0.0-alpha'

// Route task type to role (DD §8.3 mapping)
const TASK_TYPE_ROLE: Record<string, new (rt: WorkerRuntime) => { run(spec: any): Promise<any> }> = {
  execute: ExecutorRole,
  review: ReviewerRole,
  debug: DebuggerRole,
  compact: CompactorRole,
  mine_experience: ExperienceMinerRole,
  docs: ExecutorRole  // docs tasks handled by Executor
}

async function main(): Promise<void> {
  const agent_id = process.env.AIRCODING_AGENT_ID || 'unknown'
  const session_id = process.env.AIRCODING_SESSION_ID || 'unknown'

  // Create runtime with stdout as IPC channel
  const runtime = new WorkerRuntime({ agent_id, session_id }, (line: string) => {
    process.stdout.write(line + '\n')
  })

  // Parse stdin as NDJSON
  let buffer = ''
  process.stdin.setEncoding('utf-8')
  process.stdin.on('data', (chunk: string) => {
    buffer += chunk
    const lines = buffer.split('\n')
    buffer = lines.pop() || ''

    for (const line of lines) {
      if (!line.trim()) continue
      try {
        const msg = JSON.parse(line)
        handle_message(msg, runtime)
      } catch {
        // Skip invalid JSON
      }
    }
  })

  // Send ready handshake
  runtime.send_ready(PROTOCOL_VERSION, WORKER_VERSION)

  // Start heartbeat
  const heartbeat_interval = setInterval(() => {
    runtime.heartbeat()
  }, 5000)

  // Handle exit
  process.on('SIGTERM', () => {
    clearInterval(heartbeat_interval)
    process.exit(0)
  })

  process.on('SIGINT', () => {
    clearInterval(heartbeat_interval)
    process.exit(0)
  })
}

async function handle_message(msg: { id: string; type: string; payload: Record<string, unknown> }, runtime: WorkerRuntime): Promise<void> {
  switch (msg.type) {
    case 'agent.start': {
      const task_type = (msg.payload.task_type as string) || 'execute'
      const task_spec = msg.payload.task_spec as Record<string, unknown> || {}
      const RoleClass = TASK_TYPE_ROLE[task_type]

      if (!RoleClass) {
        runtime.send_error(`Unknown task_type: ${task_type}`)
        process.exit(2) // Protocol error
        return
      }

      try {
        const role = new RoleClass(runtime)
        const result = await role.run(task_spec)
        await runtime.report_result(result)
        process.exit(0)
      } catch (error) {
        runtime.send_error(error instanceof Error ? error.message : String(error))
        process.exit(1)
      }
      break
    }

    case 'tool.result':
    case 'agent.cancel':
    case 'agent.ping':
      runtime.handle_message(msg.type, msg.payload)
      break

    default:
      runtime.send_error(`Unknown message type: ${msg.type}`)
  }
}

main().catch((error) => {
  console.error('Worker fatal error:', error)
  process.exit(1)
})
