'use client'

import { useState, useCallback, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import { X, ChevronDown, ChevronUp, Replace, CaseSensitive, Regex } from 'lucide-react'
import { useLanguage } from '@/lib/i18n'
import { cn } from '@/lib/utils'
import { Extension } from '@tiptap/core'
import { Editor } from '@tiptap/core'
import { Decoration, DecorationSet } from '@tiptap/pm/view'
import { Plugin, PluginKey, TextSelection } from '@tiptap/pm/state'

interface Match {
  from: number
  to: number
}

const pluginKey = new PluginKey<DecorationState>('findReplaceDecorations')

interface DecorationState {
  decorations: DecorationSet
  currentIndex: number
}

function findMatches(doc: any, query: string, caseSensitive: boolean, useRegex: boolean): Match[] {
  if (!query) return []
  let pattern: RegExp
  try {
    if (useRegex) {
      pattern = new RegExp(query, caseSensitive ? 'g' : 'gi')
    } else {
      pattern = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), caseSensitive ? 'g' : 'gi')
    }
  } catch { return [] }

  const results: Match[] = []
  doc.descendants((node: any, pos: number) => {
    if (!node.isText || !node.text) return
    pattern.lastIndex = 0
    let m: RegExpExecArray | null
    while ((m = pattern.exec(node.text)) !== null) {
      if (m[0].length === 0) { pattern.lastIndex++; continue }
      results.push({ from: pos + m.index, to: pos + m.index + m[0].length })
    }
  })
  return results
}

export const FindReplaceExtension = Extension.create({
  name: 'findReplace',

  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: pluginKey,
        state: {
          init(): DecorationState {
            return { decorations: DecorationSet.empty, currentIndex: -1 }
          },
          apply(tr, old: DecorationState): DecorationState {
            const meta = tr.getMeta(pluginKey)
            if (meta) return meta
            if (tr.docChanged) {
              return { decorations: DecorationSet.empty, currentIndex: -1 }
            }
            return old || { decorations: DecorationSet.empty, currentIndex: -1 }
          },
        },
        props: {
          decorations(state) {
            return pluginKey.getState(state)?.decorations || null
          },
        },
      }),
    ]
  },
})

export function FindReplaceBar({ editor, onClose }: { editor: Editor; onClose: () => void }) {
  const { t } = useLanguage()
  const [searchText, setSearchText] = useState('')
  const [replaceText, setReplaceText] = useState('')
  const [caseSensitive, setCaseSensitive] = useState(false)
  const [useRegex, setUseRegex] = useState(false)
  const [count, setCount] = useState(0)
  const [currentIndex, setCurrentIndex] = useState(-1)
  const [showReplace, setShowReplace] = useState(false)
  const inputRef = useRef<HTMLInputElement>(null)

  const matchesRef = useRef<Match[]>([])
  const indexRef = useRef(-1)

  const applyDecorations = useCallback((matches: Match[], activeIdx: number) => {
    const decos = matches.map((m, i) =>
      Decoration.inline(m.from, m.to, {
        class: i === activeIdx ? 'fr-active' : 'fr-match',
      })
    )
    const set = DecorationSet.create(editor.state.doc, decos)
    const tr = editor.state.tr.setMeta(pluginKey, { decorations: set, currentIndex: activeIdx })
    tr.setMeta('addToHistory', false)
    editor.view.dispatch(tr)
  }, [editor])

  const scrollToMatch = useCallback((m: Match) => {
    try {
      const dom = editor.view.domAtPos(m.from)
      const el = dom.node instanceof HTMLElement ? dom.node : (dom.node as any).parentElement
      el?.scrollIntoView({ behavior: 'smooth', block: 'center' })
    } catch {}
  }, [editor])

  const runSearch = useCallback((text: string) => {
    if (!text.trim()) {
      matchesRef.current = []
      setCount(0)
      setCurrentIndex(-1)
      indexRef.current = -1
      applyDecorations([], -1)
      return
    }
    const found = findMatches(editor.state.doc, text, caseSensitive, useRegex)
    matchesRef.current = found
    setCount(found.length)
    const idx = found.length > 0 ? 0 : -1
    setCurrentIndex(idx)
    indexRef.current = idx
    applyDecorations(found, idx)
    if (idx >= 0) scrollToMatch(found[idx])
  }, [caseSensitive, useRegex, editor, applyDecorations, scrollToMatch])

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

  const next = useCallback(() => {
    const ms = matchesRef.current
    if (ms.length === 0) return
    const ni = (indexRef.current + 1) % ms.length
    indexRef.current = ni
    setCurrentIndex(ni)
    applyDecorations(ms, ni)
    scrollToMatch(ms[ni])
  }, [applyDecorations, scrollToMatch])

  const prev = useCallback(() => {
    const ms = matchesRef.current
    if (ms.length === 0) return
    const ni = (indexRef.current - 1 + ms.length) % ms.length
    indexRef.current = ni
    setCurrentIndex(ni)
    applyDecorations(ms, ni)
    scrollToMatch(ms[ni])
  }, [applyDecorations, scrollToMatch])

  const replaceOne = useCallback(() => {
    const ms = matchesRef.current
    const idx = indexRef.current
    if (idx < 0 || ms.length === 0) return
    const m = ms[idx]
    editor.chain().focus().insertContentAt({ from: m.from, to: m.to }, replaceText).run()
    setTimeout(() => {
      const found = findMatches(editor.state.doc, searchText, caseSensitive, useRegex)
      matchesRef.current = found
      setCount(found.length)
      const ni = found.length > 0 ? Math.min(idx, found.length - 1) : -1
      indexRef.current = ni
      setCurrentIndex(ni)
      applyDecorations(found, ni)
      if (ni >= 0) scrollToMatch(found[ni])
    }, 50)
  }, [editor, replaceText, searchText, caseSensitive, useRegex, applyDecorations, scrollToMatch])

  const replaceAll = useCallback(() => {
    const ms = matchesRef.current
    if (ms.length === 0) return
    // Sort descending by position so replacements don't shift earlier positions
    const sorted = [...ms].sort((a, b) => b.from - a.from)
    // Use a single ProseMirror transaction for all replacements
    const tr = editor.state.tr
    for (const m of sorted) {
      tr.insertText(replaceText, m.from, m.to)
    }
    editor.view.dispatch(tr)
    matchesRef.current = []
    setCount(0)
    setCurrentIndex(-1)
    indexRef.current = -1
    applyDecorations([], -1)
  }, [editor, replaceText, applyDecorations])

  return createPortal(
    <div
      className="fixed top-4 right-4 z-[9999] w-80 rounded-xl border border-border bg-popover shadow-xl"
      dir="auto"
      onMouseDown={(e) => e.stopPropagation()}
    >
      <div className="flex items-center justify-between px-3 py-2 border-b border-border/50">
        <span className="text-sm font-medium">{t('richTextEditor.findReplaceTitle')}</span>
        <button onClick={onClose} className="p-0.5 rounded hover:bg-muted text-muted-foreground">
          <X className="h-4 w-4" />
        </button>
      </div>

      <div className="p-3 space-y-2">
        <div className="flex items-center gap-1">
          <input
            ref={inputRef}
            type="text"
            value={searchText}
            onChange={(e) => {
              setSearchText(e.target.value)
              runSearch(e.target.value)
            }}
            onKeyDown={(e) => {
              e.stopPropagation()
              if (e.key === 'Enter') { e.preventDefault(); e.shiftKey ? prev() : next() }
              if (e.key === 'Escape') onClose()
            }}
            placeholder={t('richTextEditor.findPlaceholder')}
            className="flex-1 min-w-0 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm outline-none focus:ring-2 focus:ring-primary/30"
          />
          <span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap px-1">
            {count > 0 ? `${currentIndex + 1}/${count}` : `0/0`}
          </span>
        </div>

        <div className="flex items-center gap-0.5">
          <button
            onClick={() => setCaseSensitive(v => !v)}
            className={cn('p-1.5 rounded hover:bg-muted text-muted-foreground transition-colors', caseSensitive && 'bg-primary/10 text-primary')}
            title={t('richTextEditor.findCaseSensitive')}
          >
            <CaseSensitive className="h-4 w-4" />
          </button>
          <button
            onClick={() => setUseRegex(v => !v)}
            className={cn('p-1.5 rounded hover:bg-muted text-muted-foreground transition-colors', useRegex && 'bg-primary/10 text-primary')}
            title={t('richTextEditor.findRegex')}
          >
            <Regex className="h-4 w-4" />
          </button>
          <button
            onClick={() => setShowReplace(v => !v)}
            className={cn('p-1.5 rounded hover:bg-muted text-muted-foreground transition-colors', showReplace && 'bg-muted text-foreground')}
            title={t('richTextEditor.findReplaceToggle')}
          >
            <Replace className="h-4 w-4" />
          </button>
          <div className="flex-1" />
          <button
            onClick={prev}
            disabled={count === 0}
            className="p-1.5 rounded hover:bg-muted text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed"
            title={t('richTextEditor.findPrev')}
          >
            <ChevronUp className="h-4 w-4" />
          </button>
          <button
            onClick={next}
            disabled={count === 0}
            className="p-1.5 rounded hover:bg-muted text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed"
            title={t('richTextEditor.findNext')}
          >
            <ChevronDown className="h-4 w-4" />
          </button>
        </div>

        {showReplace && (
          <div className="flex items-center gap-1 pt-1 border-t border-border/30">
            <input
              type="text"
              value={replaceText}
              onChange={(e) => setReplaceText(e.target.value)}
              onKeyDown={(e) => e.stopPropagation()}
              placeholder={t('richTextEditor.replacePlaceholder')}
              className="flex-1 min-w-0 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm outline-none focus:ring-2 focus:ring-primary/30"
            />
            <button
              onClick={replaceOne}
              disabled={currentIndex < 0}
              className="px-2 py-1 text-xs rounded-md hover:bg-muted text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed whitespace-nowrap"
            >
              {t('richTextEditor.replace')}
            </button>
            <button
              onClick={replaceAll}
              disabled={count === 0}
              className="px-2 py-1 text-xs rounded-md bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-40 disabled:cursor-not-allowed whitespace-nowrap font-medium"
            >
              {t('richTextEditor.replaceAll')}
            </button>
          </div>
        )}
      </div>
    </div>,
    document.body
  )
}
