import type { DecisionContextKv, DecisionRowOption } from '@overdeck/deck-ui'
import type { Item } from '../../lib/collector-types'

export const OLD_WAITING_MS = 24 * 60 * 60 * 1000

interface DecisionExtras {
  dataBlock?: string
  journalRef?: string
  contextKvs?: DecisionContextKv[]
}

function parseDecisionExtras(context: string | undefined): DecisionExtras {
  if (!context) return {}
  try {
    const parsed = JSON.parse(context) as {
      data?: string
      dataBlock?: string
      journal?: string
      journalRef?: string
      kvs?: DecisionContextKv[]
    }
    if (!parsed || typeof parsed !== 'object') return {}
    return {
      dataBlock: parsed.dataBlock ?? parsed.data,
      journalRef: parsed.journalRef ?? parsed.journal,
      contextKvs: parsed.kvs,
    }
  } catch {
    return { contextKvs: [{ label: 'context', value: context }] }
  }
}

export function waitingSinceFor(item: Item): string {
  return item.decision?.waitingSince ?? item.ts
}

export function formatWaitingAge(waitingSince: string, now: number): string {
  const ms = Math.max(0, now - Date.parse(waitingSince))
  if (ms < 60_000) return `waiting ${Math.round(ms / 1000)}s`
  if (ms < 3_600_000) return `waiting ${Math.round(ms / 60_000)}m`
  if (ms < 86_400_000) return `waiting ${Math.round(ms / 3_600_000)}h`
  return `waiting ${Math.round(ms / 86_400_000)}d`
}

export function isOldWaiting(waitingSince: string, now: number): boolean {
  return now - Date.parse(waitingSince) >= OLD_WAITING_MS
}

/** Oldest waiting first — the queue surface is time-sensitive. */
export function sortDecisionItems(items: Item[]): Item[] {
  return [...items].sort((left, right) => Date.parse(waitingSinceFor(left)) - Date.parse(waitingSinceFor(right)))
}

/** Genuine questions only — halts are a different nature and get their own section. */
export function isDecisionQueueItem(item: Item): boolean {
  return item.kind === 'decision'
}

export function isHaltItem(item: Item): boolean {
  return item.kind === 'halt'
}

const ANSWER_VERBS = new Set(['harness.decision.answer', 'factory.decision.answer', 'permission.answer'])

export function optionsForItem(item: Item): DecisionRowOption[] {
  return item.actions
    .filter((action) => ANSWER_VERBS.has(action.verb) && action.args.choice)
    .map((action) => ({
      label: action.label,
      recommended: action.recommended,
      choice: action.args.choice,
    }))
}

/** Factory decisions answer through the collector action gateway; harness ones
 * through the harness decision endpoint. */
export function isFactoryDecisionItem(item: Item): boolean {
  return item.id.startsWith('factory-decision-')
}

export function factoryDecisionId(item: Item): string {
  return item.id.replace(/^factory-decision-/, '')
}

const PERMISSION_ID_PREFIX = 'permission:'

/** Tool-permission requests answer through the collector's permission queue. */
export function isPermissionItem(item: Item): boolean {
  return item.id.startsWith(PERMISSION_ID_PREFIX)
}

export function expandedContentForItem(item: Item) {
  const extras = parseDecisionExtras(item.decision?.context)
  const journalFromKvs = extras.contextKvs?.find((kv) => kv.label.toLowerCase() === 'journal')?.value
  return {
    question: item.decision?.question ?? item.detail,
    dataBlock: extras.dataBlock,
    contextKvs: extras.contextKvs?.filter((kv) => kv.label.toLowerCase() !== 'journal'),
    journalRef: extras.journalRef ?? journalFromKvs,
    allowFreeText: isFactoryDecisionItem(item) ? item.decision?.freeText === true : item.decision?.freeText ?? true,
  }
}

export function projectIdsFromItems(items: Item[]): string[] {
  return [...new Set(items.map((item) => item.project).filter((id): id is string => Boolean(id)))].sort()
}
