import process from 'node:process'
import { Command } from 'commander'
import { createParser } from 'eventsource-parser'
import { logger } from '../../core/logger.ts'
import { DAEMON_BASE_URL } from '../../core/paths.ts'

type TailOptions = {
  agent?: string
  kind?: string[]
  format: string
}

// biome-ignore lint/suspicious/noExplicitAny: third-party packet shape
type Packet = any

export const tailCommand = new Command('tail')
  .description('Live-tail actions across all wired agents.')
  .option('--agent <id>', 'Filter to one agent.')
  .option('--kind <kinds...>', 'Filter by action kind (model_call, mcp_call, ...).')
  .option('--format <fmt>', "'compact' | 'json'", 'compact')
  .action(async (options: TailOptions) => {
    let res: Response
    try {
      res = await fetch(`${DAEMON_BASE_URL}/api/feed`, {
        headers: { accept: 'text/event-stream' },
      })
    } catch {
      logger.print('Daemon not reachable. Start it with `openthomas wire` or `openthomas daemon`.')
      process.exitCode = 1
      return
    }
    if (!res.ok || !res.body) {
      logger.print(`Daemon error: HTTP ${res.status}`)
      process.exitCode = 1
      return
    }

    const parser = createParser({
      onEvent: (ev) => {
        if (ev.event !== 'action') return
        let packet: Packet
        try {
          packet = JSON.parse(ev.data)
        } catch {
          return
        }
        if (options.agent && packet.sourceAgent !== options.agent) return
        if (
          options.kind &&
          options.kind.length > 0 &&
          !options.kind.includes(packet.payload?.kind)
        ) {
          return
        }
        if (options.format === 'json') {
          process.stdout.write(`${JSON.stringify(packet)}\n`)
        } else {
          process.stdout.write(`${formatLine(packet)}\n`)
        }
      },
    })

    const decoder = new TextDecoder()
    for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {
      parser.feed(decoder.decode(chunk, { stream: true }))
    }
  })

function formatLine(packet: Packet): string {
  const t = new Date(packet.ts)
  const time = `${pad(t.getHours())}:${pad(t.getMinutes())}:${pad(t.getSeconds())}`
  const p = packet.payload
  const agent = String(packet.sourceAgent).padEnd(12)
  const risk = riskPrefix(packet.risk)

  if (p?.kind === 'model_call') {
    const usd = packet.cost?.usd ?? 0
    const tIn = packet.cost?.tokensIn ?? 0
    const tOut = packet.cost?.tokensOut ?? 0
    const status = p.status ?? '?'
    // When model is unknown (errors, non-chat endpoints), show the path so
    // it's obvious what the agent actually hit.
    const what = p.model && p.model.length > 0 ? p.model : urlPath(p.endpoint) || '?'
    const errSuffix =
      p.error
        ? `  err: ${String(p.error).replace(/\s+/g, ' ').slice(0, 120)}`
        : ''
    return `${risk}${time}  ${agent}  model_call  ${what}  ${status}  ${tIn}/${tOut}  ${formatCost(usd)}${errSuffix}`
  }
  if (p?.kind === 'mcp_call') {
    const dir = p.direction === 'request' ? '→' : p.direction === 'response' ? '←' : '·'
    return `${risk}${time}  ${agent}  mcp_call    ${dir} ${p.server}  ${p.method ?? '(response)'}`
  }
  return `${risk}${time}  ${agent}  ${p?.kind ?? '?'}`
}

function riskPrefix(risk: Array<{ severity: string }> | undefined): string {
  if (!risk || risk.length === 0) return '  '
  if (risk.some((r) => r.severity === 'high')) return '⚠ '
  if (risk.some((r) => r.severity === 'warn')) return '! '
  return 'ⓘ '
}

function pad(n: number): string {
  return String(n).padStart(2, '0')
}

function formatCost(usd: number): string {
  if (usd === 0) return '$0'
  if (usd < 0.01) return `$${usd.toFixed(4)}`
  return `$${usd.toFixed(2)}`
}

function urlPath(endpoint: unknown): string {
  if (typeof endpoint !== 'string' || !endpoint) return ''
  try {
    return new URL(endpoint).pathname
  } catch {
    return endpoint
  }
}
