import { formatDurationMs } from '@overdeck/deck-ui'
import type { FactoryAgentAttemptView, FactoryDecisionView, FactoryRunView } from '../../lib/factory-types'

const TOKEN_FORMAT = new Intl.NumberFormat('en-US')
const SPEND_FORMAT = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  minimumFractionDigits: 4,
  maximumFractionDigits: 4,
})

export function repoDisplayName(run: Pick<FactoryRunView, 'repo' | 'repoName'>): string {
  const stored = run.repoName?.trim()
  if (stored) return stored

  const repo = run.repo?.trim()
  if (!repo) return 'unassigned'

  const segments = repo.split('/').filter(Boolean)
  const worktreesIdx = segments.lastIndexOf('.worktrees')
  if (worktreesIdx > 0) {
    return segments[worktreesIdx - 1]!
  }

  return segments.at(-1) ?? repo
}

export function runDisplayName(run: FactoryRunView): string {
  const runSlug = run.runSlug?.trim()
  if (runSlug) return runSlug
  const request = run.request?.trim()
  if (request) return request
  const adwName = run.adwName?.trim()
  if (adwName) return adwName
  return run.adwId
}

export function runSubtitle(run: FactoryRunView): string | null {
  const title = runDisplayName(run)
  const request = run.request?.trim()
  const adwName = run.adwName?.trim()
  const parts: string[] = []
  if (request && request !== title) parts.push(request)
  if (adwName && adwName !== title && adwName !== request) parts.push(adwName)
  return parts.length > 0 ? parts.join(' · ') : null
}

export function isFactoryRunning(status: string | null | undefined): boolean {
  return status?.trim().toLowerCase() === 'running'
}

export function factoryStopCommand(adwId: string): string {
  return `factory stop ${adwId}`
}

export function pendingDecisions(run: FactoryRunView): FactoryDecisionView[] {
  return (run.decisions ?? []).filter((decision) => decision.status === 'pending')
}

export function decisionAnswerSummary(decision: FactoryDecisionView): string {
  if (decision.answerValue !== null && decision.answerValue !== '') {
    const option = decision.options.find((entry) => entry.value === decision.answerValue)
    return option?.label ?? decision.answerValue
  }
  if (decision.answerText !== null && decision.answerText !== '') return decision.answerText
  return '—'
}

function shellQuote(value: string): string {
  return `'${value.replace(/'/g, "'\\''")}'`
}

/** Copyable command to start the same request again — the change-your-mind path
 * once an answer has already been consumed by the run. */
export function factoryRerunCommand(run: FactoryRunView): string | null {
  const request = run.request?.trim()
  if (!request) return null
  const adwName = run.adwName?.trim()
  if (!adwName) return null
  const segments = adwName.split('+').map((segment) => segment.trim().replace(/^adw_/, '').replace(/\.py$/, ''))
  if (segments.some((segment) => !segment)) return null
  const token = segments.join('_')
  if (!/^[A-Za-z0-9_-]+$/.test(token)) return null
  const repoFlag = run.repo?.trim() ? `--repo ${shellQuote(run.repo.trim())} ` : ''
  return `factory ${repoFlag}${token} ${shellQuote(request)}`
}

export function formatTokenCount(value: number | null | undefined): string {
  if (value === null || value === undefined || !Number.isFinite(value)) return '—'
  return TOKEN_FORMAT.format(value)
}

export function formatEstimatedSpend(value: number | null | undefined): string {
  if (value === null || value === undefined || !Number.isFinite(value)) return '—'
  return `est. ${SPEND_FORMAT.format(value)}`
}

export function parseTimestampMs(value: string | null | undefined): number | null {
  if (!value) return null
  const parsed = Date.parse(value)
  return Number.isFinite(parsed) ? parsed : null
}

export function formatAbsoluteTimestamp(value: string | null | undefined): string {
  const epoch = parseTimestampMs(value)
  return epoch === null ? '—' : new Date(epoch).toISOString()
}

export function formatElapsed(startedAt: string | null | undefined, endedAt: string | null | undefined): string {
  const startedMs = parseTimestampMs(startedAt)
  const endedMs = parseTimestampMs(endedAt)
  if (startedMs === null) return '—'
  const terminalMs = endedMs ?? Date.now()
  return terminalMs >= startedMs ? formatDurationMs(terminalMs - startedMs) : '—'
}

export function hostsForAttempts(attempts: FactoryAgentAttemptView[], phaseId?: string): string {
  const hosts = new Set(
    attempts
      .filter((attempt) => phaseId === undefined || attempt.phaseId === phaseId)
      .map((attempt) => attempt.host?.trim())
      .filter((host): host is string => Boolean(host)),
  )
  return hosts.size > 0 ? [...hosts].join(', ') : '—'
}

export function sortFactoryRuns(runs: FactoryRunView[]): FactoryRunView[] {
  return [...runs].sort((left, right) => {
    const leftRunning = isFactoryRunning(left.status)
    const rightRunning = isFactoryRunning(right.status)
    if (leftRunning !== rightRunning) return leftRunning ? -1 : 1

    const leftStarted = parseTimestampMs(left.startedAt) ?? -Infinity
    const rightStarted = parseTimestampMs(right.startedAt) ?? -Infinity
    if (leftStarted !== rightStarted) return rightStarted - leftStarted

    return right.adwId.localeCompare(left.adwId)
  })
}

export function displayStatus(status: string | null | undefined): string {
  const trimmed = status?.trim()
  return trimmed || 'unknown'
}

export function displayText(value: string | null | undefined, fallback = '—'): string {
  const trimmed = value?.trim()
  return trimmed || fallback
}

export function displayEventType(event: { type: string | null; name: string | null }): string {
  return displayText(event.name, displayText(event.type, 'event'))
}
