import * as React from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useConfig, buildDaemonRequest } from '@/state/config'
import { useI18n } from '@/state/i18n'
import { ipc } from '@/lib/api/desktop'
import { asEnvelope } from '@/lib/error'
import { qk } from '@/lib/queryKeys'
import type {
  DesktopHistoryResponse,
  DesktopLifecycleAction,
  DesktopRecordResponse,
} from '@/lib/types/desktop'
import type { LedgerEntry } from '@/lib/types/lifecycle'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { ErrorBanner } from '@/components/error-banner'
import { DraftDialog } from '@/components/draft-dialog'
import {
  ActionConfirmDialog,
  type ActionConfirmMetadata,
} from '@/components/action-confirm-dialog'
import {
  actionLabel,
  entrySummaryLine,
  stateLabel,
  stateVariant,
} from '@/lib/lifecycle-format'
import {
  Archive,
  CheckCircle2,
  FilePlus,
  Inbox,
  Loader2,
  Search,
  Sparkles,
  TrendingUp,
  Zap,
} from 'lucide-react'

type QueueTab = 'pending' | 'ready'

type ConfirmTarget =
  | { kind: 'single'; recordId: string; title?: string }
  | { kind: 'batch'; ids: string[] }

const ACTION_META: Record<
  DesktopLifecycleAction,
  { icon: typeof CheckCircle2; variant: 'default' | 'outline' | 'destructive' }
> = {
  accept: { icon: CheckCircle2, variant: 'default' },
  promote: { icon: TrendingUp, variant: 'outline' },
  archive: { icon: Archive, variant: 'destructive' },
}

function isEditingTarget(target: EventTarget | null): boolean {
  if (!(target instanceof HTMLElement)) return false
  if (target instanceof HTMLInputElement) return true
  if (target instanceof HTMLTextAreaElement) return true
  if (target instanceof HTMLSelectElement) return true
  if (target.isContentEditable) return true
  return false
}

export function WorkbenchPage({ navigateToId }: { navigateToId?: string | null }) {
  const cfg = useConfig()
  const { t } = useI18n()
  const qc = useQueryClient()
  const [queueTab, setQueueTab] = React.useState<QueueTab>('pending')
  const [selectedId, setSelectedId] = React.useState<string | null>(null)
  const [draftMode, setDraftMode] = React.useState<'manual' | 'propose' | null>(null)
  const [searchQuery, setSearchQuery] = React.useState('')
  const [typeFilter, setTypeFilter] = React.useState<string>('all')
  const [checkedIds, setCheckedIds] = React.useState<Set<string>>(new Set())
  const [pendingAction, setPendingAction] = React.useState<DesktopLifecycleAction | null>(null)
  const [pendingTarget, setPendingTarget] = React.useState<ConfirmTarget | null>(null)
  const searchInputRef = React.useRef<HTMLInputElement | null>(null)

  const daemon = React.useMemo(() => buildDaemonRequest(cfg), [cfg])
  const configPath = cfg.configPath

  const workbenchQuery = useQuery({
    queryKey: qk.workbench(configPath),
    queryFn: () =>
      ipc.loadWorkbench({
        config_path: configPath,
        daemon,
      }),
    enabled: configPath.trim().length > 0,
  })

  const recordQuery = useQuery({
    queryKey: selectedId ? qk.record(configPath, selectedId) : ['record', '__none__'],
    queryFn: () =>
      ipc.getRecord({
        config_path: configPath,
        record_id: selectedId as string,
        daemon,
      }),
    enabled: Boolean(selectedId) && configPath.trim().length > 0,
  })

  const historyQuery = useQuery({
    queryKey: selectedId ? qk.history(configPath, selectedId) : ['history', '__none__'],
    queryFn: () =>
      ipc.getHistory({
        config_path: configPath,
        record_id: selectedId as string,
        daemon,
      }),
    enabled: Boolean(selectedId) && configPath.trim().length > 0,
  })

  const actionMutation = useMutation({
    mutationFn: async (input: {
      recordId: string
      action: DesktopLifecycleAction
      metadata: ActionConfirmMetadata
    }) => {
      await ipc.applyMemoryAction({
        config_path: configPath,
        record_id: input.recordId,
        action: input.action,
        metadata: {
          actor: input.metadata.actor || null,
          reason: input.metadata.reason || null,
          evidence_refs: input.metadata.evidence_refs,
        },
      })
      return input
    },
    onSuccess: ({ recordId }) => {
      qc.invalidateQueries({ queryKey: qk.workbench(configPath) })
      qc.invalidateQueries({ queryKey: qk.record(configPath, recordId) })
      qc.invalidateQueries({ queryKey: qk.history(configPath, recordId) })
    },
  })

  const batchMutation = useMutation({
    mutationFn: async (input: {
      ids: string[]
      action: DesktopLifecycleAction
      metadata: ActionConfirmMetadata
    }) => {
      const meta = {
        actor: input.metadata.actor || null,
        reason: input.metadata.reason || null,
        evidence_refs: input.metadata.evidence_refs,
      }
      for (const recordId of input.ids) {
        await ipc.applyMemoryAction({
          config_path: configPath,
          record_id: recordId,
          action: input.action,
          metadata: meta,
        })
      }
      return input.ids
    },
    onSuccess: (ids) => {
      qc.invalidateQueries({ queryKey: qk.workbench(configPath) })
      for (const id of ids) {
        qc.invalidateQueries({ queryKey: qk.record(configPath, id) })
        qc.invalidateQueries({ queryKey: qk.history(configPath, id) })
      }
      setCheckedIds(new Set())
    },
  })

  React.useEffect(() => {
    if (navigateToId) {
      setSelectedId(navigateToId)
    }
  }, [navigateToId])

  const snapshot = workbenchQuery.data ?? null
  const detail: DesktopRecordResponse | null = (recordQuery.data as DesktopRecordResponse | null | undefined) ?? null
  const history: DesktopHistoryResponse | null = historyQuery.data ?? null
  const error =
    workbenchQuery.error ??
    recordQuery.error ??
    historyQuery.error ??
    actionMutation.error ??
    batchMutation.error ??
    null
  const errorEnvelope = error ? asEnvelope(error) : null

  const loadingQueue = workbenchQuery.isFetching
  const loadingDetail = recordQuery.isFetching || historyQuery.isFetching
  const actionLoading: DesktopLifecycleAction | null =
    actionMutation.isPending && actionMutation.variables
      ? actionMutation.variables.action
      : null
  const batchLoading = batchMutation.isPending
  const dialogOpen = pendingAction !== null && pendingTarget !== null

  const rawEntries =
    snapshot?.snapshot[queueTab === 'pending' ? 'pending_review' : 'wakeup_ready'] ?? []

  const entries = React.useMemo(() => {
    let filtered = rawEntries
    if (searchQuery.trim()) {
      const q = searchQuery.toLowerCase()
      filtered = filtered.filter(
        (e) =>
          e.record.title.toLowerCase().includes(q) ||
          e.record.summary.toLowerCase().includes(q)
      )
    }
    if (typeFilter !== 'all') {
      filtered = filtered.filter((e) => e.record.memory_type === typeFilter)
    }
    if (cfg.currentProjectId) {
      filtered = filtered.filter(
        (e) => e.record.project_id === cfg.currentProjectId,
      )
    }
    return filtered
  }, [rawEntries, searchQuery, typeFilter, cfg.currentProjectId])

  const memoryTypes = React.useMemo(() => {
    const types = new Set(rawEntries.map((e) => e.record.memory_type))
    return Array.from(types).sort()
  }, [rawEntries])

  function toggleCheck(recordId: string) {
    setCheckedIds((prev) => {
      const next = new Set(prev)
      if (next.has(recordId)) next.delete(recordId)
      else next.add(recordId)
      return next
    })
  }

  function toggleAll() {
    const visibleIds = entries.map((e) => e.record_id)
    const allChecked = visibleIds.every((id) => checkedIds.has(id))
    if (allChecked) {
      setCheckedIds((prev) => {
        const next = new Set(prev)
        for (const id of visibleIds) next.delete(id)
        return next
      })
    } else {
      setCheckedIds((prev) => {
        const next = new Set(prev)
        for (const id of visibleIds) next.add(id)
        return next
      })
    }
  }

  const requestSingleAction = React.useCallback(
    (recordId: string, action: DesktopLifecycleAction, title?: string) => {
      setPendingAction(action)
      setPendingTarget({ kind: 'single', recordId, title })
    },
    [],
  )

  const requestBatchAction = React.useCallback(
    (ids: string[], action: DesktopLifecycleAction) => {
      setPendingAction(action)
      setPendingTarget({ kind: 'batch', ids })
    },
    [],
  )

  function closeDialog() {
    setPendingAction(null)
    setPendingTarget(null)
  }

  function handleConfirm(metadata: ActionConfirmMetadata) {
    if (!pendingAction || !pendingTarget) return
    if (pendingTarget.kind === 'single') {
      actionMutation.mutate(
        {
          recordId: pendingTarget.recordId,
          action: pendingAction,
          metadata,
        },
        { onSuccess: () => closeDialog() },
      )
    } else {
      batchMutation.mutate(
        {
          ids: pendingTarget.ids,
          action: pendingAction,
          metadata,
        },
        { onSuccess: () => closeDialog() },
      )
    }
  }

  React.useEffect(() => {
    function onKey(event: KeyboardEvent) {
      if (dialogOpen) return
      if (draftMode !== null) return
      if (event.metaKey || event.ctrlKey || event.altKey) return
      if (isEditingTarget(event.target)) {
        if (event.key === 'Escape' && document.activeElement instanceof HTMLElement) {
          document.activeElement.blur()
        }
        return
      }

      const list = entries
      const currentIndex = selectedId ? list.findIndex((e) => e.record_id === selectedId) : -1

      switch (event.key) {
        case 'j':
        case 'ArrowDown': {
          if (list.length === 0) return
          event.preventDefault()
          const next = currentIndex < 0 ? 0 : Math.min(currentIndex + 1, list.length - 1)
          setSelectedId(list[next].record_id)
          break
        }
        case 'k':
        case 'ArrowUp': {
          if (list.length === 0) return
          event.preventDefault()
          const next = currentIndex < 0 ? list.length - 1 : Math.max(currentIndex - 1, 0)
          setSelectedId(list[next].record_id)
          break
        }
        case 'a': {
          if (!selectedId) return
          event.preventDefault()
          const entry = list.find((e) => e.record_id === selectedId)
          if (entry) requestSingleAction(selectedId, 'accept', entry.record.title)
          break
        }
        case 'p': {
          if (!selectedId) return
          event.preventDefault()
          const entry = list.find((e) => e.record_id === selectedId)
          if (entry) requestSingleAction(selectedId, 'promote', entry.record.title)
          break
        }
        case 'x': {
          if (!selectedId) return
          event.preventDefault()
          const entry = list.find((e) => e.record_id === selectedId)
          if (entry) requestSingleAction(selectedId, 'archive', entry.record.title)
          break
        }
        case '/': {
          event.preventDefault()
          searchInputRef.current?.focus()
          break
        }
        default:
          break
      }
    }

    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [dialogOpen, draftMode, entries, selectedId, requestSingleAction])

  const dialogTarget = pendingTarget
  const dialogRecordTitle =
    dialogTarget?.kind === 'single' ? dialogTarget.title : undefined
  const dialogCountLabel =
    dialogTarget?.kind === 'batch' ? ` ${dialogTarget.ids.length} 条` : undefined

  return (
    <div className="grid gap-5 lg:grid-cols-[380px_1fr]">
      {/* Queue panel */}
      <div className="flex h-[calc(100vh-7rem)] flex-col rounded-xl border border-border-subtle bg-bg-elevated/50 backdrop-blur-sm overflow-hidden">
        {/* Queue header */}
        <div className="shrink-0 space-y-3 p-4 border-b border-border-subtle">
          <div className="flex items-center justify-between">
            <h2 className="text-sm font-semibold text-foreground flex items-center gap-2">
              {t('workbench.queue')}
              {loadingQueue && (
                <Loader2 className="h-3.5 w-3.5 animate-spin text-muted-foreground" />
              )}
            </h2>
          </div>

          {/* Pill tabs */}
          <div className="flex h-8 rounded-lg bg-bg-deep p-0.5">
            <button
              onClick={() => { setQueueTab('pending'); setCheckedIds(new Set()) }}
              className={`flex flex-1 items-center justify-center gap-1.5 rounded-md text-xs font-medium transition-all duration-200 ease-out-expo ${
                queueTab === 'pending'
                  ? 'bg-bg-elevated text-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground/80'
              }`}
            >
              <Inbox className="h-3.5 w-3.5" />
              {t('workbench.tab.pending')}
              {(snapshot?.snapshot.pending_review.length ?? 0) > 0 && (
                <span className={`min-w-[18px] rounded-full px-1.5 text-[10px] font-semibold leading-[18px] text-center ${
                  queueTab === 'pending' ? 'bg-primary/15 text-primary' : 'bg-muted/80 text-muted-foreground'
                }`}>
                  {snapshot?.snapshot.pending_review.length ?? 0}
                </span>
              )}
            </button>
            <button
              onClick={() => { setQueueTab('ready'); setCheckedIds(new Set()) }}
              className={`flex flex-1 items-center justify-center gap-1.5 rounded-md text-xs font-medium transition-all duration-200 ease-out-expo ${
                queueTab === 'ready'
                  ? 'bg-bg-elevated text-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground/80'
              }`}
            >
              <Zap className="h-3.5 w-3.5" />
              {t('workbench.tab.wakeup')}
              {(snapshot?.snapshot.wakeup_ready.length ?? 0) > 0 && (
                <span className={`min-w-[18px] rounded-full px-1.5 text-[10px] font-semibold leading-[18px] text-center ${
                  queueTab === 'ready' ? 'bg-success/15 text-success' : 'bg-muted/80 text-muted-foreground'
                }`}>
                  {snapshot?.snapshot.wakeup_ready.length ?? 0}
                </span>
              )}
            </button>
          </div>

          {/* Search + filter */}
          <div className="flex gap-2">
            <div className="relative flex-1">
              <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/60" />
              <input
                ref={searchInputRef}
                placeholder={t('workbench.search.placeholder')}
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                className="h-8 w-full rounded-lg bg-bg-deep pl-8 pr-3 text-xs text-foreground placeholder:text-muted-foreground/50 outline-none transition-shadow duration-150 focus:shadow-glow-sm"
              />
            </div>
            <Select value={typeFilter} onValueChange={setTypeFilter}>
              <SelectTrigger className="h-8 w-[90px] text-xs border-border-subtle bg-bg-deep">
                <SelectValue placeholder={t('workbench.filter.all')} />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t('workbench.filter.all')}</SelectItem>
                {memoryTypes.map((t) => (
                  <SelectItem key={t} value={t}>{t}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          {/* Action buttons */}
          <div className="flex gap-2">
            <button
              className="flex h-8 flex-1 items-center justify-center gap-1.5 rounded-lg border border-dashed border-border-subtle text-xs text-muted-foreground transition-all duration-150 hover:border-border-hover hover:bg-bg-deep hover:text-foreground cursor-pointer"
              onClick={() => setDraftMode('manual')}
            >
              <FilePlus className="h-3.5 w-3.5" />
              {t('workbench.action.manual')}
            </button>
            <button
              className="flex h-8 flex-1 items-center justify-center gap-1.5 rounded-lg border border-dashed border-border-subtle text-xs text-muted-foreground transition-all duration-150 hover:border-border-hover hover:bg-bg-deep hover:text-foreground cursor-pointer"
              onClick={() => setDraftMode('propose')}
            >
              <Sparkles className="h-3.5 w-3.5" />
              {t('workbench.action.propose')}
            </button>
          </div>

          {/* Batch bar */}
          {checkedIds.size > 0 && (
            <div className="flex items-center gap-2 rounded-lg bg-primary/5 border border-primary/15 px-3 py-2 animate-fade-in-up">
              <span className="text-xs text-muted-foreground">
                {t('workbench.batch.selected').replace('{n}', String(checkedIds.size))}
              </span>
              <Button
                size="sm"
                className="ml-auto h-6 text-xs gap-1 bg-success hover:bg-success/90 text-success-foreground"
                disabled={batchLoading}
                onClick={() => requestBatchAction(Array.from(checkedIds), 'accept')}
              >
                {batchLoading ? <Loader2 className="h-3 w-3 animate-spin" /> : <CheckCircle2 className="h-3 w-3" />}
                {t('workbench.batch.accept')}
              </Button>
              <Button
                size="sm"
                className="h-6 text-xs gap-1 bg-destructive/15 text-destructive hover:bg-destructive/25 border-0"
                disabled={batchLoading}
                onClick={() => requestBatchAction(Array.from(checkedIds), 'archive')}
              >
                {batchLoading ? <Loader2 className="h-3 w-3 animate-spin" /> : <Archive className="h-3 w-3" />}
                {t('workbench.batch.archive')}
              </Button>
            </div>
          )}
        </div>

        {/* Queue list */}
        <div className="flex-1 overflow-y-auto px-3 pb-3 pt-2">
          {entries.length === 0 && !loadingQueue && (
            <div className="flex flex-col items-center justify-center py-12 animate-fade-in-up">
              <div className="flex h-12 w-12 items-center justify-center rounded-full bg-muted/30 mb-3">
                {queueTab === 'pending' ? (
                  <Inbox className="h-5 w-5 text-muted-foreground/50" />
                ) : (
                  <Zap className="h-5 w-5 text-muted-foreground/50" />
                )}
              </div>
              <p className="text-sm font-medium text-muted-foreground/70">
                {queueTab === 'pending' ? t('workbench.empty.pending.title') : t('workbench.empty.wakeup.title')}
              </p>
              <p className="mt-1.5 text-[11px] text-muted-foreground/40 max-w-[240px] text-center leading-relaxed">
                {queueTab === 'ready'
                  ? t('workbench.empty.wakeup.desc')
                  : t('workbench.empty.pending.desc')}
              </p>
            </div>
          )}
          {entries.length > 0 && (
            <div className="mb-2 flex items-center gap-2 px-1">
              <input
                type="checkbox"
                className="h-3.5 w-3.5 rounded border-muted-foreground/30 cursor-pointer"
                checked={entries.length > 0 && entries.every((e) => checkedIds.has(e.record_id))}
                onChange={toggleAll}
              />
              <span className="text-[10px] text-muted-foreground/60">{t('workbench.select_all')}</span>
            </div>
          )}
          <div className="stagger-children space-y-0.5">
            {entries.map((entry) => (
              <QueueItem
                key={entry.record_id}
                entry={entry}
                selected={entry.record_id === selectedId}
                checked={checkedIds.has(entry.record_id)}
                onSelect={() => setSelectedId(entry.record_id)}
                onCheck={() => toggleCheck(entry.record_id)}
              />
            ))}
          </div>
          <p className="mt-4 px-1 text-[10px] leading-relaxed text-muted-foreground/40">
            {t('workbench.keyboard.hint')}
          </p>
        </div>
      </div>

      {/* Detail panel */}
      <div className="space-y-4">
        {errorEnvelope && <ErrorBanner envelope={errorEnvelope} />}
        {!selectedId && (
          <div className="flex h-[calc(100vh-7rem)] items-center justify-center rounded-xl border border-border-subtle bg-bg-elevated/30 backdrop-blur-sm">
            <div className="text-center animate-fade-in-up">
              <div className="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-muted/30">
                <Search className="h-5 w-5 text-muted-foreground/40" />
              </div>
              <p className="text-sm text-muted-foreground/60">{t('workbench.detail.empty')}</p>
              <p className="mt-1 text-[11px] text-muted-foreground/40">{t('workbench.detail.empty.desc')}</p>
            </div>
          </div>
        )}
        {selectedId && detail && (
          <DetailPanel
            detail={detail}
            loading={loadingDetail}
            actionLoading={actionLoading}
            onAction={(action) =>
              requestSingleAction(selectedId, action, detail.record.record.title)
            }
          />
        )}
        {selectedId && history && <HistoryPanel history={history} />}
      </div>

      {draftMode && (
        <DraftDialog
          mode={draftMode}
          open
          onOpenChange={(open) => !open && setDraftMode(null)}
          onCreated={() => {
            setDraftMode(null)
            qc.invalidateQueries({ queryKey: qk.workbench(configPath) })
          }}
        />
      )}

      <ActionConfirmDialog
        open={dialogOpen}
        action={pendingAction}
        recordTitle={dialogRecordTitle}
        countLabel={dialogCountLabel}
        defaultActor={cfg.defaultActor}
        loading={actionMutation.isPending || batchMutation.isPending}
        onConfirm={handleConfirm}
        onCancel={closeDialog}
      />
    </div>
  )
}

function QueueItem({
  entry,
  selected,
  checked,
  onSelect,
  onCheck,
}: {
  entry: LedgerEntry
  selected: boolean
  checked: boolean
  onSelect: () => void
  onCheck: () => void
}) {
  return (
    <div
      className={`group flex items-start gap-2.5 rounded-lg px-2.5 py-2.5 transition-all duration-150 ease-out-expo cursor-pointer ${
        selected
          ? 'bg-bg-elevated shadow-glow-sm'
          : 'hover:bg-bg-elevated/50'
      }`}
    >
      {/* Left accent bar */}
      <div className="relative flex items-start pt-1">
        <div
          className={`absolute -left-2.5 top-0 bottom-0 w-0.5 rounded-r transition-all duration-200 ease-out-expo ${
            selected ? 'bg-primary opacity-100' : 'bg-primary opacity-0 group-hover:opacity-30'
          }`}
        />
        <input
          type="checkbox"
          className="h-3.5 w-3.5 shrink-0 rounded border-muted-foreground/30 cursor-pointer"
          checked={checked}
          onChange={(e) => { e.stopPropagation(); onCheck() }}
          onClick={(e) => e.stopPropagation()}
        />
      </div>
      <button
        type="button"
        onClick={onSelect}
        className="min-w-0 flex-1 text-left"
      >
        <div className="flex items-center justify-between gap-2">
          <span className="line-clamp-1 text-sm font-medium text-foreground">
            {entrySummaryLine(entry)}
          </span>
          <Badge
            variant={stateVariant[entry.record.state]}
            className="shrink-0 text-[10px] bg-primary/10 text-primary border-0"
          >
            {stateLabel[entry.record.state]}
          </Badge>
        </div>
        <p className="mt-0.5 line-clamp-1 text-xs text-muted-foreground/60">
          {entry.record.summary.split('\n')[0]}
        </p>
        <div className="mt-1 flex items-center gap-2 text-[10px] text-muted-foreground/50">
          <span>{entry.record.memory_type}</span>
          <span className="opacity-40">·</span>
          <span>{entry.record.scope}</span>
          {entry.record.project_id && (
            <>
              <span className="opacity-40">·</span>
              <span className="truncate max-w-[80px] text-primary/60">{entry.record.project_id}</span>
            </>
          )}
          <span className="ml-auto text-muted-foreground/30">{entry.recorded_at.slice(0, 10)}</span>
        </div>
      </button>
    </div>
  )
}

function DetailPanel({
  detail,
  loading,
  actionLoading,
  onAction,
}: {
  detail: DesktopRecordResponse
  loading: boolean
  actionLoading: DesktopLifecycleAction | null
  onAction: (a: DesktopLifecycleAction) => void
}) {
  const { t } = useI18n()
  const { record } = detail
  return (
    <div className="rounded-xl border border-border-subtle bg-bg-elevated/50 backdrop-blur-sm overflow-hidden animate-fade-in-up">
      <div className="p-5 border-b border-border-subtle">
        <div className="flex items-start justify-between gap-4">
          <div className="space-y-2 min-w-0 flex-1">
            <h3 className="text-base font-semibold text-foreground">{record.record.title}</h3>
            <div className="flex flex-wrap items-center gap-1.5">
              <span className="text-[10px] font-mono text-muted-foreground/40 truncate max-w-[160px]">{record.record_id}</span>
              <Badge variant={stateVariant[record.record.state]} className="text-[10px] bg-primary/10 text-primary border-0">
                {stateLabel[record.record.state]}
              </Badge>
              <Badge className="text-[10px] bg-muted text-muted-foreground border-0">{record.record.memory_type}</Badge>
              <Badge className="text-[10px] bg-muted text-muted-foreground border-0">{record.record.scope}</Badge>
            </div>
          </div>
          <div className="flex items-center gap-1.5 shrink-0">
            {detail.available_actions.map((action) => {
              const meta = ACTION_META[action]
              const Icon = meta.icon
              const busy = actionLoading === action
              return (
                <Button
                  key={action}
                  variant={meta.variant}
                  size="sm"
                  className={`gap-1 text-xs ${
                    action === 'accept'
                      ? 'bg-success hover:bg-success/90 text-success-foreground'
                      : action === 'archive'
                        ? 'bg-destructive/15 text-destructive hover:bg-destructive/25 border-0'
                        : ''
                  }`}
                  disabled={actionLoading !== null}
                  onClick={() => onAction(action)}
                >
                  {busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Icon className="h-3.5 w-3.5" />}
                  {t(`workbench.action.${action}` as Parameters<typeof t>[0])}
                </Button>
              )
            })}
            {loading && <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />}
          </div>
        </div>
      </div>
      <div className="p-5 space-y-4">
        <p className="text-sm leading-relaxed text-foreground/90">{record.record.summary}</p>

        <div className="grid grid-cols-2 gap-3 text-xs">
          <div className="flex items-center gap-2">
            <span className="text-muted-foreground/50">source</span>
            <span className="text-foreground/70">{record.record.origin.source_kind}</span>
          </div>
          <div className="flex items-center gap-2">
            <span className="text-muted-foreground/50">ref</span>
            <span className="text-foreground/70 truncate">{record.record.origin.source_ref}</span>
          </div>
          {record.record.project_id && (
            <div className="flex items-center gap-2">
              <span className="text-muted-foreground/50">project</span>
              <span className="text-primary/70">{record.record.project_id}</span>
            </div>
          )}
          {record.record.user_id && (
            <div className="flex items-center gap-2">
              <span className="text-muted-foreground/50">user</span>
              <span className="text-foreground/70">{record.record.user_id}</span>
            </div>
          )}
          {record.record.sensitivity && (
            <div className="flex items-center gap-2">
              <span className="text-muted-foreground/50">sensitivity</span>
              <span className="text-foreground/70">{record.record.sensitivity}</span>
            </div>
          )}
        </div>
      </div>
    </div>
  )
}

function HistoryPanel({ history }: { history: DesktopHistoryResponse }) {
  const { t } = useI18n()
  return (
    <div className="rounded-xl border border-border-subtle bg-bg-elevated/50 backdrop-blur-sm overflow-hidden animate-fade-in-up">
      <div className="p-5 border-b border-border-subtle">
        <h3 className="text-sm font-semibold text-foreground">{t('workbench.history.title')}</h3>
        <p className="text-[11px] text-muted-foreground/50 mt-0.5">
          {t('workbench.history.events').replace('{n}', String(history.history.length))}
        </p>
      </div>
      <div className="p-4">
        <ol className="stagger-children space-y-2">
          {history.history.map((entry, idx) => (
            <li
              key={`${entry.record_id}-${idx}`}
              className="rounded-lg bg-bg-deep px-4 py-3 text-xs"
            >
              <div className="flex flex-wrap items-center gap-2">
                <Badge className="text-[10px] bg-muted text-muted-foreground border-0">{actionLabel[entry.action]}</Badge>
                <Badge variant={stateVariant[entry.record.state]} className="text-[10px] bg-primary/10 text-primary border-0">
                  {stateLabel[entry.record.state]}
                </Badge>
                <span className="text-muted-foreground/40 ml-auto">{entry.recorded_at}</span>
              </div>
              {(entry.metadata.actor || entry.metadata.reason) && (
                <p className="mt-1.5 text-muted-foreground/60">
                  {entry.metadata.actor && <span>actor={entry.metadata.actor} </span>}
                  {entry.metadata.reason && <span>reason={entry.metadata.reason}</span>}
                </p>
              )}
              {entry.metadata.evidence_refs && entry.metadata.evidence_refs.length > 0 && (
                <p className="mt-1 text-muted-foreground/50">
                  evidence: {entry.metadata.evidence_refs.join(', ')}
                </p>
              )}
            </li>
          ))}
        </ol>
      </div>
    </div>
  )
}
