import React from 'react'
import ReactDOM from 'react-dom/client'
import {
  QueryClientProvider,
  useMutation,
  useQuery,
  useQueryClient,
} from '@tanstack/react-query'
import { invoke as tauriInvoke } from '@tauri-apps/api/core'
import { queryClient } from '@/lib/queryClient'
import { bindMemorySync } from '@/lib/syncEvents'
import { ipc } from '@/lib/api/desktop'
import { qk } from '@/lib/queryKeys'
import { ConfigProvider, useConfig, buildDaemonRequest } from '@/state/config'
import { I18nProvider, useI18n } from '@/state/i18n'
import { buildMetadataFromFields } from '@/lib/drafts'
import { entrySummaryLine, stateLabel, stateVariant } from '@/lib/lifecycle-format'
import { asEnvelope } from '@/lib/error'
import {
  ActionConfirmDialog,
  type ActionConfirmMetadata,
} from '@/components/action-confirm-dialog'
import {
  CommandPalette,
  useCommandPaletteShortcut,
} from '@/components/command-palette'
import type {
  DesktopLifecycleAction,
  DesktopMemoryDraftRequest,
} from '@/lib/types/desktop'
import type { LedgerEntry } from '@/lib/types/lifecycle'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
  Archive,
  ArrowRight,
  CheckCircle2,
  Inbox,
  Loader2,
  PanelRightOpen,
  Plus,
  Search,
  Sparkles,
  X,
  Zap,
} from 'lucide-react'
import '@/styles/globals.css'

type QueueTab = 'pending' | 'wakeup_ready'

const MAX_VISIBLE = 50

function PopoverApp() {
  const cfg = useConfig()
  const { t } = useI18n()
  const qc = useQueryClient()
  const [tab, setTab] = React.useState<QueueTab>('pending')
  const [search, setSearch] = React.useState('')
  const [selectedId, setSelectedId] = React.useState<string | null>(null)
  const [quickOpen, setQuickOpen] = React.useState(false)
  const [quickTitle, setQuickTitle] = React.useState('')
  const [quickSummary, setQuickSummary] = React.useState('')
  const [errorText, setErrorText] = React.useState<string | null>(null)
  const [pendingAction, setPendingAction] = React.useState<DesktopLifecycleAction | null>(null)
  const [pendingTarget, setPendingTarget] = React.useState<{
    recordId: string
    title: string
  } | null>(null)
  const [paletteOpen, setPaletteOpen] = React.useState(false)
  const searchRef = React.useRef<HTMLInputElement>(null)

  useCommandPaletteShortcut(setPaletteOpen)

  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 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) })
      if (selectedId === recordId) setSelectedId(null)
      setErrorText(null)
    },
    onError: (err) => {
      setErrorText(asEnvelope(err).message ?? '操作失败')
    },
  })

  const quickMutation = useMutation({
    mutationFn: async (input: { title: string; summary: string }) => {
      const payload: DesktopMemoryDraftRequest = {
        config_path: configPath,
        title: input.title,
        summary: input.summary,
        memory_type: 'preference',
        scope: 'user',
        source_ref: 'quick:popover',
        project_id: null,
        user_id: null,
        sensitivity: null,
        metadata: buildMetadataFromFields(cfg.defaultActor, '', ''),
        entities: [],
        tags: [],
        triggers: [],
        related_files: [],
        related_records: [],
        supersedes: null,
        applies_to: [],
        valid_until: null,
      }
      return ipc.recordManual(payload)
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: qk.workbench(configPath) })
      setQuickTitle('')
      setQuickSummary('')
      setQuickOpen(false)
      setErrorText(null)
    },
    onError: (err) => {
      setErrorText(asEnvelope(err).message ?? '快记失败')
    },
  })

  React.useEffect(() => {
    const syncUnlistenPromise = bindMemorySync(qc)
    return () => {
      void syncUnlistenPromise.then((unlisten) => unlisten?.())
    }
  }, [qc])

  React.useEffect(() => {
    function onKey(event: KeyboardEvent) {
      if (pendingAction) return
      if (quickOpen) return
      const target = event.target
      const isEditing =
        target instanceof HTMLInputElement ||
        target instanceof HTMLTextAreaElement ||
        (target instanceof HTMLElement && target.isContentEditable)
      if (isEditing) return
      if (event.key === '/' && !event.metaKey && !event.ctrlKey && !event.altKey) {
        event.preventDefault()
        searchRef.current?.focus()
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [pendingAction, quickOpen])

  const snapshot = workbenchQuery.data ?? null
  const rawEntries =
    snapshot?.snapshot[tab === 'pending' ? 'pending_review' : 'wakeup_ready'] ?? []

  const visibleEntries = React.useMemo(() => {
    const q = search.trim().toLowerCase()
    let list = rawEntries
    if (q) {
      list = list.filter(
        (e) =>
          e.record.title.toLowerCase().includes(q) ||
          e.record.summary.toLowerCase().includes(q),
      )
    }
    if (cfg.currentProjectId) {
      list = list.filter((e) => e.record.project_id === cfg.currentProjectId)
    }
    return list.slice(0, MAX_VISIBLE)
  }, [rawEntries, search, cfg.currentProjectId])

  const pendingCount = snapshot?.snapshot.pending_review.length ?? 0
  const readyCount = snapshot?.snapshot.wakeup_ready.length ?? 0

  const actionLoading: { id: string; action: DesktopLifecycleAction } | null =
    actionMutation.isPending && actionMutation.variables
      ? {
          id: actionMutation.variables.recordId,
          action: actionMutation.variables.action,
        }
      : null

  const handleOpenMain = React.useCallback(() => {
    void tauriInvoke('show_main_window').catch(() => undefined)
  }, [])

  const commandCtx = React.useMemo(
    () => ({
      onCreateManual: handleOpenMain,
      onCreateProposal: handleOpenMain,
      onImportSession: handleOpenMain,
      onNavigateInbox: handleOpenMain,
      onNavigateSessions: handleOpenMain,
      onNavigateIndex: handleOpenMain,
      onNavigateLint: handleOpenMain,
      onNavigateSettings: handleOpenMain,
      onOpenPopover: () => undefined,
      onOpenMain: handleOpenMain,
    }),
    [handleOpenMain],
  )

  const requestAction = React.useCallback(
    (entry: LedgerEntry, action: DesktopLifecycleAction) => {
      setPendingAction(action)
      setPendingTarget({ recordId: entry.record_id, title: entry.record.title })
    },
    [],
  )

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

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

  if (cfg.ready && !cfg.configPath.trim()) {
    return (
      <div className="flex h-screen items-center justify-center bg-bg-deep p-5">
        <div className="animate-scale-in text-center space-y-3">
          <div className="mx-auto flex h-10 w-10 items-center justify-center rounded-full bg-primary/10">
            <Sparkles className="h-5 w-5 text-primary" />
          </div>
          <p className="text-[11px] text-muted-foreground">{t('popover.config.prompt')}</p>
          <Button
            size="sm"
            className="gap-1 h-7 text-[11px]"
            onClick={() => tauriInvoke('show_main_window').catch(() => undefined)}
          >
            {t('popover.config.open')}
            <ArrowRight className="h-3 w-3" />
          </Button>
        </div>
      </div>
    )
  }

  return (
    <div className="flex h-screen w-screen flex-col bg-bg-deep text-foreground">
      {/* Header */}
      <header className="flex h-10 shrink-0 items-center gap-2 border-b border-border-subtle px-2.5">
        <div className="relative flex flex-1 items-center">
          <Search className="pointer-events-none absolute left-2 h-3 w-3 text-muted-foreground" />
          <input
            ref={searchRef}
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder={t('popover.search.placeholder')}
            className="h-7 w-full rounded-md bg-bg-elevated pl-7 pr-2.5 text-[11px] text-foreground placeholder:text-muted-foreground/60 outline-none transition-shadow duration-150 focus:shadow-glow-sm focus:bg-bg-hover"
          />
        </div>
        <button
          onClick={handleOpenMain}
          className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors duration-150 hover:bg-bg-elevated hover:text-foreground"
          title={t('popover.open_main')}
        >
          <PanelRightOpen className="h-3.5 w-3.5" />
        </button>
      </header>

      {/* Pill segment control */}
      <div className="px-2.5 pt-2 pb-1">
        <div className="flex h-7 rounded-md bg-bg-elevated p-0.5">
          <button
            onClick={() => setTab('pending')}
            className={`flex flex-1 items-center justify-center gap-1 rounded text-[11px] font-medium transition-all duration-200 ease-out-expo ${
              tab === 'pending'
                ? 'bg-bg-hover text-foreground shadow-sm'
                : 'text-muted-foreground hover:text-foreground/80'
            }`}
          >
            <Inbox className="h-3 w-3" />
            {t('popover.tab.pending')}
            {pendingCount > 0 && (
              <span className={`min-w-[16px] rounded-full px-1 py-0 text-[9px] font-semibold leading-[16px] text-center ${
                tab === 'pending' ? 'bg-primary/15 text-primary' : 'bg-muted text-muted-foreground'
              }`}>
                {pendingCount}
              </span>
            )}
          </button>
          <button
            onClick={() => setTab('wakeup_ready')}
            className={`flex flex-1 items-center justify-center gap-1 rounded text-[11px] font-medium transition-all duration-200 ease-out-expo ${
              tab === 'wakeup_ready'
                ? 'bg-bg-hover text-foreground shadow-sm'
                : 'text-muted-foreground hover:text-foreground/80'
            }`}
          >
            <Zap className="h-3 w-3" />
            {t('popover.tab.wakeup')}
            {readyCount > 0 && (
              <span className={`min-w-[16px] rounded-full px-1 py-0 text-[9px] font-semibold leading-[16px] text-center ${
                tab === 'wakeup_ready' ? 'bg-success/15 text-success' : 'bg-muted text-muted-foreground'
              }`}>
                {readyCount}
              </span>
            )}
          </button>
        </div>
      </div>

      {/* Project indicator */}
      {cfg.currentProjectId && (
        <div className="mx-2.5 mb-1 flex items-center gap-1 rounded bg-bg-elevated px-2 py-0.5 text-[10px]">
          <span className="font-medium text-muted-foreground">{t('popover.project.label')}</span>
          <span className="flex-1 truncate text-foreground/70">{cfg.currentProjectId}</span>
          <button
            type="button"
            className="text-primary/80 hover:text-primary transition-colors"
            onClick={handleOpenMain}
          >
            {t('popover.project.switch')}
          </button>
        </div>
      )}

      {/* Error */}
      {errorText && (
        <div className="mx-2.5 mb-1 flex items-start gap-2 rounded border border-destructive/30 bg-destructive/8 px-2.5 py-1.5 text-[11px] text-destructive animate-fade-in-up">
          <span className="flex-1">{errorText}</span>
          <button
            type="button"
            onClick={() => setErrorText(null)}
            className="text-destructive/60 hover:text-destructive transition-colors"
          >
            <X className="h-3 w-3" />
          </button>
        </div>
      )}

      {/* List */}
      <div className="flex-1 overflow-y-auto px-1.5 pb-1.5">
        {workbenchQuery.isLoading && (
          <div className="flex items-center justify-center py-8 text-xs text-muted-foreground animate-fade-in-up">
            <Loader2 className="mr-2 h-3.5 w-3.5 animate-spin" />
            {t('popover.loading')}
          </div>
        )}
        {!workbenchQuery.isLoading && visibleEntries.length === 0 && (
          <div className="flex flex-col items-center justify-center py-10 animate-fade-in-up">
            <div className="flex h-10 w-10 items-center justify-center rounded-full bg-muted/50 mb-2.5">
              {tab === 'pending' ? (
                <Inbox className="h-4 w-4 text-muted-foreground/60" />
              ) : (
                <Zap className="h-4 w-4 text-muted-foreground/60" />
              )}
            </div>
            <p className="text-xs font-medium text-muted-foreground/80">
              {search.trim()
                ? t('popover.empty.search.title')
                : tab === 'pending'
                  ? t('popover.empty.pending.title')
                  : t('popover.empty.wakeup.title')}
            </p>
            <p className="mt-1 text-[10px] text-muted-foreground/50 max-w-[220px] text-center leading-relaxed">
              {search.trim()
                ? t('popover.empty.search.desc')
                : tab === 'pending'
                  ? t('popover.empty.pending.desc')
                  : t('popover.empty.wakeup.desc')}
            </p>
          </div>
        )}
        <ul className="stagger-children space-y-0.5">
          {visibleEntries.map((entry) => (
            <PopoverItem
              key={entry.record_id}
              entry={entry}
              selected={selectedId === entry.record_id}
              busyAction={
                actionLoading && actionLoading.id === entry.record_id
                  ? actionLoading.action
                  : null
              }
              disabled={actionMutation.isPending}
              onSelect={() =>
                setSelectedId(
                  selectedId === entry.record_id ? null : entry.record_id,
                )
              }
              onAccept={() => requestAction(entry, 'accept')}
              onArchive={() => requestAction(entry, 'archive')}
            />
          ))}
        </ul>
      </div>

      {/* Footer — quick capture */}
      <footer className="shrink-0 border-t border-border-subtle px-2.5 py-1.5">
        {!quickOpen ? (
          <button
            onClick={() => setQuickOpen(true)}
            className="flex h-7 w-full items-center justify-center gap-1 rounded-md border border-dashed border-border-subtle text-[11px] text-muted-foreground transition-all duration-150 hover:border-border-hover hover:bg-bg-elevated hover:text-foreground cursor-pointer"
          >
            <Plus className="h-3 w-3" />
            {t('popover.quick.button')}
          </button>
        ) : (
          <div className="space-y-1 animate-fade-in-up">
            <input
              value={quickTitle}
              onChange={(e) => setQuickTitle(e.target.value)}
              placeholder={t('popover.quick.title.placeholder')}
              className="h-7 w-full rounded bg-bg-elevated px-2 text-[11px] text-foreground placeholder:text-muted-foreground/50 outline-none focus:shadow-glow-sm"
              autoFocus
            />
            <input
              value={quickSummary}
              onChange={(e) => setQuickSummary(e.target.value)}
              placeholder={t('popover.quick.summary.placeholder')}
              className="h-7 w-full rounded bg-bg-elevated px-2 text-[11px] text-foreground placeholder:text-muted-foreground/50 outline-none focus:shadow-glow-sm"
              onKeyDown={(e) => {
                if (e.key === 'Enter' && quickTitle.trim() && quickSummary.trim()) {
                  quickMutation.mutate({ title: quickTitle.trim(), summary: quickSummary.trim() })
                }
              }}
            />
            <div className="flex gap-1">
              <button
                className="flex h-6 flex-1 items-center justify-center rounded text-[11px] text-muted-foreground transition-colors hover:bg-bg-elevated hover:text-foreground"
                onClick={() => {
                  setQuickOpen(false)
                  setQuickTitle('')
                  setQuickSummary('')
                  setErrorText(null)
                }}
                disabled={quickMutation.isPending}
              >
                {t('popover.quick.cancel')}
              </button>
              <button
                className="flex h-6 flex-1 items-center justify-center gap-1 rounded bg-primary text-[11px] font-medium text-primary-foreground transition-all duration-150 hover:brightness-110 disabled:opacity-40"
                disabled={
                  quickMutation.isPending ||
                  !quickTitle.trim() ||
                  !quickSummary.trim()
                }
                onClick={() =>
                  quickMutation.mutate({
                    title: quickTitle.trim(),
                    summary: quickSummary.trim(),
                  })
                }
              >
                {quickMutation.isPending && (
                  <Loader2 className="h-2.5 w-2.5 animate-spin" />
                )}
                {t('popover.quick.save')}
              </button>
            </div>
          </div>
        )}
      </footer>

      <ActionConfirmDialog
        open={pendingAction !== null && pendingTarget !== null}
        action={pendingAction}
        recordTitle={pendingTarget?.title}
        defaultActor={cfg.defaultActor}
        loading={actionMutation.isPending}
        onConfirm={handleConfirm}
        onCancel={closeDialog}
      />

      <CommandPalette
        open={paletteOpen}
        onOpenChange={setPaletteOpen}
        ctx={commandCtx}
      />
    </div>
  )
}

function PopoverItem({
  entry,
  selected,
  busyAction,
  disabled,
  onSelect,
  onAccept,
  onArchive,
}: {
  entry: LedgerEntry
  selected: boolean
  busyAction: DesktopLifecycleAction | null
  disabled: boolean
  onSelect: () => void
  onAccept: () => void
  onArchive: () => void
}) {
  const { t } = useI18n()
  return (
    <li className="group">
      <button
        type="button"
        onClick={onSelect}
        className={`relative block w-full rounded-md px-2 py-1.5 text-left transition-all duration-150 ease-out-expo ${
          selected
            ? 'bg-bg-elevated shadow-glow-sm'
            : 'hover:bg-bg-elevated/60'
        }`}
      >
        {/* Left accent bar */}
        <div
          className={`absolute left-0 top-1.5 bottom-1.5 w-0.5 rounded-r transition-all duration-200 ease-out-expo ${
            selected ? 'bg-primary opacity-100' : 'bg-primary opacity-0 group-hover:opacity-40'
          }`}
        />

        <div className="flex items-center gap-1">
          <span className="line-clamp-1 flex-1 text-[11px] font-medium text-foreground">
            {entrySummaryLine(entry)}
          </span>
          <Badge
            variant={stateVariant[entry.record.state]}
            className="shrink-0 text-[9px] bg-primary/10 text-primary border-0 h-4 px-1"
          >
            {stateLabel[entry.record.state]}
          </Badge>
        </div>
        <p className="mt-0.5 line-clamp-1 text-[10px] text-muted-foreground/70">
          {entry.record.summary.split('\n')[0]}
        </p>
        <div className="mt-0.5 flex items-center gap-1 text-[9px] 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-[70px]">{entry.record.project_id}</span>
            </>
          )}
        </div>
      </button>
      {selected && (
        <div className="mx-2 mt-1 mb-1 flex gap-1 animate-fade-in-up">
          <Button
            size="sm"
            className="h-6 flex-1 gap-1 text-[10px] bg-success hover:bg-success/90 text-success-foreground"
            disabled={disabled}
            onClick={(e) => {
              e.stopPropagation()
              onAccept()
            }}
          >
            {busyAction === 'accept' ? (
              <Loader2 className="h-2.5 w-2.5 animate-spin" />
            ) : (
              <CheckCircle2 className="h-2.5 w-2.5" />
            )}
            {t('popover.action.accept')}
          </Button>
          <Button
            size="sm"
            variant="destructive"
            className="h-6 flex-1 gap-1 text-[10px] bg-destructive/15 text-destructive hover:bg-destructive/25 border-0"
            disabled={disabled}
            onClick={(e) => {
              e.stopPropagation()
              onArchive()
            }}
          >
            {busyAction === 'archive' ? (
              <Loader2 className="h-2.5 w-2.5 animate-spin" />
            ) : (
              <Archive className="h-2.5 w-2.5" />
            )}
            {t('popover.action.archive')}
          </Button>
        </div>
      )}
    </li>
  )
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <I18nProvider>
        <ConfigProvider>
          <PopoverApp />
        </ConfigProvider>
      </I18nProvider>
    </QueryClientProvider>
  </React.StrictMode>,
)
