'use client'

import { useEffect, useRef, useState, useCallback, forwardRef, useImperativeHandle } from 'react'
import { createPortal } from 'react-dom'
import { useLanguage } from '@/lib/i18n'
import { useEditor, EditorContent } from '@tiptap/react'
import { BubbleMenu } from '@tiptap/react/menus'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import Placeholder from '@tiptap/extension-placeholder'
import TiptapLink from '@tiptap/extension-link'
import Highlight from '@tiptap/extension-highlight'
import Image from '@tiptap/extension-image'
import TextAlign from '@tiptap/extension-text-align'
import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
import Superscript from '@tiptap/extension-superscript'
import Subscript from '@tiptap/extension-subscript'
import Typography from '@tiptap/extension-typography'
import type { Editor } from '@tiptap/core'
import type { EditorState } from '@tiptap/pm/state'
import {
  Bold, Italic, Underline as UnderlineIcon, Strikethrough, Code,
  Heading1, Heading2, Heading3, List, ListOrdered, CheckSquare,
  Quote, CodeXml, Minus, ImageIcon, Type, Highlighter, Link as LinkIcon,
  Sparkles, Wand2, Scissors, Lightbulb, X, Check, ExternalLink,
  FileText, Pilcrow, MessageSquare, AlignLeft, AlignCenter, AlignRight,
  Superscript as SuperscriptIcon, Subscript as SubscriptIcon, Expand,
} from 'lucide-react'
import { cn } from '@/lib/utils'

export interface RichTextEditorHandle {
  getEditor: () => Editor | null
}

interface RichTextEditorProps {
  content?: string
  onChange?: (content: string) => void
  className?: string
  placeholder?: string
}

type SlashItem = {
  title: string
  description: string
  icon: typeof Bold
  category?: string
  shortcut?: string
  isImage?: boolean
  isAi?: boolean
  aiOption?: 'clarify' | 'shorten' | 'improve'
  command: (editor: Editor) => void
}

const slashCommands: SlashItem[] = [
  { title: 'Text', description: 'Plain paragraph', icon: Pilcrow, category: 'Basic blocks', shortcut: '¶', command: (e) => e.chain().focus().setParagraph().run() },
  { title: 'Heading 1', description: 'Big section heading', icon: Heading1, category: 'Basic blocks', shortcut: '#', command: (e) => e.chain().focus().toggleHeading({ level: 1 }).run() },
  { title: 'Heading 2', description: 'Medium section heading', icon: Heading2, category: 'Basic blocks', shortcut: '##', command: (e) => e.chain().focus().toggleHeading({ level: 2 }).run() },
  { title: 'Heading 3', description: 'Small section heading', icon: Heading3, category: 'Basic blocks', shortcut: '###', command: (e) => e.chain().focus().toggleHeading({ level: 3 }).run() },
  { title: 'Bullet List', description: 'Unordered list', icon: List, category: 'Basic blocks', shortcut: '-', command: (e) => e.chain().focus().toggleBulletList().run() },
  { title: 'Numbered List', description: 'Ordered numbered list', icon: ListOrdered, category: 'Basic blocks', shortcut: '1.', command: (e) => e.chain().focus().toggleOrderedList().run() },
  { title: 'To-do List', description: 'Checkboxes for tasks', icon: CheckSquare, category: 'Basic blocks', shortcut: '[]', command: (e) => e.chain().focus().toggleTaskList().run() },
  { title: 'Quote', description: 'Capture a quote', icon: Quote, category: 'Basic blocks', shortcut: '>', command: (e) => e.chain().focus().toggleBlockquote().run() },
  { title: 'Code Block', description: 'Code snippet', icon: CodeXml, category: 'Basic blocks', shortcut: '```', command: (e) => e.chain().focus().toggleCodeBlock().run() },
  { title: 'Divider', description: 'Horizontal separator', icon: Minus, category: 'Basic blocks', shortcut: '---', command: (e) => e.chain().focus().setHorizontalRule().run() },
  { title: 'Image', description: 'Embed image from URL', icon: ImageIcon, category: 'Media', isImage: true, command: () => {} },
  { title: 'Align Left', description: 'Align text left', icon: AlignLeft, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('left').run() },
  { title: 'Align Center', description: 'Center text', icon: AlignCenter, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('center').run() },
  { title: 'Align Right', description: 'Align text right', icon: AlignRight, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('right').run() },
  { title: 'Superscript', description: 'Raise text above baseline', icon: SuperscriptIcon, category: 'Formatting', command: (e) => e.chain().focus().toggleSuperscript().run() },
  { title: 'Subscript', description: 'Lower text below baseline', icon: SubscriptIcon, category: 'Formatting', command: (e) => e.chain().focus().toggleSubscript().run() },
  { title: 'Clarifier', description: 'Rendre le texte plus clair', icon: Lightbulb, category: 'IA Note', isAi: true, aiOption: 'clarify', command: () => {} },
  { title: 'Raccourcir', description: 'Condenser le texte', icon: Scissors, category: 'IA Note', isAi: true, aiOption: 'shorten', command: () => {} },
  { title: 'Améliorer', description: 'Améliorer le style', icon: Wand2, category: 'IA Note', isAi: true, aiOption: 'improve', command: () => {} },
  { title: 'Développer', description: 'Élaborer et enrichir le texte', icon: Expand, category: 'IA Note', isAi: true, aiOption: 'clarify', command: () => {} },
]

async function aiReformulate(text: string, option: 'clarify' | 'shorten' | 'improve'): Promise<string> {
  const res = await fetch('/api/ai/reformulate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ text, option }),
  })
  const data = await res.json()
  if (!res.ok) throw new Error(data.error || 'AI failed')
  return data.reformulatedText || data.text || text
}

function useImageInsert() {
  const [open, setOpen] = useState(false)
  const editorRef = useRef<Editor | null>(null)

  const requestInsert = useCallback((editor: Editor) => {
    editorRef.current = editor
    setOpen(true)
  }, [])

  const confirm = useCallback((url: string) => {
    if (url.trim() && editorRef.current) {
      editorRef.current.chain().focus().setImage({ src: url.trim() }).run()
    }
    setOpen(false)
    editorRef.current = null
  }, [])

  const cancel = useCallback(() => {
    setOpen(false)
    editorRef.current = null
  }, [])

  return { open, requestInsert, confirm, cancel }
}

export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(
  function RichTextEditor({ content, onChange, className, placeholder }, ref) {
    const imageInsert = useImageInsert()

    const editor = useEditor({
      extensions: [
        StarterKit.configure({ heading: { levels: [1, 2, 3] }, link: false, underline: false }),
        Underline,
        TiptapLink.configure({ openOnClick: false, autolink: true }),
        Highlight.configure({ multicolor: false }),
        Image.configure({ inline: false, allowBase64: true }),
        TextAlign.configure({ types: ['heading', 'paragraph'] }),
        TaskList,
        TaskItem.configure({ nested: true }),
        Superscript,
        Subscript,
        Typography,
        Placeholder.configure({ placeholder: placeholder || "Type '/' for commands..." }),
      ],
      content: content || '',
      immediatelyRender: false,
      editorProps: {
        attributes: { class: 'notion-editor' },
      },
      onUpdate: ({ editor: e }) => {
        onChange?.(e.getHTML())
      },
    })

    useImperativeHandle(ref, () => ({ getEditor: () => editor }), [editor])

    return (
      <div className={cn('notion-editor-wrapper', className)}>
        {editor && (
          <BubbleMenu
            editor={editor}
            className="notion-bubble-menu"
            shouldShow={({ editor: e, state }: { editor: Editor; state: EditorState }) => {
              const { from, to } = state.selection
              return from !== to && !e.isActive('codeBlock')
            }}
          >
            <BubbleToolbar editor={editor} />
          </BubbleMenu>
        )}

        {editor && <SlashCommandMenu editor={editor} onInsertImage={imageInsert.requestInsert} />}

        <EditorContent editor={editor} />

        {imageInsert.open && (
          <ImageModal onConfirm={imageInsert.confirm} onCancel={imageInsert.cancel} />
        )}
      </div>
    )
  }
)

function ImageModal({ onConfirm, onCancel }: { onConfirm: (url: string) => void; onCancel: () => void }) {
  const [url, setUrl] = useState('')
  const [preview, setPreview] = useState<string | null>(null)
  const [error, setError] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)

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

  const handleConfirm = () => {
    if (!url.trim()) return
    if (!/^https?:\/\/.+/i.test(url.trim())) { setError('Please enter a valid URL'); return }
    onConfirm(url.trim())
  }

  return (
    <div className="notion-overlay" onClick={onCancel}>
      <div className="notion-image-modal" onClick={(e) => e.stopPropagation()}>
        <div className="text-sm font-medium mb-3">Insert image</div>
        <input
          ref={inputRef}
          type="url"
          value={url}
          onChange={(e) => { setUrl(e.target.value); setError(''); setPreview(null) }}
          onKeyDown={(e) => { if (e.key === 'Enter') handleConfirm(); if (e.key === 'Escape') onCancel() }}
          placeholder="https://example.com/image.png"
          className="notion-modal-input"
        />
        {url.trim() && !preview && (
          <button onClick={() => setPreview(url.trim())} className="text-xs text-muted-foreground hover:text-foreground transition-colors underline mt-2">
            Preview
          </button>
        )}
        {preview && (
          <div className="mt-2 rounded-lg overflow-hidden border border-border max-h-40">
            <img src={preview} alt="" className="max-h-40 object-contain w-full" onError={() => { setPreview(null); setError('Failed to load image') }} />
          </div>
        )}
        {error && <div className="mt-1.5 text-xs text-destructive">{error}</div>}
        <div className="flex justify-end gap-2 mt-4">
          <button onClick={onCancel} className="notion-modal-btn">Cancel</button>
          <button onClick={handleConfirm} className="notion-modal-btn notion-modal-btn-primary">Insert</button>
        </div>
      </div>
    </div>
  )
}

function BubbleToolbar({ editor }: { editor: Editor | null }) {
  const [, setTick] = useState(0)
  const [aiOpen, setAiOpen] = useState(false)
  const [aiLoading, setAiLoading] = useState(false)
  const [linkOpen, setLinkOpen] = useState(false)
  const [linkUrl, setLinkUrl] = useState('')
  const linkInputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    if (!editor) return
    const h = () => setTick(t => t + 1)
    editor.on('transaction', h)
    editor.on('selectionUpdate', h)
    return () => { editor.off('transaction', h); editor.off('selectionUpdate', h) }
  }, [editor])

  useEffect(() => {
    if (linkOpen && linkInputRef.current) linkInputRef.current.focus()
  }, [linkOpen])

  if (!editor) return null

  const marks = [
    { icon: Bold, active: editor.isActive('bold'), action: () => editor.chain().focus().toggleBold().run() },
    { icon: Italic, active: editor.isActive('italic'), action: () => editor.chain().focus().toggleItalic().run() },
    { icon: UnderlineIcon, active: editor.isActive('underline'), action: () => editor.chain().focus().toggleUnderline().run() },
    { icon: Strikethrough, active: editor.isActive('strike'), action: () => editor.chain().focus().toggleStrike().run() },
    { icon: Code, active: editor.isActive('code'), action: () => editor.chain().focus().toggleCode().run() },
    { icon: Highlighter, active: editor.isActive('highlight'), action: () => editor.chain().focus().toggleHighlight().run() },
  ]

  const handleAI = async (option: 'clarify' | 'shorten' | 'improve') => {
    const { from, to } = editor.state.selection
    const text = editor.state.doc.textBetween(from, to, ' ')
    if (!text || text.split(/\s+/).length < 5) return
    setAiLoading(true)
    setAiOpen(false)
    try {
      const result = await aiReformulate(text, option)
      editor.chain().focus().insertContentAt({ from, to }, result).run()
    } catch (err) {
      console.error('AI error:', err)
    } finally {
      setAiLoading(false)
    }
  }

  const openLinkEditor = () => {
    const existing = editor.getAttributes('link').href || ''
    setLinkUrl(existing)
    setLinkOpen(true)
    setAiOpen(false)
  }

  const applyLink = () => {
    if (linkUrl.trim()) {
      editor.chain().focus().extendMarkRange('link').setLink({ href: linkUrl.trim() }).run()
    } else {
      editor.chain().focus().extendMarkRange('link').unsetLink().run()
    }
    setLinkOpen(false)
  }

  if (linkOpen) {
    return (
      <div className="flex items-center gap-1.5 px-2 py-1.5">
        <LinkIcon className="w-3.5 h-3.5 text-muted-foreground flex-shrink-0" />
        <input
          ref={linkInputRef}
          type="url"
          value={linkUrl}
          onChange={(e) => setLinkUrl(e.target.value)}
          onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); applyLink() }; if (e.key === 'Escape') { setLinkOpen(false); editor.chain().focus().run() } }}
          placeholder="Paste or type a link..."
          className="notion-inline-input"
        />
        <button onClick={applyLink} className="notion-bubble-btn notion-bubble-btn-active"><Check className="w-3.5 h-3.5" /></button>
        {editor.isActive('link') && (
          <button onClick={() => { editor.chain().focus().extendMarkRange('link').unsetLink().run(); setLinkOpen(false) }} className="notion-bubble-btn">
            <ExternalLink className="w-3.5 h-3.5" />
          </button>
        )}
        <button onClick={() => { setLinkOpen(false); editor.chain().focus().run() }} className="notion-bubble-btn"><X className="w-3.5 h-3.5" /></button>
      </div>
    )
  }

  return (
    <div className="flex items-center gap-0.5 px-1 py-0.5 relative">
      {marks.map((m, i) => (
        <button key={i} onClick={m.action} className={cn('notion-bubble-btn', m.active && 'notion-bubble-btn-active')}>
          <m.icon className="w-3.5 h-3.5" />
        </button>
      ))}
      <div className="w-px h-4 bg-gray-300 dark:bg-gray-600 mx-0.5" />
      <button onClick={openLinkEditor} className={cn('notion-bubble-btn', editor.isActive('link') && 'notion-bubble-btn-active')}><LinkIcon className="w-3.5 h-3.5" /></button>
      <button onClick={() => setAiOpen(!aiOpen)} className={cn('notion-bubble-btn', aiLoading && 'animate-pulse')}><Sparkles className="w-3.5 h-3.5" /></button>
      {aiOpen && (
        <div className="notion-ai-submenu">
          <button className="notion-ai-subitem" onClick={() => handleAI('clarify')}><Lightbulb className="w-3.5 h-3.5 text-amber-500" /><span>Clarify</span></button>
          <button className="notion-ai-subitem" onClick={() => handleAI('shorten')}><Scissors className="w-3.5 h-3.5 text-blue-500" /><span>Shorten</span></button>
          <button className="notion-ai-subitem" onClick={() => handleAI('improve')}><Wand2 className="w-3.5 h-3.5 text-purple-500" /><span>Improve</span></button>
        </div>
      )}
    </div>
  )
}

function SlashCommandMenu({ editor, onInsertImage }: { editor: Editor; onInsertImage: (editor: Editor) => void }) {
  const { t } = useLanguage()
  const [isOpen, setIsOpen] = useState(false)
  const [query, setQuery] = useState('')
  const [selectedIndex, setSelectedIndex] = useState(0)
  const [activeCategory, setActiveCategory] = useState<string | null>(null)
  const [coords, setCoords] = useState({ top: 0, left: 0 })
  const [aiLoading, setAiLoading] = useState(false)
  const menuRef = useRef<HTMLDivElement>(null)
  const selectedItemRef = useRef<HTMLButtonElement>(null)
  // Flag: true while user is interacting with the menu (prevents selectionUpdate from closing it)
  const menuInteracting = useRef(false)

  // Translated category names (keys match slashCommands category field)
  const CAT_LABELS: Record<string, string> = {
    'Basic blocks': t('richTextEditor.slashCatBasic'),
    'Media': t('richTextEditor.slashCatMedia'),
    'Formatting': t('richTextEditor.slashCatFormatting'),
    'IA Note': t('richTextEditor.slashCatAi'),
  }

  // Translated command list (keeps same order/icons/shortcuts as global slashCommands)
  const localCommands: SlashItem[] = [
    { ...slashCommands[0],  title: t('richTextEditor.slashText'),        description: t('richTextEditor.slashTextDesc'),        category: 'Basic blocks' },
    { ...slashCommands[1],  title: t('richTextEditor.slashH1'),          description: t('richTextEditor.slashH1Desc'),          category: 'Basic blocks' },
    { ...slashCommands[2],  title: t('richTextEditor.slashH2'),          description: t('richTextEditor.slashH2Desc'),          category: 'Basic blocks' },
    { ...slashCommands[3],  title: t('richTextEditor.slashH3'),          description: t('richTextEditor.slashH3Desc'),          category: 'Basic blocks' },
    { ...slashCommands[4],  title: t('richTextEditor.slashBullet'),      description: t('richTextEditor.slashBulletDesc'),      category: 'Basic blocks' },
    { ...slashCommands[5],  title: t('richTextEditor.slashNumbered'),    description: t('richTextEditor.slashNumberedDesc'),    category: 'Basic blocks' },
    { ...slashCommands[6],  title: t('richTextEditor.slashTodo'),        description: t('richTextEditor.slashTodoDesc'),        category: 'Basic blocks' },
    { ...slashCommands[7],  title: t('richTextEditor.slashQuote'),       description: t('richTextEditor.slashQuoteDesc'),       category: 'Basic blocks' },
    { ...slashCommands[8],  title: t('richTextEditor.slashCode'),        description: t('richTextEditor.slashCodeDesc'),        category: 'Basic blocks' },
    { ...slashCommands[9],  title: t('richTextEditor.slashDivider'),     description: t('richTextEditor.slashDividerDesc'),     category: 'Basic blocks' },
    { ...slashCommands[10], title: t('richTextEditor.slashImage'),       description: t('richTextEditor.slashImageDesc'),       category: 'Media' },
    { ...slashCommands[11], title: t('richTextEditor.slashAlignLeft'),   description: t('richTextEditor.slashAlignLeftDesc'),   category: 'Formatting' },
    { ...slashCommands[12], title: t('richTextEditor.slashAlignCenter'), description: t('richTextEditor.slashAlignCenterDesc'), category: 'Formatting' },
    { ...slashCommands[13], title: t('richTextEditor.slashAlignRight'),  description: t('richTextEditor.slashAlignRightDesc'),  category: 'Formatting' },
    { ...slashCommands[14], title: t('richTextEditor.slashSuperscript'), description: t('richTextEditor.slashSuperscriptDesc'), category: 'Formatting' },
    { ...slashCommands[15], title: t('richTextEditor.slashSubscript'),   description: t('richTextEditor.slashSubscriptDesc'),   category: 'Formatting' },
    { ...slashCommands[16], title: t('richTextEditor.slashClarify'),     description: t('richTextEditor.slashClarifyDesc'),     category: 'IA Note' },
    { ...slashCommands[17], title: t('richTextEditor.slashShorten'),     description: t('richTextEditor.slashShortenDesc'),     category: 'IA Note' },
    { ...slashCommands[18], title: t('richTextEditor.slashImprove'),     description: t('richTextEditor.slashImproveDesc'),     category: 'IA Note' },
    { ...slashCommands[19], title: t('richTextEditor.slashExpand'),      description: t('richTextEditor.slashExpandDesc'),      category: 'IA Note' },
  ]

  const closeMenu = useCallback(() => {
    setIsOpen(false); setQuery(''); setSelectedIndex(0); setActiveCategory(null)
  }, [])

  const deleteSlashText = useCallback(() => {
    const { from, to } = editor.state.selection
    const textBefore = editor.state.doc.textBetween(Math.max(0, from - 50), from, '\n')
    const slashIdx = textBefore.lastIndexOf('/')
    if (slashIdx >= 0) {
      const deleteFrom = from - (textBefore.length - slashIdx)
      editor.chain().focus().deleteRange({ from: deleteFrom, to }).run()
    }
  }, [editor])

  const handleSelect = useCallback(async (item: SlashItem) => {
    if (item.isImage) {
      deleteSlashText(); closeMenu(); onInsertImage(editor)
    } else if (item.isAi && item.aiOption) {
      deleteSlashText(); closeMenu(); setAiLoading(true)
      try {
        const allText = editor.state.doc.textContent
        if (!allText || allText.split(/\s+/).length < 5) return
        const result = await aiReformulate(allText, item.aiOption)
        editor.chain().focus().setContent(result).run()
      } catch (err) { console.error('AI slash error:', err) }
      finally { setAiLoading(false) }
    } else {
      deleteSlashText(); item.command(editor); closeMenu()
    }
  }, [editor, closeMenu, deleteSlashText, onInsertImage])

  // All category names in order
  const allCategories = Array.from(new Set(localCommands.map(c => c.category || 'Basic blocks')))

  const textFiltered = localCommands.filter(c => c.title.toLowerCase().includes(query.toLowerCase()) || c.description.toLowerCase().includes(query.toLowerCase()))
  const filtered = activeCategory ? textFiltered.filter(c => (c.category || 'Basic blocks') === activeCategory) : textFiltered

  const categories = filtered.reduce((acc, item) => {
    const cat = item.category || 'Basic blocks'
    if (!acc[cat]) acc[cat] = []
    acc[cat].push(item)
    return acc
  }, {} as Record<string, SlashItem[]>)

  // Auto-scroll selected item into view
  useEffect(() => {
    selectedItemRef.current?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
  }, [selectedIndex])

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (!isOpen) return
      if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex(i => (i + 1) % filtered.length); return }
      if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex(i => (i - 1 + filtered.length) % filtered.length); return }
      if (e.key === 'Enter') { e.preventDefault(); if (filtered[selectedIndex]) handleSelect(filtered[selectedIndex]); return }
      if (e.key === 'Escape') { e.preventDefault(); closeMenu(); return }
      if (e.key === 'Tab') {
        e.preventDefault()
        // Cycle through categories with Tab
        const catKeys = Object.keys(categories)
        if (catKeys.length < 2) return
        const currentCatIdx = activeCategory ? catKeys.indexOf(activeCategory) : -1
        const nextCat = catKeys[(currentCatIdx + 1) % catKeys.length]
        setActiveCategory(nextCat)
        setSelectedIndex(0)
        return
      }
    }
    document.addEventListener('keydown', handleKeyDown, true)
    return () => document.removeEventListener('keydown', handleKeyDown, true)
  }, [isOpen, selectedIndex, filtered, handleSelect, closeMenu, categories, activeCategory])

  useEffect(() => {
    if (!isOpen) return
    const { from } = editor.state.selection
    const c = editor.view.coordsAtPos(from)
    setCoords({ top: c.bottom + 8, left: c.left })
  }, [isOpen, editor, query])

  useEffect(() => {
    const handleClick = (e: MouseEvent) => {
      if (isOpen && menuRef.current && !menuRef.current.contains(e.target as Node)) {
        closeMenu()
      }
    }
    document.addEventListener('click', handleClick)
    return () => document.removeEventListener('click', handleClick)
  }, [isOpen, closeMenu])

  useEffect(() => {
    const handler = () => {
      // Ignore events fired while user clicks inside the menu
      if (menuInteracting.current) return
      const { from, empty } = editor.state.selection
      if (!empty) { if (isOpen) closeMenu(); return }
      const text = editor.state.doc.textBetween(Math.max(0, from - 50), from, '\n')
      const m = text.match(/\/([^\s/]*)$/)
      if (m) { setQuery(m[1]); setSelectedIndex(0); if (!isOpen) setIsOpen(true) }
      else if (isOpen) closeMenu()
    }
    editor.on('update', handler)
    editor.on('selectionUpdate', handler)
    return () => { editor.off('update', handler); editor.off('selectionUpdate', handler) }
  }, [editor, isOpen, closeMenu])

  if (!isOpen || filtered.length === 0) return null

  let flatIndex = -1
  const totalVisible = Object.keys(categories).length

  return createPortal(
    <div
      ref={menuRef}
      className="notion-slash-menu"
      style={{ top: coords.top, left: coords.left }}
      onClick={(e) => e.stopPropagation()}
    >
      {/* Category tabs */}
      {!query && totalVisible > 1 && (
        <div className="notion-slash-tabs" onMouseDown={(e) => e.preventDefault()}>
          <button
            className={cn('notion-slash-tab', !activeCategory && 'notion-slash-tab-active')}
            onMouseDown={(e) => e.preventDefault()}
            onClick={() => { setActiveCategory(null); setSelectedIndex(0) }}
          >
            {t('richTextEditor.slashTabAll')}
          </button>
          {allCategories.filter(cat => categories[cat]).map(cat => (
            <button
              key={cat}
              className={cn('notion-slash-tab', activeCategory === cat && 'notion-slash-tab-active', cat === 'IA Note' && 'notion-slash-tab-ai')}
              onMouseDown={(e) => e.preventDefault()}
              onClick={() => { setActiveCategory(activeCategory === cat ? null : cat); setSelectedIndex(0) }}
            >
              {cat === 'IA Note' && <Sparkles className="w-2.5 h-2.5" />}
              {cat}
              <span className="notion-slash-tab-count">{categories[cat]?.length ?? 0}</span>
            </button>
          ))}
        </div>
      )}

      {/* Header hint */}
      <div className="notion-slash-header">
        <span>{t('richTextEditor.slashHint')}</span>
      </div>

      {aiLoading && (
        <div className="notion-slash-loading">
          <Sparkles className="w-3.5 h-3.5 animate-spin" />
          <span>{t('richTextEditor.slashLoading')}</span>
        </div>
      )}
      {!aiLoading && Object.entries(categories).map(([cat, items]) => (
        <div key={cat} className="notion-slash-section">
          <div className={cn('notion-slash-label', cat === 'IA Note' && 'notion-slash-label-ai')}>
            {cat === 'IA Note' && <Sparkles className="w-3 h-3 inline mr-1" />}
            {CAT_LABELS[cat] || cat}
          </div>
          {items.map((item) => {
            flatIndex++
            const idx = flatIndex
            const isSelected = idx === selectedIndex
            return (
              <button
                key={item.title}
                ref={isSelected ? selectedItemRef : null}
                className={cn('notion-slash-item', isSelected && 'notion-slash-item-selected')}
                onMouseDown={(e) => e.preventDefault()}
                onClick={() => handleSelect(item)}
                onMouseEnter={() => setSelectedIndex(idx)}
              >
                <div className={cn('notion-slash-icon', item.isAi && 'notion-slash-icon-ai')}>
                  <item.icon className="w-4 h-4" />
                </div>
                <div className="notion-slash-content">
                  <span className="notion-slash-title">{item.title}</span>
                  <span className="notion-slash-desc">{item.description}</span>
                </div>
                {item.shortcut && (
                  <span className="notion-slash-shortcut">{item.shortcut}</span>
                )}
              </button>
            )
          })}
        </div>
      ))}
    </div>,
    document.body
  )
}

