import React, { useState, useEffect, useRef } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { getHistory, getGenerationPersons, addGenerationPerson, removeGenerationPerson, createHistoryShare, revokeHistoryShare, savePresetFromHistory, listPersons } from '../api/client'
import { useAuth } from '../hooks/useAuth'
import { X } from 'lucide-react'

interface HistoryRow {
  id: number
  prompt_id: string
  source: string
  user_label?: string
  overrides: Record<string, unknown>
  seed?: number
  file_paths?: string[]
  created_at: string
  share_token?: string | null
  share_is_public?: boolean | null
  share_expires_at?: string | null
  share_max_views?: number | null
  share_view_count?: number | null
  detected_persons?: string[]
}

/** Debounce a value by `delay` ms. */
function useDebounce<T>(value: T, delay: number): T {
  const [debounced, setDebounced] = useState(value)
  useEffect(() => {
    const t = setTimeout(() => setDebounced(value), delay)
    return () => clearTimeout(t)
  }, [value, delay])
  return debounced
}

/** Chip-based multi-person tag input with a filterable combobox dropdown. */
function PersonTagInput({
  selected,
  onChange,
  allPersons,
}: {
  selected: string[]
  onChange: (persons: string[]) => void
  allPersons: Array<{ id: number; name: string }>
}) {
  const [inputVal, setInputVal] = useState('')
  const [showDropdown, setShowDropdown] = useState(false)

  const available = allPersons.filter(
    p => !selected.includes(p.name) &&
      (!inputVal || p.name.toLowerCase().includes(inputVal.toLowerCase()))
  )

  const add = (name: string) => {
    if (!selected.includes(name)) onChange([...selected, name])
    setInputVal('')
    setShowDropdown(false)
  }

  const remove = (name: string) => onChange(selected.filter(p => p !== name))

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter' && available.length > 0) add(available[0].name)
    if (e.key === 'Backspace' && !inputVal && selected.length > 0) {
      remove(selected[selected.length - 1])
    }
  }

  return (
    <div className="space-y-1.5">
      {selected.length > 0 && (
        <div className="flex flex-wrap gap-1">
          {selected.map(p => (
            <span
              key={p}
              className="flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-indigo-500/20 text-indigo-300"
            >
              {p}
              <button onClick={() => remove(p)} className="hover:text-white ml-0.5">
                <X size={10} />
              </button>
            </span>
          ))}
        </div>
      )}
      {allPersons.length > selected.length && (
        <div className="relative">
          <input
            type="text"
            value={inputVal}
            onChange={e => setInputVal(e.target.value)}
            onFocus={() => setShowDropdown(true)}
            onBlur={() => setTimeout(() => setShowDropdown(false), 150)}
            onKeyDown={handleKeyDown}
            placeholder={selected.length === 0 ? 'Filter by person…' : 'Add person…'}
            className="glass-input w-full text-sm"
          />
          {showDropdown && available.length > 0 && (
            <div className="absolute z-20 top-full mt-1 w-full bg-gray-900/95 backdrop-blur-xl border border-white/10 rounded-2xl p-1 max-h-48 overflow-y-auto shadow-xl">
              {available.map(p => (
                <button
                  key={p.id}
                  onMouseDown={() => add(p.name)}
                  className="w-full text-left text-xs px-3 py-1.5 rounded-lg hover:bg-white/10 text-gray-300 transition-colors"
                >
                  {p.name}
                </button>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  )
}

/** Return only the selected persons that appear in the row's detected_persons array. */
function getComboKey(row: HistoryRow, selected: string[]): string {
  const matched = selected.filter(p => row.detected_persons?.includes(p))
  return matched.join('|')
}

interface SectionGroup { key: string; combo: string[]; rows: HistoryRow[] }

/** Group rows by their exclusive combination of selected persons (ascending combo size). */
function groupByCombo(rows: HistoryRow[], selected: string[]): SectionGroup[] {
  const groups = new Map<string, HistoryRow[]>()
  for (const row of rows) {
    const key = getComboKey(row, selected)
    if (!key) continue // matched none of the selected persons
    if (!groups.has(key)) groups.set(key, [])
    groups.get(key)!.push(row)
  }
  return Array.from(groups.entries())
    .map(([key, sRows]) => ({ key, combo: key.split('|'), rows: sRows }))
    .sort((a, b) =>
      a.combo.length !== b.combo.length
        ? a.combo.length - b.combo.length
        : a.key.localeCompare(b.key)
    )
}

export default function HistoryPage() {
  const [lightbox, setLightbox] = useState<string | null>(null)
  const [expandedId, setExpandedId] = useState<string | null>(null)
  const [searchInput, setSearchInput] = useState('')
  const [selectedPersons, setSelectedPersons] = useState<string[]>([])
  const { user, isAdmin } = useAuth()

  const debouncedQ = useDebounce(searchInput.trim(), 300)

  const { data: personsData } = useQuery({ queryKey: ['faces', 'persons'], queryFn: listPersons })
  const persons = personsData?.persons ?? []

  const { data, isLoading } = useQuery({
    queryKey: ['history', debouncedQ, selectedPersons],
    queryFn: () => getHistory(debouncedQ || undefined, selectedPersons.length ? selectedPersons : undefined),
    refetchInterval: 10_000,
  })

  const rows: HistoryRow[] = ((data?.history ?? []) as unknown as HistoryRow[])
  const grouped: SectionGroup[] | null = selectedPersons.length >= 2 ? groupByCombo(rows, selectedPersons) : null

  const isSearching = searchInput.trim() !== debouncedQ

  if (isLoading && !searchInput) return <div className="text-sm text-gray-400">Loading history…</div>

  return (
    <div className="space-y-4">
      <h1 className="text-2xl font-bold tracking-tight">
        <span className="bg-gradient-to-r from-indigo-400 to-violet-400 bg-clip-text text-transparent">
          History
        </span>
      </h1>

      {/* Search + person filter */}
      <div className="glass-card p-3 space-y-2 relative z-30">
        <div className="relative">
          <input
            type="text"
            value={searchInput}
            onChange={e => setSearchInput(e.target.value)}
            placeholder="Search by prompt, checkpoint, seed…"
            className="glass-input w-full pr-8"
          />
          {searchInput && (
            <button
              onClick={() => setSearchInput('')}
              className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-300 transition-colors"
            >
              <X size={14} />
            </button>
          )}
        </div>
        {persons.length > 0 && (
          <PersonTagInput
            selected={selectedPersons}
            onChange={setSelectedPersons}
            allPersons={persons}
          />
        )}
      </div>
      {isSearching && <p className="text-xs text-gray-400">Searching…</p>}

      {isLoading ? (
        <div className="text-sm text-gray-400">Loading…</div>
      ) : rows.length === 0 ? (
        <p className="text-sm text-gray-400">
          {debouncedQ ? `No results for "${debouncedQ}".` : 'No generation history yet.'}
        </p>
      ) : grouped ? (
        /* Grouped view: selectedPersons.length >= 2 */
        <div className="space-y-6">
          {grouped.length === 0 ? (
            <p className="text-sm text-gray-400">No results match the selected persons.</p>
          ) : (
            grouped.map(section => (
              <div key={section.key} className="space-y-2">
                <div className="glass-card p-3">
                  <h2 className="text-sm font-semibold text-indigo-300">
                    {section.combo.join(' & ')}
                    <span className="ml-2 text-xs text-gray-400">{section.rows.length} result(s)</span>
                  </h2>
                </div>
                <HistoryList
                  rows={section.rows}
                  expandedId={expandedId}
                  setExpandedId={setExpandedId}
                  onLightbox={setLightbox}
                  currentUserLabel={user?.label ?? null}
                  isAdmin={isAdmin}
                />
              </div>
            ))
          )}
        </div>
      ) : (
        /* Flat view */
        <HistoryList
          rows={rows}
          expandedId={expandedId}
          setExpandedId={setExpandedId}
          onLightbox={setLightbox}
          currentUserLabel={user?.label ?? null}
          isAdmin={isAdmin}
        />
      )}

      {/* Lightbox */}
      {lightbox && (
        <div
          className="fixed inset-0 bg-black/80 flex items-center justify-center z-50"
          onClick={() => setLightbox(null)}
        >
          <button
            className="absolute top-3 right-3 text-white hover:text-gray-300 transition-colors"
            onClick={() => setLightbox(null)}
            aria-label="Close"
          >
            <X size={24} />
          </button>
          <img
            src={lightbox}
            alt="preview"
            className="max-w-[90vw] max-h-[90vh] object-contain rounded-2xl shadow-2xl"
          />
        </div>
      )}
    </div>
  )
}

function HistoryList({
  rows,
  expandedId,
  setExpandedId,
  onLightbox,
  currentUserLabel,
  isAdmin,
}: {
  rows: HistoryRow[]
  expandedId: string | null
  setExpandedId: (id: string | null) => void
  onLightbox: (url: string) => void
  currentUserLabel: string | null
  isAdmin: boolean
}) {
  return (
    <>
      {/* Desktop table */}
      <div className="hidden sm:block glass-card overflow-hidden p-0">
        <table className="w-full text-sm border-collapse">
          <thead>
            <tr className="bg-white/20 dark:bg-white/5 text-left text-xs text-gray-500 dark:text-gray-400">
              <th className="pb-2 pt-2.5 px-4 border-b border-white/10 dark:border-white/5">Time</th>
              <th className="pb-2 pt-2.5 px-4 border-b border-white/10 dark:border-white/5">Source</th>
              <th className="pb-2 pt-2.5 px-4 border-b border-white/10 dark:border-white/5">User</th>
              <th className="pb-2 pt-2.5 px-4 border-b border-white/10 dark:border-white/5">Seed</th>
              <th className="pb-2 pt-2.5 px-4 border-b border-white/10 dark:border-white/5">Files</th>
            </tr>
          </thead>
          <tbody>
            {rows.map(row => (
              <React.Fragment key={row.prompt_id}>
                <tr
                  className="border-b border-white/5 dark:border-white/5 hover:bg-white/10 dark:hover:bg-white/5 transition-colors cursor-pointer"
                  onClick={() => setExpandedId(expandedId === row.prompt_id ? null : row.prompt_id)}
                >
                  <td className="py-2.5 px-4 text-gray-500 dark:text-gray-400 whitespace-nowrap">
                    {new Date(row.created_at).toLocaleString()}
                  </td>
                  <td className="py-2.5 px-4">
                    <span className={`text-xs px-2 py-0.5 rounded-full ${
                      row.source === 'web'
                        ? 'bg-blue-500/20 text-blue-300'
                        : 'bg-violet-500/20 text-violet-300'
                    }`}>
                      {row.source}
                    </span>
                  </td>
                  <td className="py-2.5 px-4 text-gray-500 dark:text-gray-400">{row.user_label ?? '—'}</td>
                  <td className="py-2.5 px-4 font-mono text-gray-600 dark:text-gray-300">{row.seed ?? '—'}</td>
                  <td className="py-2.5 px-4 text-gray-500 dark:text-gray-400">{(row.file_paths ?? []).length} file(s)</td>
                </tr>
                {expandedId === row.prompt_id && (
                  <tr className="bg-white/5 dark:bg-white/5">
                    <td colSpan={5} className="px-4 py-3">
                      <ExpandedRow row={row} onLightbox={onLightbox} currentUserLabel={currentUserLabel} isAdmin={isAdmin} />
                    </td>
                  </tr>
                )}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>

      {/* Mobile card list */}
      <div className="sm:hidden space-y-2">
        {rows.map(row => {
          const isExpanded = expandedId === row.prompt_id
          const dt = new Date(row.created_at)
          const timeStr = dt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
          const dateStr = dt.toLocaleDateString([], { month: 'short', day: 'numeric' })
          return (
            <div key={row.prompt_id} className="glass-card p-0 overflow-hidden">
              <button
                className="w-full text-left px-3 py-2.5 space-y-1"
                onClick={() => setExpandedId(isExpanded ? null : row.prompt_id)}
              >
                <div className="flex items-center justify-between">
                  <span className="text-xs text-gray-500 dark:text-gray-400">{timeStr} · {dateStr}</span>
                  <span className={`text-xs px-2 py-0.5 rounded-full ${
                    row.source === 'web'
                      ? 'bg-blue-500/20 text-blue-300'
                      : 'bg-violet-500/20 text-violet-300'
                  }`}>
                    {row.source}
                  </span>
                </div>
                <div className="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400">
                  <span>User: {row.user_label ?? '—'}</span>
                  <span>Seed: {row.seed ?? '—'}</span>
                  <span>{(row.file_paths ?? []).length} file(s)</span>
                  <span className="ml-auto">{isExpanded ? '▲' : '▼'}</span>
                </div>
              </button>
              {isExpanded && (
                <div className="px-3 pb-3 border-t border-white/10 dark:border-white/5 pt-2">
                  <ExpandedRow row={row} onLightbox={onLightbox} currentUserLabel={currentUserLabel} isAdmin={isAdmin} />
                </div>
              )}
            </div>
          )
        })}
      </div>
    </>
  )
}

function formatExpiry(s: string | null | undefined): string {
  if (!s) return 'Never'
  const d = new Date(s)
  return d < new Date() ? 'Expired' : d.toLocaleString()
}

function ExpandedRow({
  row,
  onLightbox,
  currentUserLabel,
  isAdmin,
}: {
  row: HistoryRow
  onLightbox: (url: string) => void
  currentUserLabel: string | null
  isAdmin: boolean
}) {
  const qc = useQueryClient()
  const [copied, setCopied] = useState(false)
  const [showSavePreset, setShowSavePreset] = useState(false)
  const [presetName, setPresetName] = useState('')
  const [presetDesc, setPresetDesc] = useState('')
  const [presetMsg, setPresetMsg] = useState<{ ok: boolean; text: string } | null>(null)
  const presetNameRef = useRef<HTMLInputElement>(null)
  const [addPersonInput, setAddPersonInput] = useState('')
  const [showPersonDrop, setShowPersonDrop] = useState(false)
  const [showSharePanel, setShowSharePanel] = useState(false)
  const [shareIsPublic, setShareIsPublic] = useState(false)
  const [shareExpiryHours, setShareExpiryHours] = useState<number | null>(null)
  const [shareMaxViews, setShareMaxViews] = useState<number | null>(null)

  const { data: imagesData, isLoading } = useQuery({
    queryKey: ['history', row.prompt_id, 'images'],
    queryFn: async () => {
      const res = await fetch(`/api/history/${row.prompt_id}/images`, { credentials: 'include' })
      if (!res.ok) throw new Error(`${res.status}`)
      return res.json() as Promise<{ images: Array<{ filename: string; data: string | null; mime_type: string }> }>
    },
  })

  const { data: personsData } = useQuery({
    queryKey: ['history', row.prompt_id, 'persons'],
    queryFn: () => getGenerationPersons(row.prompt_id),
  })
  const rowPersons = personsData?.persons ?? []

  const { data: allPersonsData } = useQuery({
    queryKey: ['faces', 'persons'],
    queryFn: listPersons,
    enabled: isAdmin,
  })
  const allPersons = allPersonsData?.persons ?? []

  const addPersonMut = useMutation({
    mutationFn: (name: string) => addGenerationPerson(row.prompt_id, name),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['history', row.prompt_id, 'persons'] })
      qc.invalidateQueries({ queryKey: ['history'] })
      setAddPersonInput('')
    },
  })

  const removePersonMut = useMutation({
    mutationFn: (personId: number) => removeGenerationPerson(row.prompt_id, personId),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['history', row.prompt_id, 'persons'] })
      qc.invalidateQueries({ queryKey: ['history'] })
    },
  })

  const personDropOptions = allPersons.filter(
    p => !rowPersons.some(rp => rp.id === p.id) &&
      (!addPersonInput || p.name.toLowerCase().includes(addPersonInput.toLowerCase()))
  )

  const shareMut = useMutation({
    mutationFn: () => createHistoryShare(row.prompt_id, {
      is_public: shareIsPublic,
      expires_in_hours: shareExpiryHours ?? undefined,
      max_views: shareMaxViews ?? undefined,
    }),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['history'] })
      setShowSharePanel(false)
    },
  })

  const revokeMut = useMutation({
    mutationFn: () => revokeHistoryShare(row.prompt_id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['history'] }),
  })

  const savePresetMut = useMutation({
    mutationFn: () => savePresetFromHistory(row.prompt_id, presetName.trim(), presetDesc.trim() || undefined),
    onSuccess: (res) => {
      qc.invalidateQueries({ queryKey: ['presets'] })
      setPresetMsg({ ok: true, text: `Saved as preset "${res.name}"` })
      setPresetName('')
      setPresetDesc('')
    },
    onError: (err) => {
      setPresetMsg({ ok: false, text: err instanceof Error ? err.message : String(err) })
    },
  })

  const shareUrl = row.share_token
    ? `${window.location.origin}/share/${row.share_token}`
    : null

  const isOwner = currentUserLabel !== null && row.user_label === currentUserLabel

  const handleCopy = () => {
    if (!shareUrl) return
    navigator.clipboard.writeText(shareUrl).then(() => {
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    })
  }

  return (
    <div className="space-y-3">
      <details>
        <summary className="text-xs text-gray-400 cursor-pointer hover:text-gray-300">Overrides</summary>
        <pre className="text-xs bg-white/5 rounded-xl p-2 mt-1 overflow-auto max-h-32 text-gray-400">
          {JSON.stringify(row.overrides, null, 2)}
        </pre>
      </details>

      {isLoading ? (
        <p className="text-xs text-gray-400">Loading images…</p>
      ) : (imagesData?.images ?? []).length > 0 ? (
        <div className="flex gap-2 flex-wrap">
          {(imagesData?.images ?? []).map((img, i) => {
            const isVideo = img.mime_type.startsWith('video/')
            if (isVideo) {
              const videoSrc = `/api/history/${row.prompt_id}/file/${encodeURIComponent(img.filename)}`
              return <video key={i} src={videoSrc} controls className="rounded-xl max-h-40" />
            }
            const src = `data:${img.mime_type};base64,${img.data}`
            return (
              <img
                key={i}
                src={src}
                alt={img.filename}
                className="rounded-xl max-h-40 cursor-pointer shadow-md hover:shadow-lg transition-shadow"
                onClick={() => onLightbox(src)}
              />
            )
          })}
        </div>
      ) : (
        <p className="text-xs text-gray-400">Files not available (may have been moved or deleted).</p>
      )}

      {(isAdmin || rowPersons.length > 0) && (
        <div className="space-y-1.5">
          <div className="flex items-center gap-2 flex-wrap">
            <span className="text-xs text-gray-500 dark:text-gray-400">People:</span>
            {rowPersons.map(p => (
              <span key={p.id} className="flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-blue-500/20 text-blue-300">
                {p.name}
                {isAdmin && (
                  <button
                    onClick={() => removePersonMut.mutate(p.id)}
                    disabled={removePersonMut.isPending}
                    className="hover:text-white ml-0.5 disabled:opacity-50"
                    aria-label={`Remove ${p.name}`}
                  >
                    <X size={10} />
                  </button>
                )}
              </span>
            ))}
            {rowPersons.length === 0 && !isAdmin && <span className="text-xs text-gray-600">None detected</span>}
          </div>
          {isAdmin && (
            <div className="relative">
              <input
                type="text"
                value={addPersonInput}
                onChange={e => setAddPersonInput(e.target.value)}
                onFocus={() => setShowPersonDrop(true)}
                onBlur={() => setTimeout(() => setShowPersonDrop(false), 150)}
                onKeyDown={e => {
                  if (e.key === 'Enter' && personDropOptions.length > 0) {
                    addPersonMut.mutate(personDropOptions[0].name)
                    setShowPersonDrop(false)
                  }
                }}
                placeholder="Tag a person…"
                className="glass-input w-full text-xs py-1"
                disabled={addPersonMut.isPending}
              />
              {showPersonDrop && personDropOptions.length > 0 && (
                <div className="absolute z-20 top-full mt-1 w-full bg-gray-900/95 backdrop-blur-xl border border-white/10 rounded-2xl p-1 max-h-40 overflow-y-auto shadow-xl">
                  {personDropOptions.map(p => (
                    <button
                      key={p.id}
                      onMouseDown={() => { addPersonMut.mutate(p.name); setShowPersonDrop(false) }}
                      className="w-full text-left text-xs px-3 py-1.5 rounded-lg hover:bg-white/10 text-gray-300 transition-colors"
                    >
                      {p.name}
                    </button>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>
      )}

      {isOwner && (
        <div className="pt-1 border-t border-white/10 dark:border-white/5 space-y-2">
          {shareUrl ? (
            <div className="space-y-1.5">
              <div className="flex items-center gap-2">
                <p className="text-xs text-gray-500 dark:text-gray-400">Share link</p>
                <span className={`text-xs px-1.5 py-0.5 rounded-full ${
                  row.share_is_public
                    ? 'bg-green-500/20 text-green-300'
                    : 'bg-gray-500/20 text-gray-400'
                }`}>
                  {row.share_is_public ? 'Public' : 'Private'}
                </span>
              </div>
              <div className="flex items-center gap-2 flex-wrap">
                <code className="text-xs bg-white/5 rounded-xl px-2 py-1 text-gray-300 break-all select-all flex-1 min-w-0">
                  {shareUrl}
                </code>
                <button
                  onClick={handleCopy}
                  className="shrink-0 text-xs px-2 py-1 rounded-lg bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 transition-colors"
                >
                  {copied ? 'Copied!' : 'Copy'}
                </button>
                <button
                  onClick={() => revokeMut.mutate()}
                  disabled={revokeMut.isPending}
                  className="btn-danger shrink-0"
                >
                  {revokeMut.isPending ? 'Revoking…' : 'Revoke'}
                </button>
              </div>
              <div className="flex gap-4 text-xs text-gray-500">
                <span>Expires: {formatExpiry(row.share_expires_at)}</span>
                {row.share_max_views != null ? (
                  <span>Views: {row.share_view_count ?? 0} / {row.share_max_views}</span>
                ) : (row.share_view_count ?? 0) > 0 ? (
                  <span>Views: {row.share_view_count}</span>
                ) : null}
              </div>
            </div>
          ) : showSharePanel ? (
            <div className="space-y-2">
              <p className="text-xs text-gray-400">Create share link</p>
              <div className="flex gap-2 items-center flex-wrap">
                <span className="text-xs text-gray-500">Visibility:</span>
                <button
                  onClick={() => setShareIsPublic(false)}
                  className={`text-xs px-2 py-0.5 rounded-full transition-colors ${
                    !shareIsPublic
                      ? 'bg-indigo-500/30 text-indigo-300'
                      : 'bg-white/10 text-gray-400 hover:bg-white/15'
                  }`}
                >
                  Private
                </button>
                <button
                  onClick={() => setShareIsPublic(true)}
                  className={`text-xs px-2 py-0.5 rounded-full transition-colors ${
                    shareIsPublic
                      ? 'bg-green-500/30 text-green-300'
                      : 'bg-white/10 text-gray-400 hover:bg-white/15'
                  }`}
                >
                  Public
                </button>
              </div>
              <div className="flex gap-4 flex-wrap">
                <div className="flex items-center gap-1.5">
                  <span className="text-xs text-gray-500">Expires after:</span>
                  <input
                    type="number"
                    min="0"
                    step="any"
                    value={shareExpiryHours ?? ''}
                    onChange={e => setShareExpiryHours(e.target.value ? parseFloat(e.target.value) : null)}
                    placeholder="hours"
                    className="glass-input w-20 py-0.5 text-xs"
                  />
                  <span className="text-xs text-gray-500">hrs</span>
                  {shareExpiryHours !== null && (
                    <button onClick={() => setShareExpiryHours(null)} className="text-xs text-gray-500 hover:text-gray-300">×</button>
                  )}
                </div>
                <div className="flex items-center gap-1.5">
                  <span className="text-xs text-gray-500">Max views:</span>
                  <input
                    type="number"
                    min="1"
                    step="1"
                    value={shareMaxViews ?? ''}
                    onChange={e => setShareMaxViews(e.target.value ? parseInt(e.target.value, 10) : null)}
                    placeholder="unlimited"
                    className="glass-input w-24 py-0.5 text-xs"
                  />
                  {shareMaxViews !== null && (
                    <button onClick={() => setShareMaxViews(null)} className="text-xs text-gray-500 hover:text-gray-300">×</button>
                  )}
                </div>
              </div>
              {shareIsPublic && !shareExpiryHours && !shareMaxViews && (
                <p className="text-xs text-amber-400">⚠ Public shares require at least one expiry condition.</p>
              )}
              {shareMut.isError && (
                <p className="text-xs text-red-400">{shareMut.error instanceof Error ? shareMut.error.message : 'Failed to create share'}</p>
              )}
              <div className="flex gap-2">
                <button
                  onClick={() => shareMut.mutate()}
                  disabled={shareMut.isPending || (shareIsPublic && !shareExpiryHours && !shareMaxViews)}
                  className="text-xs px-2 py-1 rounded-lg bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 disabled:opacity-40 transition-colors"
                >
                  {shareMut.isPending ? 'Creating…' : 'Create Link'}
                </button>
                <button
                  onClick={() => { setShowSharePanel(false); shareMut.reset() }}
                  className="text-xs px-2 py-1 rounded-lg bg-white/10 hover:bg-white/15 text-gray-400 hover:text-gray-300 transition-colors"
                >
                  Cancel
                </button>
              </div>
            </div>
          ) : (
            <button
              onClick={() => setShowSharePanel(true)}
              className="text-xs px-2 py-1 rounded-lg bg-white/10 hover:bg-white/15 text-gray-400 hover:text-gray-300 transition-colors"
            >
              Share
            </button>
          )}

          {!showSavePreset ? (
            <button
              onClick={() => { setShowSavePreset(true); setPresetMsg(null); setTimeout(() => presetNameRef.current?.focus(), 50) }}
              className="text-xs px-2 py-1 rounded-lg bg-white/10 hover:bg-white/15 text-gray-400 hover:text-gray-300 transition-colors"
            >
              Save as preset
            </button>
          ) : (
            <div className="space-y-1.5">
              <p className="text-xs text-gray-500 dark:text-gray-400">Save overrides as preset</p>
              <p className="text-xs text-amber-400">
                Note: workflow template is not saved — load it separately before using this preset.
              </p>
              <div className="flex gap-2 flex-wrap">
                <input
                  ref={presetNameRef}
                  type="text"
                  value={presetName}
                  onChange={e => setPresetName(e.target.value)}
                  placeholder="Preset name"
                  className="glass-input flex-1 min-w-0 py-1 text-xs"
                />
                <input
                  type="text"
                  value={presetDesc}
                  onChange={e => setPresetDesc(e.target.value)}
                  placeholder="Description (optional)"
                  className="glass-input flex-1 min-w-0 py-1 text-xs"
                />
              </div>
              <div className="flex gap-2">
                <button
                  onClick={() => savePresetMut.mutate()}
                  disabled={!presetName.trim() || savePresetMut.isPending}
                  className="btn-primary py-1 px-2 text-xs disabled:opacity-50"
                >
                  {savePresetMut.isPending ? 'Saving…' : 'Save'}
                </button>
                <button
                  onClick={() => { setShowSavePreset(false); setPresetMsg(null); setPresetName(''); setPresetDesc('') }}
                  className="text-xs px-2 py-1 rounded-lg bg-white/10 hover:bg-white/15 text-gray-400 hover:text-gray-300 transition-colors"
                >
                  Cancel
                </button>
              </div>
              {presetMsg && (
                <p className={`text-xs ${presetMsg.ok ? 'text-green-400' : 'text-red-400'}`}>
                  {presetMsg.text}
                </p>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  )
}
