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

const stamp = (value: string | null) => value && Number.isFinite(Date.parse(value)) ? Date.parse(value) : Number.MAX_SAFE_INTEGER
export type TranscriptStep =
 | { type: 'phase'; id: string; phase: FactoryPhaseView; attempts: FactoryAgentAttemptView[]; diffs: FactoryPhaseDiffView[]; summary: string; isStreaming: boolean }
 | { type: 'attempt'; id: string; attempt: FactoryAgentAttemptView; phase: FactoryPhaseView; diffs: FactoryPhaseDiffView[]; summary: string; isStreaming: boolean }

export function factoryAgentHref(run: FactoryRunView, step: TranscriptStep): string | undefined {
 if (step.type !== 'attempt' || !step.phase.taskId) return undefined
 return `/factory/${encodeURIComponent(run.adwId)}/agents/${encodeURIComponent(step.phase.taskId)}`
}

function fragments(values: Array<string | null | undefined>): string { return values.filter((value): value is string => Boolean(value)).join(' · ') }
function diffSummary(diffs: FactoryPhaseDiffView[]): string[] { const files = diffs.reduce((n, diff) => n + diff.files.length, 0); const additions = diffs.reduce((n, diff) => n + (diff.insertions ?? 0), 0); const deletions = diffs.reduce((n, diff) => n + (diff.deletions ?? 0), 0); return [files ? `${files} files` : '', additions ? `+${additions}` : '', deletions ? `−${deletions}` : ''] }
export function transcriptSteps(run: FactoryRunView): TranscriptStep[] {
 const phases = [...run.phases].sort((a,b) => stamp(a.startedAt)-stamp(b.startedAt) || (a.seq ?? Number.MAX_SAFE_INTEGER)-(b.seq ?? Number.MAX_SAFE_INTEGER) || a.phaseId.localeCompare(b.phaseId))
 return phases.flatMap((phase) => {
  const diffs = (run.diffs ?? []).filter(diff => diff.phaseId === phase.phaseId)
  const attempts = (run.attempts ?? []).filter(attempt => attempt.phaseId === phase.phaseId).sort((a,b) => stamp(a.startedAt)-stamp(b.startedAt) || a.attemptId.localeCompare(b.attemptId))
  const phaseStep: TranscriptStep = { type:'phase', id: phase.phaseId, phase, attempts, diffs, isStreaming: !phase.endedAt, summary: fragments([phase.name, phase.kind, phase.owner, ...diffSummary(diffs), phase.durationMs == null ? '' : formatDurationMs(phase.durationMs)]) }
  return [phaseStep, ...attempts.map((attempt): TranscriptStep => ({ type:'attempt', id:attempt.attemptId, attempt, phase, diffs: diffs.filter(diff => diff.attempt === phase.attempt || diff.attempt === null), isStreaming: !attempt.endedAt, summary: fragments([attempt.agent, attempt.model, attempt.toolCalls?.length ? `${attempt.toolCalls.length} tool calls` : '', attempt.durationMs == null ? '' : formatDurationMs(attempt.durationMs)]) }))]
 })
}
function violationReasons(value: unknown): string[] {
 if (typeof value === 'string') return [value]
 if (!Array.isArray(value)) return []
 return value.filter((reason): reason is string => typeof reason === 'string' && reason.length > 0)
}

export function failureReasons(run: FactoryRunView): string[] {
 return [
  ...run.phases.map(phase => phase.error),
  ...(run.attempts ?? []).map(attempt => attempt.error),
  ...(run.gates ?? []).filter(gate => gate.passed === false).flatMap(gate => violationReasons(gate.violations)),
 ].filter((reason): reason is string => Boolean(reason))
}
