import process from 'node:process'
import { Command } from 'commander'
import type { AgentId } from '../../core/agent.ts'
import { logger } from '../../core/logger.ts'
import { paths } from '../../core/paths.ts'
import { ensureService, probeService, waitForHealth } from '../service/index.ts'
import { formatDetectionSummary } from '../tui/format.ts'
import { execCapture } from '../util/exec.ts'
import { detectPlan, runWire, type WireAgentResult } from '../wire/orchestrate.ts'
import type { ApplyResult } from '../detect/types.ts'

type WireOptions = {
  dryRun: boolean
  yes: boolean
  includeProjects: boolean
  noApply: boolean
}

export const wireCommand = new Command('wire')
  .description('Detect agents, wire them, and start the daemon.')
  .argument(
    '[agents...]',
    'Wire just these agents (e.g. `claude-code`, `codex`). Additive — agents not listed stay as they are. Defaults to all detected.',
  )
  .option('--dry-run', 'Show what would change; do not write anything.', false)
  .option('-y, --yes', 'Skip confirmation prompts.', false)
  .option(
    '--include-projects',
    'Also wire project-level configs (default: user-global only).',
    false,
  )
  .option(
    '--no-apply',
    "Don't restart / paste-instruct running agents (write config only).",
  )
  .action(async (agents: string[], options: WireOptions) => {
    const only = agents.length > 0 ? (agents as AgentId[]) : undefined
    const { detections } = await detectPlan(only)

    logger.print(formatDetectionSummary(detections, { dryRun: options.dryRun }))

    if (detections.length === 0) {
      process.exitCode = 1
      return
    }
    if (options.dryRun) return

    const { results } = await runWire({ only, noApply: options.noApply })

    for (const r of results) {
      await renderWireResult(r, options.noApply)
    }

    logger.print('')

    // Install + start the OpenThomas daemon service.
    const beforeState = await probeService()
    if (beforeState.state === 'unsupported') {
      logger.print(`⚠ service install not supported on ${beforeState.platform}`)
      logger.print('  Start the daemon manually: `openthomas daemon`')
      return
    }

    try {
      await ensureService()
    } catch (err) {
      logger.print(`✗ service install failed: ${(err as Error).message}`)
      logger.print('  Start the daemon manually: `openthomas daemon`')
      process.exitCode = 1
      return
    }

    const healthy = await waitForHealth(8000)
    if (healthy) {
      logger.print('✓ daemon running')
      logger.print(`  UI:        http://localhost:9877`)
      logger.print(`  Logs:      ${paths.logs.daemon}`)
      logger.print('')
      logger.print('Next:')
      logger.print(`  openthomas thomas    →  your T (outcome / AI cost)`)
      logger.print(`  thomas           →  open the dashboard`)
      logger.print('')
      logger.print('Spec: https://openthomas.com/thomas · v1.1')
    } else {
      logger.print('⚠ daemon installed but /health did not respond within 8s')
      logger.print(`  Check ${paths.logs.daemonErr} for errors`)
      process.exitCode = 1
    }
  })

async function renderWireResult(r: WireAgentResult, noApply: boolean): Promise<void> {
  if (!r.ok) {
    logger.print(`  ✗ ${r.agent}  ${r.error ?? 'unknown error'}`)
    process.exitCode = 1
    return
  }
  const captured = r.secretsCount
  logger.print(
    `  ✓ ${r.agent}  wired` +
      (captured > 0 ? ` (${captured} credential${captured === 1 ? '' : 's'} captured)` : ''),
  )

  if (r.manualInstructions) {
    logger.print('     ⓘ next step (manual):')
    for (const line of r.manualInstructions.split('\n')) logger.print(`       ${line}`)
  }

  if (r.apply) {
    await renderApply(r.agent, r.apply, noApply)
  }
}

async function renderApply(agent: string, apply: ApplyResult, skipApply: boolean): Promise<void> {
  switch (apply.kind) {
    case 'applied':
      logger.print(`     ✓ ${agent} applied live${apply.detail ? ` — ${apply.detail}` : ''}`)
      return
    case 'next-launch':
      logger.print(`     ⓘ ${apply.note ?? `${agent} applies on next launch`}`)
      return
    case 'restart': {
      if (skipApply) {
        logger.print(`     ⓘ restart skipped (--no-apply); run manually:`)
        logger.print(`        ${apply.cmd.join(' ')}`)
        return
      }
      logger.print(`     ⟲ restarting ${agent}…`)
      const cmd = apply.cmd[0]
      if (!cmd) {
        logger.print(`     ✗ restart command empty; doing nothing`)
        return
      }
      const res = await execCapture(cmd, apply.cmd.slice(1))
      if (res.exit === 0) {
        logger.print(`     ✓ ${agent} restarted`)
      } else {
        logger.print(`     ✗ restart failed (exit ${res.exit}): ${res.stderr.trim().slice(0, 200)}`)
        logger.print(`        Manual: ${apply.cmd.join(' ')}`)
      }
      return
    }
    case 'user-action': {
      logger.print('')
      for (const line of apply.instruction.split('\n')) {
        logger.print(`     ${line}`)
      }
      logger.print('')
      return
    }
  }
}
