'use client'

import { useEffect, useRef, useState, useCallback } from 'react'
import TagSelector from '@/components/tags/TagSelector'

interface Props {
  url: string
  name: string
  onClose: () => void
  onPrev?: () => void
  onNext?: () => void
  itemKey?: string
  onTagsChanged?: () => void
  onAiTag?: () => Promise<void>
  showTags?: boolean
  onShowTagsChange?: (v: boolean) => void
}

export default function ImageLightbox({ url, name, onClose, onPrev, onNext, itemKey, onTagsChanged, onAiTag, showTags: showTagsProp, onShowTagsChange }: Props) {
  const overlayRef = useRef<HTMLDivElement>(null)
  const [showTagsLocal, setShowTagsLocal] = useState(false)
  const showTags = showTagsProp ?? showTagsLocal
  const setShowTags = onShowTagsChange ?? setShowTagsLocal
  const [aiTagging, setAiTagging] = useState(false)
  const [aiTagError, setAiTagError] = useState<string | null>(null)
  const [tagRefreshKey, setTagRefreshKey] = useState(0)

  // Text extraction state
  const [extractedText, setExtractedText] = useState<string | null>(null)
  const [translatedText, setTranslatedText] = useState<string | null>(null)
  const [extracting, setExtracting] = useState(false)
  const [extractPending, setExtractPending] = useState(false)
  const [extractError, setExtractError] = useState<string | null>(null)
  const [retranslating, setRetranslating] = useState(false)
  const [translatePending, setTranslatePending] = useState(false)
  const [editedExtractedText, setEditedExtractedText] = useState<string>('')
  const [savingText, setSavingText] = useState(false)
  const [sourceLanguage, setSourceLanguage] = useState('')

  // Description state
  const [aiDescription, setAiDescription] = useState<string | null>(null)
  const [editedDescription, setEditedDescription] = useState<string>('')
  const [savingDesc, setSavingDesc] = useState(false)
  const [generatingDesc, setGeneratingDesc] = useState(false)
  const [descPending, setDescPending] = useState(false)
  const [descError, setDescError] = useState<string | null>(null)

  // OCR settings
  const [ocrMode, setOcrMode] = useState<string | null>(null)
  const [defaultOcrLanguages, setDefaultOcrLanguages] = useState('eng')
  const [ocrLanguageInput, setOcrLanguageInput] = useState('')

  // Text overlay state
  const [showTextOverlay, setShowTextOverlay] = useState(false)
  const [showOriginal, setShowOriginal] = useState(false)

  // Polling ref
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)

  // Determine if this is an image file (for text extraction controls)
  const isImage = /\.(jpe?g|png|gif|webp|bmp|tiff?)$/i.test(name)

  // Derived: what text to display in the overlay
  const displayText = (translatedText && !showOriginal) ? translatedText : extractedText

  // Fetch existing AI fields on mount / item change
  const fetchAiFields = useCallback(() => {
    if (!itemKey) return Promise.resolve()
    return fetch(`/api/ai-tagging/fields?itemKey=${encodeURIComponent(itemKey)}`)
      .then((r) => r.json())
      .then((data: { extractedText: string | null; extractedTextTranslated: string | null; aiDescription: string | null }) => {
        setExtractedText(data.extractedText)
        setEditedExtractedText(data.extractedText ?? '')
        setTranslatedText(data.extractedTextTranslated)
        setAiDescription(data.aiDescription)
        setEditedDescription(data.aiDescription ?? '')
      })
      .catch(() => {})
  }, [itemKey])

  useEffect(() => {
    fetchAiFields()
    fetch('/api/ai-settings/ocr')
      .then((r) => r.json())
      .then((d: { ocrMode: string; ocrLanguages: string }) => {
        setOcrMode(d.ocrMode)
        setDefaultOcrLanguages(d.ocrLanguages)
      })
      .catch(() => {})
    return () => {
      if (pollRef.current) clearInterval(pollRef.current)
    }
  }, [fetchAiFields])

  // Start polling fields every 2s until data changes or 5-min timeout
  const startPolling = useCallback((snapshotText: string | null, snapshotTranslated: string | null, snapshotDesc: string | null) => {
    if (!itemKey) return
    if (pollRef.current) clearInterval(pollRef.current)
    const deadline = Date.now() + 5 * 60 * 1000
    pollRef.current = setInterval(async () => {
      if (Date.now() > deadline) {
        clearInterval(pollRef.current!)
        pollRef.current = null
        setExtractPending(false)
        setTranslatePending(false)
        setDescPending(false)
        return
      }
      try {
        const r = await fetch(`/api/ai-tagging/fields?itemKey=${encodeURIComponent(itemKey)}`)
        const data: { extractedText: string | null; extractedTextTranslated: string | null; aiDescription: string | null } = await r.json()
        const textChanged = data.extractedText !== snapshotText
        const translationChanged = data.extractedTextTranslated !== snapshotTranslated
        const descChanged = data.aiDescription !== snapshotDesc
        if (textChanged || translationChanged || descChanged) {
          clearInterval(pollRef.current!)
          pollRef.current = null
          setExtractedText(data.extractedText)
          setEditedExtractedText(data.extractedText ?? '')
          setTranslatedText(data.extractedTextTranslated)
          setAiDescription(data.aiDescription)
          setEditedDescription(data.aiDescription ?? '')
          setExtractPending(false)
          setTranslatePending(false)
          setDescPending(false)
        }
      } catch { /* ignore */ }
    }, 2000)
  }, [itemKey])

  useEffect(() => {
    const handleKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose()
      if (e.key === 'ArrowLeft') onPrev?.()
      if (e.key === 'ArrowRight') onNext?.()
    }
    document.addEventListener('keydown', handleKey)
    document.body.style.overflow = 'hidden'
    return () => {
      document.removeEventListener('keydown', handleKey)
      document.body.style.overflow = ''
    }
  }, [onClose, onPrev, onNext])

  const handleOverlayClick = (e: React.MouseEvent) => {
    if (e.target === overlayRef.current) onClose()
  }

  const handleGenerateDescription = async () => {
    if (!itemKey) return
    setGeneratingDesc(true)
    setDescError(null)
    setDescPending(false)
    try {
      const res = await fetch('/api/ai-tagging/describe', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ itemKey }),
      })
      if (res.status === 202) {
        setDescPending(true)
        startPolling(extractedText, translatedText, aiDescription)
        return
      }
      if (!res.ok) {
        const data = await res.json().catch(() => ({}))
        throw new Error((data as { error?: string }).error ?? 'Failed to generate description')
      }
      const { description } = await res.json()
      setAiDescription(description)
    } catch (err) {
      setDescError(err instanceof Error ? err.message : 'Failed to generate description')
      setTimeout(() => setDescError(null), 4000)
    } finally {
      setGeneratingDesc(false)
    }
  }

  const callExtract = async (modeOverride: string) => {
    setExtracting(true)
    setExtractError(null)
    setExtractPending(false)
    try {
      const res = await fetch('/api/ai-tagging/extract-text', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          itemKey,
          ocrMode: modeOverride,
          ...(modeOverride !== 'llm' && ocrLanguageInput.trim() && { ocrLanguages: ocrLanguageInput.trim() }),
        }),
      })
      if (res.status === 202) {
        setExtractPending(true)
        startPolling(extractedText, translatedText, aiDescription)
        return
      }
      if (!res.ok) {
        const data = await res.json().catch(() => ({}))
        throw new Error((data as { error?: string }).error ?? 'Failed to extract text')
      }
      const result = await res.json()
      setExtractedText(result.extractedText || null)
      setEditedExtractedText(result.extractedText || '')
      setTranslatedText(result.translatedText || null)
    } catch (err) {
      setExtractError(err instanceof Error ? err.message : 'Failed to extract text')
      setTimeout(() => setExtractError(null), 4000)
    } finally {
      setExtracting(false)
    }
  }

  const handleAiTag = async () => {
    if (!onAiTag) return
    setAiTagging(true)
    setAiTagError(null)
    try {
      await onAiTag()
      setTagRefreshKey((k) => k + 1)
      onTagsChanged?.()
    } catch (err) {
      setAiTagError(err instanceof Error ? err.message : 'AI tagging failed')
      setTimeout(() => setAiTagError(null), 4000)
    } finally {
      setAiTagging(false)
    }
  }

  const smallBtn = 'w-7 h-7 rounded-full flex items-center justify-center transition-colors flex-shrink-0'

  return (
    <div
      ref={overlayRef}
      className="fixed inset-0 z-50 overflow-hidden"
      style={{ backgroundColor: 'rgba(0,0,0,0.9)', height: '100vh' }}
      onClick={handleOverlayClick}
    >
      {/* Outer flex — row on md+, col on mobile when panel open */}
      <div className={`flex h-full w-full ${showTags ? 'flex-col md:flex-row' : ''}`}>

        {/* ── Media pane — always full when no panel, flex-1 when panel open ── */}
        <div className="relative flex-1 min-h-0 min-w-0">
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img
            src={url}
            alt={name}
            className="absolute inset-0 w-full h-full object-contain"
            onClick={(e) => e.stopPropagation()}
          />

          {/* Prev / Next */}
          {onPrev && (
            <button
              onClick={(e) => { e.stopPropagation(); onPrev() }}
              className="absolute left-2 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full flex items-center justify-center text-lg transition-opacity hover:opacity-100 opacity-70"
              style={{ backgroundColor: 'rgba(0,0,0,0.4)', color: '#fff' }}
              aria-label="Previous"
            >
              ‹
            </button>
          )}
          {onNext && (
            <button
              onClick={(e) => { e.stopPropagation(); onNext() }}
              className="absolute right-2 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full flex items-center justify-center text-lg transition-opacity hover:opacity-100 opacity-70"
              style={{ backgroundColor: 'rgba(0,0,0,0.4)', color: '#fff' }}
              aria-label="Next"
            >
              ›
            </button>
          )}

          {/* Text overlay */}
          {showTextOverlay && displayText && (
            <div
              className="absolute bottom-16 left-4 right-4 z-10 rounded-xl p-4"
              style={{ backgroundColor: 'rgba(0,0,0,0.75)' }}
              onClick={(e) => e.stopPropagation()}
            >
              {extractedText && translatedText && (
                <div className="flex justify-end mb-2">
                  <button
                    onClick={() => setShowOriginal((v) => !v)}
                    className="text-xs px-2 py-0.5 rounded-full"
                    style={{ backgroundColor: 'rgba(255,255,255,0.15)', color: 'rgba(255,255,255,0.7)' }}
                  >
                    {showOriginal ? 'Show Translation' : 'Show Original'}
                  </button>
                </div>
              )}
              <p className="text-sm whitespace-pre-wrap" style={{ color: 'rgba(255,255,255,0.9)' }}>
                {displayText}
              </p>
            </div>
          )}

          {/* ── Floating controls ── */}

          {/* Filename pill — bottom-left */}
          <div
            className="absolute bottom-4 left-4 max-w-[55%] px-2.5 py-1 rounded-full pointer-events-none"
            style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}
          >
            <span className="block text-xs truncate" style={{ color: 'rgba(255,255,255,0.85)' }}>
              {name}
            </span>
          </div>

          {/* Tags + Close — top-right */}
          <div
            className="absolute top-4 right-4 flex items-center gap-1.5"
            onClick={(e) => e.stopPropagation()}
          >
            {itemKey && !showTags && (
              <button
                onClick={() => { setShowTags(true); setShowTextOverlay(false) }}
                className={smallBtn}
                style={{ backgroundColor: 'var(--surface)', color: 'var(--text-primary)' }}
                onMouseEnter={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface-hover)'}
                onMouseLeave={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface)'}
                aria-label="Show tags"
                title="Tags"
              >
                🏷
              </button>
            )}
            {!showTags && (
              <button
                onClick={onClose}
                className={smallBtn}
                style={{ backgroundColor: 'var(--surface)', color: 'var(--text-primary)' }}
                onMouseEnter={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface-hover)'}
                onMouseLeave={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface)'}
                aria-label="Close"
                title="Close"
              >
                ✕
              </button>
            )}
          </div>

          {/* Text display button — bottom-right, hidden when panel open */}
          {!showTags && extractedText && (
            <button
              onClick={(e) => { e.stopPropagation(); setShowTextOverlay((v) => !v) }}
              className={`absolute bottom-4 right-4 ${smallBtn}`}
              style={{
                backgroundColor: showTextOverlay ? 'var(--accent)' : 'var(--surface)',
                color: showTextOverlay ? '#fff' : 'var(--text-primary)',
              }}
              onMouseEnter={(e) => {
                if (!showTextOverlay) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface-hover)'
              }}
              onMouseLeave={(e) => {
                if (!showTextOverlay) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface)'
              }}
              aria-label={showTextOverlay ? 'Hide text' : 'Show text'}
              title="Display text"
            >
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <line x1="3" y1="6" x2="21" y2="6"/>
                <line x1="3" y1="12" x2="15" y2="12"/>
                <line x1="3" y1="18" x2="18" y2="18"/>
              </svg>
            </button>
          )}
        </div>

        {/* ── Tag panel — bottom half on mobile, right sidebar on desktop ── */}
        {showTags && (
          <div
            className="flex-shrink-0 flex flex-col overflow-hidden w-full max-h-[50vh] md:w-80 md:max-h-none md:h-full"
            style={{ backgroundColor: 'var(--surface)', border: '1px solid var(--border)' }}
            onClick={(e) => e.stopPropagation()}
          >
            {/* Panel header — ‹ hide  |  ✨ AI tag  ✕ close */}
            <div className="flex items-center justify-between p-4 flex-shrink-0">
              <button
                onClick={() => setShowTags(false)}
                className={smallBtn}
                style={{ backgroundColor: 'var(--border)', color: 'var(--text-secondary)', fontSize: '0.85rem' }}
                onMouseEnter={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'}
                onMouseLeave={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'}
                aria-label="Hide panel"
                title="Hide panel"
              >
                ›
              </button>
              <div className="flex items-center gap-1.5">
                <button
                  onClick={onClose}
                  className={smallBtn}
                  style={{ backgroundColor: 'var(--border)', color: 'var(--text-secondary)', fontSize: '0.85rem' }}
                  onMouseEnter={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'}
                  onMouseLeave={(e) => (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'}
                  aria-label="Close"
                  title="Close"
                >
                  ✕
                </button>
              </div>
            </div>

            {/* Scrollable panel content */}
            <div className="overflow-y-auto flex-1 min-h-0 flex flex-col gap-4 px-4 pb-4">

              {/* Description section */}
              <div className="flex flex-col gap-1" style={{ borderTop: '1px solid var(--border)', paddingTop: '1rem' }}>
                {/* Heading row */}
                <div className="flex items-center justify-between mb-2">
                  <p className="text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--text-secondary)' }}>
                    Description
                  </p>
                  <button
                    onClick={handleGenerateDescription}
                    disabled={generatingDesc || descPending}
                    className={`${smallBtn} disabled:opacity-50`}
                    style={{
                      backgroundColor: descPending ? 'var(--accent)' : 'var(--border)',
                      color: descPending ? '#fff' : 'var(--text-secondary)',
                      fontSize: '1rem',
                    }}
                    onMouseEnter={(e) => {
                      if (!generatingDesc && !descPending) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'
                    }}
                    onMouseLeave={(e) => {
                      if (!descPending) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'
                    }}
                    aria-label={aiDescription ? 'Regenerate description' : 'Generate description'}
                    title={aiDescription ? 'Regenerate AI description' : 'Generate AI description'}
                  >
                    {generatingDesc || descPending ? <span className="animate-spin" style={{ display: 'inline-block' }}>⟳</span> : '✨'}
                  </button>
                </div>
                {/* Editable textarea */}
                <textarea
                  value={editedDescription}
                  onChange={(e) => setEditedDescription(e.target.value)}
                  placeholder="No description yet…"
                  className="text-xs rounded-lg p-2 w-full resize-y outline-none"
                  style={{
                    backgroundColor: 'var(--background)',
                    border: '1px solid var(--border)',
                    color: 'var(--text-primary)',
                    minHeight: '3.5rem',
                    maxHeight: '8rem',
                    fontFamily: 'inherit',
                  }}
                />
                {editedDescription !== (aiDescription ?? '') && (
                  <button
                    onClick={async () => {
                      setSavingDesc(true)
                      try {
                        await fetch('/api/ai-tagging/fields', {
                          method: 'PATCH',
                          headers: { 'Content-Type': 'application/json' },
                          body: JSON.stringify({ itemKey, aiDescription: editedDescription }),
                        })
                        setAiDescription(editedDescription)
                      } finally {
                        setSavingDesc(false)
                      }
                    }}
                    disabled={savingDesc}
                    className="mt-1 text-xs px-2 py-0.5 rounded-full transition-colors disabled:opacity-50"
                    style={{ backgroundColor: 'var(--accent)', color: '#fff' }}
                  >
                    {savingDesc ? '⟳ Saving…' : 'Save'}
                  </button>
                )}
                {descError && <span className="text-xs" style={{ color: '#f87171' }}>{descError}</span>}
              </div>

              {/* Text extraction section — only for images */}
              {isImage && (
                <div className="flex flex-col gap-2" style={{ borderTop: '1px solid var(--border)', paddingTop: '1rem' }}>
                  {/* Heading row */}
                  <div className="flex items-center justify-between">
                    <p className="text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--text-secondary)' }}>
                      Text Extraction
                    </p>
                    {/* AI button — forces LLM, no OCR */}
                    <button
                      onClick={() => callExtract('llm')}
                      disabled={extracting || extractPending}
                      className={`${smallBtn} disabled:opacity-50`}
                      style={{
                        backgroundColor: extractPending ? 'var(--accent)' : 'var(--border)',
                        color: extractPending ? '#fff' : 'var(--text-secondary)',
                        fontSize: '1rem',
                      }}
                      onMouseEnter={(e) => {
                        if (!extracting && !extractPending) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'
                      }}
                      onMouseLeave={(e) => {
                        if (!extractPending) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'
                      }}
                      aria-label="Extract text with AI"
                      title="Extract with AI (skips OCR)"
                    >
                      {extractPending ? <span className="animate-spin" style={{ display: 'inline-block' }}>⟳</span> : '✨'}
                    </button>
                  </div>

                  {/* OCR button row */}
                  <div className="flex items-center gap-2 flex-wrap">
                    <button
                      onClick={() => callExtract('tesseract')}
                      disabled={extracting || extractPending}
                      className="text-xs px-2 py-1 rounded-lg transition-colors disabled:opacity-50 self-start flex-shrink-0"
                      style={{
                        backgroundColor: 'var(--border)',
                        color: 'var(--text-secondary)',
                      }}
                      onMouseEnter={(e) => {
                        if (!extracting && !extractPending) {
                          ;(e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'
                          ;(e.currentTarget as HTMLElement).style.color = 'var(--background)'
                        }
                      }}
                      onMouseLeave={(e) => {
                        ;(e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'
                        ;(e.currentTarget as HTMLElement).style.color = 'var(--text-secondary)'
                      }}
                    >
                      {extracting ? '⟳ Scanning…' : extractedText ? '🔍 Re-scan with OCR' : '🔍 Scan with OCR'}
                    </button>
                    <input
                      type="text"
                      value={ocrLanguageInput}
                      onChange={(e) => setOcrLanguageInput(e.target.value)}
                      placeholder={defaultOcrLanguages}
                      className="text-xs px-2 py-0.5 rounded-full outline-none"
                      style={{
                        backgroundColor: 'var(--background)',
                        border: '1px solid var(--border)',
                        color: 'var(--text-primary)',
                        width: 120,
                      }}
                      title="Tesseract language(s) for this extraction (e.g. jpn+jpn_vert). Leave blank to use the configured default."
                    />
                  </div>

                  {extractError && (
                    <p className="text-xs" style={{ color: '#f87171' }}>{extractError}</p>
                  )}

                  {extractedText && (
                    <div className="flex flex-col gap-2">
                      <div>
                        <p className="text-xs font-medium mb-1" style={{ color: 'var(--text-secondary)' }}>
                          Extracted Text
                        </p>
                        <textarea
                          value={editedExtractedText}
                          onChange={(e) => setEditedExtractedText(e.target.value)}
                          className="text-xs whitespace-pre-wrap rounded-lg p-2 w-full resize-y outline-none"
                          style={{
                            backgroundColor: 'var(--background)',
                            color: 'var(--text-primary)',
                            border: '1px solid var(--border)',
                            minHeight: '4rem',
                            maxHeight: '10rem',
                            fontFamily: 'inherit',
                          }}
                        />
                        {editedExtractedText !== extractedText && (
                          <button
                            onClick={async () => {
                              setSavingText(true)
                              try {
                                await fetch('/api/ai-tagging/fields', {
                                  method: 'PATCH',
                                  headers: { 'Content-Type': 'application/json' },
                                  body: JSON.stringify({ itemKey, extractedText: editedExtractedText }),
                                })
                                setExtractedText(editedExtractedText)
                              } finally {
                                setSavingText(false)
                              }
                            }}
                            disabled={savingText}
                            className="mt-1 text-xs px-2 py-0.5 rounded-full transition-colors disabled:opacity-50"
                            style={{ backgroundColor: 'var(--accent)', color: '#fff' }}
                          >
                            {savingText ? '⟳ Saving…' : 'Save'}
                          </button>
                        )}
                      </div>

                      {translatedText && (
                        <div>
                          <p className="text-xs font-medium mb-1" style={{ color: 'var(--text-secondary)' }}>
                            Translation
                          </p>
                          <pre
                            className="text-xs whitespace-pre-wrap rounded-lg p-2 max-h-40 overflow-y-auto"
                            style={{ backgroundColor: 'var(--background)', color: 'var(--text-primary)', border: '1px solid var(--border)' }}
                          >
                            {translatedText}
                          </pre>
                        </div>
                      )}

                      <div className="flex items-center gap-1.5 flex-wrap">
                        <input
                          type="text"
                          value={sourceLanguage}
                          onChange={(e) => setSourceLanguage(e.target.value)}
                          placeholder="Source lang…"
                          className="text-xs px-2 py-0.5 rounded-full outline-none"
                          style={{
                            backgroundColor: 'var(--background)',
                            border: '1px solid var(--border)',
                            color: 'var(--text-primary)',
                            width: 100,
                          }}
                        />
                        <button
                          onClick={async () => {
                            setRetranslating(true)
                            setTranslatePending(false)
                            try {
                              const res = await fetch('/api/ai-tagging/translate', {
                                method: 'POST',
                                headers: { 'Content-Type': 'application/json' },
                                body: JSON.stringify({ itemKey, ...(sourceLanguage.trim() && { sourceLanguage: sourceLanguage.trim() }) }),
                              })
                              if (res.status === 202) {
                                setTranslatePending(true)
                                startPolling(extractedText, translatedText, aiDescription)
                                return
                              }
                              if (!res.ok) {
                                const data = await res.json().catch(() => ({}))
                                throw new Error((data as { error?: string }).error ?? 'Failed to translate')
                              }
                              const result = await res.json()
                              setTranslatedText(result.translatedText || null)
                            } catch {
                              // ignore
                            } finally {
                              setRetranslating(false)
                            }
                          }}
                          disabled={retranslating || translatePending}
                          className="text-xs px-2 py-0.5 rounded-full transition-colors disabled:opacity-50"
                          style={{
                            backgroundColor: translatePending ? 'var(--accent)' : 'var(--border)',
                            color: translatePending ? '#fff' : 'var(--text-secondary)',
                          }}
                          onMouseEnter={(e) => {
                            if (!retranslating && !translatePending) {
                              ;(e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'
                              ;(e.currentTarget as HTMLElement).style.color = 'var(--background)'
                            }
                          }}
                          onMouseLeave={(e) => {
                            if (!translatePending) {
                              ;(e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'
                              ;(e.currentTarget as HTMLElement).style.color = 'var(--text-secondary)'
                            }
                          }}
                        >
                          {retranslating ? '⟳ Translating…' : translatePending ? '⟳ Queued…' : translatedText ? '🌐 Re-translate' : '🌐 Translate'}
                        </button>
                      </div>
                    </div>
                  )}
                </div>
              )}

              {/* Tags section */}
              <div style={{ borderTop: '1px solid var(--border)', paddingTop: '1rem' }}>
                <div className="flex items-center justify-between mb-3">
                  <p className="text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--text-secondary)' }}>
                    Tags
                  </p>
                  {onAiTag && (
                    <button
                      onClick={handleAiTag}
                      disabled={aiTagging}
                      className={`${smallBtn} disabled:opacity-50`}
                      style={{
                        backgroundColor: aiTagError ? '#7f1d1d' : 'var(--border)',
                        color: aiTagError ? '#fca5a5' : 'var(--text-secondary)',
                        fontSize: '1rem',
                      }}
                      onMouseEnter={(e) => {
                        if (!aiTagging && !aiTagError) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--text-secondary)'
                      }}
                      onMouseLeave={(e) => {
                        if (!aiTagError) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)'
                      }}
                      aria-label="AI Tag this image"
                      title={aiTagError ?? (aiTagging ? 'Tagging…' : 'AI Tag')}
                    >
                      {aiTagging ? <span className="animate-spin" style={{ display: 'inline-block' }}>⟳</span> : '✨'}
                    </button>
                  )}
                </div>
                {aiTagError && <p className="text-xs mb-2" style={{ color: '#f87171' }}>{aiTagError}</p>}
                <TagSelector itemKey={itemKey!} onTagsChanged={onTagsChanged} refreshKey={tagRefreshKey} hideDescription />
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  )
}
