import { Collapsible } from '@astryxdesign/core/Collapsible'
import { Markdown } from '@astryxdesign/core/Markdown'
import type { JSX } from 'react'
import type { FactoryAgentAttemptView } from '../../lib/factory-types'
import { formatAbsoluteTimestamp } from './factory-helpers'

const KNOWN_TITLES = new Set(['Build Task', 'Plan Task', 'Scout Task', 'Review Task', 'Document Task'])
const AMBIGUITY = 'The stable task or inherited context could not be separated from this message.'

export type AgentInputPresentation = {
  taskText: string
  taskSource: 'known_template' | 'exact_current_message' | 'prior_turn'
  currentMessage: string | null
  priorTurns: FactoryAgentAttemptView[]
  ambiguity: string | null
}

function knownTemplateTask(message: string | null): string | null {
  if (message === null) return null
  const prompts = [...message.matchAll(/^### prompt\r?$/gm)]
  const envelopes = [...message.matchAll(/^### previous_envelope\r?$/gm)]
  if (prompts.length !== 1 || envelopes.length !== 1) return null
  const prompt = prompts[0]!
  const envelope = envelopes[0]!
  const wrapperTitles = [...message.slice(0, prompt.index).matchAll(/^# (.*)\r?$/gm)]
  if (wrapperTitles.length !== 1 || !KNOWN_TITLES.has(wrapperTitles[0]![1]!)) return null
  const promptEnd = prompt.index! + prompt[0].length
  const envelopeStart = envelope.index!
  if (promptEnd >= envelopeStart) return null
  let start = promptEnd
  if (message.slice(start, start + 2) === '\r\n') start += 2
  else if (message[start] === '\n') start += 1
  let end = envelopeStart
  if (message.slice(end - 2, end) === '\r\n') end -= 2
  else if (message[end - 1] === '\n') end -= 1
  return start <= end ? message.slice(start, end) : null
}

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

function priorTurns(attempt: FactoryAgentAttemptView, runAttempts: FactoryAgentAttemptView[]): FactoryAgentAttemptView[] {
  const selectedAt = timestamp(attempt.startedAt)
  if (attempt.sessionId === null || selectedAt === null) return []
  return runAttempts.filter((candidate) => {
    const candidateAt = timestamp(candidate.startedAt)
    return candidate.sessionId !== null && candidate.sessionId === attempt.sessionId && candidateAt !== null && candidateAt < selectedAt
  }).sort((left, right) => timestamp(left.startedAt)! - timestamp(right.startedAt)! || left.attemptId.localeCompare(right.attemptId))
}

function stablePriorTask(attempt: FactoryAgentAttemptView, runAttempts: FactoryAgentAttemptView[]): { task: string | null; ambiguousOrdering: boolean } {
  const selectedAt = timestamp(attempt.startedAt)
  if (attempt.phaseId === null || selectedAt === null) return { task: null, ambiguousOrdering: true }
  const samePhase = runAttempts.filter((candidate) => candidate.attemptId !== attempt.attemptId && candidate.phaseId === attempt.phaseId)
  if (samePhase.some((candidate) => timestamp(candidate.startedAt) === null || timestamp(candidate.startedAt) === selectedAt)) {
    return { task: null, ambiguousOrdering: true }
  }
  const candidates = samePhase
    .filter((candidate) => timestamp(candidate.startedAt)! < selectedAt)
    .sort((left, right) => timestamp(right.startedAt)! - timestamp(left.startedAt)! || right.attemptId.localeCompare(left.attemptId))
  if (candidates.length > 1 && timestamp(candidates[0]!.startedAt) === timestamp(candidates[1]!.startedAt)) {
    return { task: null, ambiguousOrdering: true }
  }
  for (const candidate of candidates) {
    const task = knownTemplateTask(candidate.userPrompt)
    if (task !== null) return { task, ambiguousOrdering: false }
  }
  return { task: null, ambiguousOrdering: false }
}

export function deriveAgentInputPresentation(attempt: FactoryAgentAttemptView, runAttempts: FactoryAgentAttemptView[]): AgentInputPresentation {
  const inherited = priorTurns(attempt, runAttempts)
  if (attempt.userPrompt === null) return { taskText: '', taskSource: 'exact_current_message', currentMessage: null, priorTurns: inherited, ambiguity: null }
  const directTask = knownTemplateTask(attempt.userPrompt)
  if (directTask !== null) return { taskText: directTask, taskSource: 'known_template', currentMessage: null, priorTurns: inherited, ambiguity: null }
  const prior = stablePriorTask(attempt, runAttempts)
  if (!prior.ambiguousOrdering && prior.task !== null) return { taskText: prior.task, taskSource: 'prior_turn', currentMessage: attempt.userPrompt, priorTurns: inherited, ambiguity: null }
  return { taskText: attempt.userPrompt, taskSource: 'exact_current_message', currentMessage: null, priorTurns: inherited, ambiguity: AMBIGUITY }
}

export function AgentInputPanel({ attempt, runAttempts }: { attempt: FactoryAgentAttemptView; runAttempts: FactoryAgentAttemptView[] }): JSX.Element {
  const presentation = deriveAgentInputPresentation(attempt, runAttempts)
  return <section className="space-y-3">
    <h2 className="font-semibold">Task instructions</h2>
    {attempt.userPrompt === null ? <p className="text-sm text-fg-muted">Task instructions were not recorded for this attempt.</p> : <>
      {presentation.taskSource !== 'exact_current_message' && <p className="text-xs text-fg-muted">Derived from the exact user message</p>}
      <Markdown>{presentation.taskText}</Markdown>
      {presentation.ambiguity && <p className="text-sm text-fg-muted">{presentation.ambiguity}</p>}
      {presentation.currentMessage !== null && <div className="space-y-1"><h3 className="font-medium">This dispatch</h3><Markdown>{presentation.currentMessage}</Markdown></div>}
    </>}
    {presentation.priorTurns.length > 0 && <div className="space-y-1"><h3 className="font-medium">Inherited context</h3><p className="text-xs text-fg-muted">{presentation.priorTurns.length} prior recorded turn{presentation.priorTurns.length === 1 ? '' : 's'}</p>{presentation.priorTurns.map((turn) => <p key={turn.attemptId} className="text-xs text-fg-muted">{[turn.agent, turn.startedAt === null ? null : formatAbsoluteTimestamp(turn.startedAt)].filter((value): value is string => value !== null).join(' · ')}</p>)}</div>}
    <p className="text-xs text-fg-muted">Attachment accounting was not recorded for this attempt.</p>
    {attempt.systemPrompt !== null && <Collapsible trigger="System message" defaultIsOpen={false}><Markdown>{attempt.systemPrompt}</Markdown></Collapsible>}
    {attempt.userPrompt !== null && <Collapsible trigger="User message" defaultIsOpen={false}><Markdown>{attempt.userPrompt}</Markdown></Collapsible>}
  </section>
}
