import { useEffect, useMemo, useRef, useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { X, Search } from '../../lib/icons'

interface Cue {
  start: number
  end: number
  text: string
}

interface Props {
  open: boolean
  onClose: () => void
  /** URL to a VTT or ASS subtitle stream. */
  subtitleUrl: string | null
  onJump: (timeSec: number) => void
}

function formatSec(sec: number): string {
  if (!Number.isFinite(sec) || sec < 0) return '0:00'
  const h = Math.floor(sec / 3600)
  const m = Math.floor((sec % 3600) / 60)
  const s = Math.floor(sec % 60)
  if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
  return `${m}:${s.toString().padStart(2, '0')}`
}

function parseTimestamp(s: string): number {
  const m = s.match(/(?:(\d+):)?(\d{1,2}):(\d{2})[.,](\d{1,3})/)
  if (!m) return 0
  return (
    Number(m[1] || 0) * 3600 +
    Number(m[2]) * 60 +
    Number(m[3]) +
    Number(m[4]) / 1000
  )
}

function parseVTT(text: string): Cue[] {
  const out: Cue[] = []
  const blocks = text.replace(/\r\n/g, '\n').split(/\n\n+/)
  for (const block of blocks) {
    const lines = block.split('\n').filter(l => l.trim() !== '')
    if (lines.length < 2) continue
    const tsLine = lines.find(l => l.includes('-->'))
    if (!tsLine) continue
    const [a, b] = tsLine.split('-->').map(s => s.trim().split(' ')[0])
    const start = parseTimestamp(a)
    const end = parseTimestamp(b)
    const textLines = lines.slice(lines.indexOf(tsLine) + 1)
    const txt = textLines.join('\n').replace(/<[^>]+>/g, '').trim()
    if (txt && end > start) out.push({ start, end, text: txt })
  }
  return out
}

function parseASS(text: string): Cue[] {
  const out: Cue[] = []
  const lines = text.split('\n')
  for (const line of lines) {
    if (!line.startsWith('Dialogue:')) continue
    // Format: Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,,Hello world
    const fields = line.slice(9).split(',')
    if (fields.length < 10) continue
    const start = parseTimestamp(fields[1])
    const end = parseTimestamp(fields[2])
    // Text is the rest joined by comma; strip ASS override blocks {\\...}
    const txt = fields.slice(9).join(',').replace(/\{[^}]*\}/g, '').replace(/\\N/gi, ' ').trim()
    if (txt && end > start) out.push({ start, end, text: txt })
  }
  return out
}

export default function SubtitleSearchPanel({ open, onClose, subtitleUrl, onJump }: Props) {
  const [cues, setCues] = useState<Cue[]>([])
  const [query, setQuery] = useState('')
  const [loading, setLoading] = useState(false)
  const inputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    if (!open || !subtitleUrl) return
    setLoading(true)
    let cancelled = false
    fetch(subtitleUrl, { credentials: 'omit' })
      .then(r => r.text())
      .then(text => {
        if (cancelled) return
        const parsed = subtitleUrl.endsWith('.ass') || subtitleUrl.endsWith('.ssa')
          ? parseASS(text)
          : parseVTT(text)
        setCues(parsed)
        setLoading(false)
      })
      .catch(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [open, subtitleUrl])

  useEffect(() => {
    if (open) inputRef.current?.focus()
  }, [open])

  const results = useMemo(() => {
    if (!query.trim()) return []
    const q = query.toLowerCase()
    const out: Cue[] = []
    for (const c of cues) {
      if (c.text.toLowerCase().includes(q)) out.push(c)
      if (out.length >= 200) break
    }
    return out
  }, [cues, query])

  return (
    <AnimatePresence>
      {open && (
        <>
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            onClick={onClose}
            className="absolute inset-0 z-30 bg-black/55 backdrop-blur-[2px]"
          />
          <motion.aside
            initial={{ x: '100%' }}
            animate={{ x: 0 }}
            exit={{ x: '100%' }}
            transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
            className="absolute right-0 top-0 bottom-0 z-40 w-[420px] max-w-[88vw] bg-[#0c0a08]/96 backdrop-blur-xl border-l border-white/10 flex flex-col shadow-[0_0_60px_rgba(0,0,0,0.6)]"
            role="dialog"
            aria-label="Search subtitles"
          >
            <header className="shrink-0 px-5 pt-5 pb-3 border-b border-white/8">
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-[13px] font-semibold uppercase tracking-[0.14em] text-white/85">
                  Search subtitles
                </h2>
                <button
                  onClick={onClose}
                  className="w-8 h-8 grid place-items-center rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors focus-ring"
                  aria-label="Close"
                >
                  <X size={16} />
                </button>
              </div>
              <div className="relative">
                <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-text-3 pointer-events-none" />
                <input
                  ref={inputRef}
                  value={query}
                  onChange={e => setQuery(e.target.value)}
                  placeholder={subtitleUrl ? 'Search dialogue...' : 'No subtitle track active'}
                  disabled={!subtitleUrl}
                  className="w-full h-10 pl-9 pr-3 rounded-md bg-void/60 border border-border focus:border-accent/50 focus:ring-2 focus:ring-accent/15 text-[13px] text-text-1 placeholder:text-text-4 transition-all duration-150 focus:outline-none disabled:opacity-50"
                />
              </div>
              {!loading && cues.length > 0 && (
                <p className="text-[10.5px] text-white/45 mt-2 tabular-nums">
                  {cues.length} cues loaded · {results.length} match
                </p>
              )}
            </header>
            <div className="flex-1 overflow-y-auto content-scroll px-3 py-3 space-y-1">
              {loading && (
                <p className="text-[12.5px] text-white/55 px-2 py-6 text-center">Loading subtitles...</p>
              )}
              {!loading && !subtitleUrl && (
                <p className="text-[12.5px] text-white/55 px-2 py-6 text-center">
                  Pick a subtitle track first.
                </p>
              )}
              {!loading && subtitleUrl && results.length === 0 && query.trim() && (
                <p className="text-[12.5px] text-white/55 px-2 py-6 text-center">No matches.</p>
              )}
              {results.map((c, i) => (
                <button
                  key={`${c.start}-${i}`}
                  onClick={() => {
                    onClose()
                    onJump(c.start)
                  }}
                  className="w-full text-left px-3 py-2.5 rounded-lg border border-white/8 hover:border-white/20 hover:bg-white/5 transition-colors focus-ring"
                >
                  <p className="text-[10.5px] font-mono tabular-nums text-accent mb-1">
                    {formatSec(c.start)}
                  </p>
                  <p className="text-[12.5px] text-white/85 leading-snug">{c.text}</p>
                </button>
              ))}
            </div>
          </motion.aside>
        </>
      )}
    </AnimatePresence>
  )
}
