'use client'

import { useState, useEffect, useRef, useCallback, useTransition } from 'react'
import { Note, CheckItem, NOTE_COLORS, NoteColor } from '@/lib/types'
import { Button } from '@/components/ui/button'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover'
import { LabelBadge } from '@/components/label-badge'
import { EditorConnectionsSection } from '@/components/editor-connections-section'
import { FusionModal } from '@/components/fusion-modal'
import { ComparisonModal } from '@/components/comparison-modal'
import { useLanguage } from '@/lib/i18n'
import { cn } from '@/lib/utils'
import {
  updateNote,
  togglePin,
  toggleArchive,
  updateColor,
  deleteNote,
  createNote,
} from '@/app/actions/notes'
import { fetchLinkMetadata } from '@/app/actions/scrape'
import {
  Pin,
  Palette,
  Archive,
  ArchiveRestore,
  Trash2,
  ImageIcon,
  Link as LinkIcon,
  X,
  Plus,
  CheckSquare,
  FileText,
  Eye,
  Sparkles,
  Loader2,
  Check,
  Wand2,
  AlignLeft,
  Minimize2,
  Lightbulb,
  RotateCcw,
  Languages,
  ChevronRight,
} from 'lucide-react'
import { toast } from 'sonner'
import { MarkdownContent } from '@/components/markdown-content'
import { EditorImages } from '@/components/editor-images'
import { useAutoTagging } from '@/hooks/use-auto-tagging'
import { GhostTags } from '@/components/ghost-tags'
import { useTitleSuggestions } from '@/hooks/use-title-suggestions'
import { TitleSuggestions } from '@/components/title-suggestions'
import { useLabels } from '@/context/LabelContext'
import { useNoteRefresh } from '@/context/NoteRefreshContext'
import { formatDistanceToNow } from 'date-fns'
import { fr } from 'date-fns/locale/fr'
import { enUS } from 'date-fns/locale/en-US'

interface NoteInlineEditorProps {
  note: Note
  onDelete?: (noteId: string) => void
  onArchive?: (noteId: string) => void
  onChange?: (noteId: string, fields: Partial<Note>) => void
  colorKey: NoteColor
  /** If true and the note is a Markdown note, open directly in preview mode */
  defaultPreviewMode?: boolean
}

function getDateLocale(language: string) {
  if (language === 'fr') return fr;
  if (language === 'fa') return require('date-fns/locale').faIR;
  return enUS;
}

/** Save content via REST API (not Server Action) to avoid Next.js implicit router re-renders */
async function saveInline(
  id: string,
  data: { title?: string | null; content?: string; checkItems?: CheckItem[]; isMarkdown?: boolean }
) {
  await fetch(`/api/notes/${id}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })
}

export function NoteInlineEditor({
  note,
  onDelete,
  onArchive,
  onChange,
  colorKey,
  defaultPreviewMode = false,
}: NoteInlineEditorProps) {
  const { t, language } = useLanguage()
  const { labels: globalLabels, addLabel } = useLabels()
  const [, startTransition] = useTransition()
  const { triggerRefresh } = useNoteRefresh()

  // ── Local edit state ──────────────────────────────────────────────────────
  const [title, setTitle] = useState(note.title || '')
  const [content, setContent] = useState(note.content || '')
  const [checkItems, setCheckItems] = useState<CheckItem[]>(note.checkItems || [])
  const [isMarkdown, setIsMarkdown] = useState(note.isMarkdown || false)
  const [showMarkdownPreview, setShowMarkdownPreview] = useState(
    defaultPreviewMode && (note.isMarkdown || false)
  )
  const [isDirty, setIsDirty] = useState(false)
  const [isSaving, setIsSaving] = useState(false)
  const [dismissedTags, setDismissedTags] = useState<string[]>([])
  const [fusionNotes, setFusionNotes] = useState<Array<Partial<Note>>>([])
  const [comparisonNotes, setComparisonNotes] = useState<Array<Partial<Note>>>([])

  const changeTitle = (t: string) => { setTitle(t); onChange?.(note.id, { title: t }) }
  const changeContent = (c: string) => { setContent(c); onChange?.(note.id, { content: c }) }
  const changeCheckItems = (ci: CheckItem[]) => { setCheckItems(ci); onChange?.(note.id, { checkItems: ci }) }

  // Link dialog
  const [linkUrl, setLinkUrl] = useState('')
  const [showLinkInput, setShowLinkInput] = useState(false)
  const [isAddingLink, setIsAddingLink] = useState(false)

  // AI popover
  const [aiOpen, setAiOpen] = useState(false)
  const [isProcessingAI, setIsProcessingAI] = useState(false)
  // Undo after AI: saves content before transformation
  const [previousContent, setPreviousContent] = useState<string | null>(null)
  // Translate sub-panel
  const [showTranslate, setShowTranslate] = useState(false)

  const fileInputRef = useRef<HTMLInputElement>(null)
  const saveTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
  const pendingRef = useRef({ title, content, checkItems, isMarkdown })
  const noteIdRef = useRef(note.id)

  // Title suggestions
  const [dismissedTitleSuggestions, setDismissedTitleSuggestions] = useState(false)
  const { suggestions: titleSuggestions, isAnalyzing: isAnalyzingTitles } = useTitleSuggestions({
    content: note.type === 'text' ? content : '',
    enabled: note.type === 'text' && !title
  })

  // Keep pending ref in sync for unmount save
  useEffect(() => {
    pendingRef.current = { title, content, checkItems, isMarkdown }
  }, [title, content, checkItems, isMarkdown])

  // ── Sync when selected note switches ─────────────────────────────────────
  useEffect(() => {
    // Flush unsaved changes for the PREVIOUS note before switching
    if (isDirty && noteIdRef.current !== note.id) {
      const { title: t, content: c, checkItems: ci, isMarkdown: im } = pendingRef.current
      saveInline(noteIdRef.current, {
        title: t.trim() || null,
        content: c,
        checkItems: note.type === 'checklist' ? ci : undefined,
        isMarkdown: im,
      }).catch(() => {})
    }

    noteIdRef.current = note.id
    setTitle(note.title || '')
    setContent(note.content || '')
    setCheckItems(note.checkItems || [])
    setIsMarkdown(note.isMarkdown || false)
    setShowMarkdownPreview(defaultPreviewMode && (note.isMarkdown || false))
    setIsDirty(false)
    setDismissedTitleSuggestions(false)
    clearTimeout(saveTimerRef.current)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [note.id])

  // ── Auto-save (1.5 s debounce, skipContentTimestamp) ─────────────────────
  const scheduleSave = useCallback(() => {
    setIsDirty(true)
    clearTimeout(saveTimerRef.current)
    saveTimerRef.current = setTimeout(async () => {
      const { title: t, content: c, checkItems: ci, isMarkdown: im } = pendingRef.current
      setIsSaving(true)
      try {
        await saveInline(noteIdRef.current, {
          title: t.trim() || null,
          content: c,
          checkItems: note.type === 'checklist' ? ci : undefined,
          isMarkdown: im,
        })
        setIsDirty(false)
      } catch {
        // silent — retry on next keystroke
      } finally {
        setIsSaving(false)
      }
    }, 1500)
  }, [note.type])

  // Flush on unmount
  useEffect(() => {
    return () => {
      clearTimeout(saveTimerRef.current)
      const { title: t, content: c, checkItems: ci, isMarkdown: im } = pendingRef.current
      saveInline(noteIdRef.current, {
        title: t.trim() || null,
        content: c,
        checkItems: note.type === 'checklist' ? ci : undefined,
        isMarkdown: im,
      }).catch(() => {})
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // ── Auto-tagging ──────────────────────────────────────────────────────────
  const { suggestions, isAnalyzing } = useAutoTagging({
    content: note.type === 'text' ? content : '',
    notebookId: note.notebookId,
    enabled: note.type === 'text',
  })
  const existingLabelsLower = (note.labels || []).map((l) => l.toLowerCase())
  const filteredSuggestions = suggestions.filter(
    (s) => s?.tag && !dismissedTags.includes(s.tag) && !existingLabelsLower.includes(s.tag.toLowerCase())
  )
  const handleSelectGhostTag = async (tag: string) => {
    const exists = (note.labels || []).some((l) => l.toLowerCase() === tag.toLowerCase())
    if (!exists) {
      const newLabels = [...(note.labels || []), tag]
      // Optimistic UI — update sidebar immediately, no page refresh needed
      onChange?.(note.id, { labels: newLabels })
      await updateNote(note.id, { labels: newLabels }, { skipRevalidation: true })
      const globalExists = globalLabels.some((l) => l.name.toLowerCase() === tag.toLowerCase())
      if (!globalExists) {
        try { await addLabel(tag) } catch {}
      }
      toast.success(t('ai.tagAdded', { tag }))
    }
  }

  const fetchNotesByIds = async (noteIds: string[]) => {
    const fetched = await Promise.all(noteIds.map(async (id) => {
      try {
        const res = await fetch(`/api/notes/${id}`)
        if (!res.ok) return null
        const data = await res.json()
        return data.success && data.data ? data.data : null
      } catch { return null }
    }))
    return fetched.filter((n: any) => n !== null) as Array<Partial<Note>>
  }

  const handleMergeNotes = async (noteIds: string[]) => {
    setFusionNotes(await fetchNotesByIds(noteIds))
  }

  const handleCompareNotes = async (noteIds: string[]) => {
    setComparisonNotes(await fetchNotesByIds(noteIds))
  }

  const handleConfirmFusion = async ({ title, content }: { title: string; content: string }, options: { archiveOriginals: boolean; keepAllTags: boolean; useLatestTitle: boolean; createBacklinks: boolean }) => {
    await createNote({
      title,
      content,
      labels: options.keepAllTags
        ? [...new Set(fusionNotes.flatMap(n => n.labels || []))]
        : fusionNotes[0].labels || [],
      color: fusionNotes[0].color,
      type: 'text',
      isMarkdown: true,
      autoGenerated: true,
      aiProvider: 'fusion',
      notebookId: fusionNotes[0].notebookId ?? undefined
    })
    if (options.archiveOriginals) {
      for (const n of fusionNotes) {
        if (n.id) await updateNote(n.id, { isArchived: true })
      }
    }
    toast.success(t('toast.notesFusionSuccess'))
    setFusionNotes([])
    triggerRefresh()
  }

  // ── Quick actions (pin, archive, color, delete) ───────────────────────────
  const handleTogglePin = () => {
    startTransition(async () => {
      // Optimitistic update
      onChange?.(note.id, { isPinned: !note.isPinned })
      // Call with skipRevalidation to avoid server layout refresh interfering with optimistic state
      await updateNote(note.id, { isPinned: !note.isPinned }, { skipRevalidation: true })
      toast.success(note.isPinned ? t('notes.unpinned') || 'Désépinglée' : t('notes.pinned') || 'Épinglée')
    })
  }

  const handleToggleArchive = () => {
    startTransition(async () => {
      onArchive?.(note.id)
      await updateNote(note.id, { isArchived: !note.isArchived }, { skipRevalidation: true })
    })
  }

  const handleColorChange = (color: string) => {
    startTransition(async () => {
      onChange?.(note.id, { color })
      await updateNote(note.id, { color }, { skipRevalidation: true })
    })
  }

  const handleDelete = () => {
    if (!confirm(t('notes.confirmDelete'))) return
    startTransition(async () => {
      await deleteNote(note.id)
      onDelete?.(note.id)
    })
  }

  // ── Image upload ──────────────────────────────────────────────────────────
  const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files
    if (!files) return
    for (const file of Array.from(files)) {
      const formData = new FormData()
      formData.append('file', file)
      try {
        const res = await fetch('/api/upload', { method: 'POST', body: formData })
        if (!res.ok) throw new Error('Upload failed')
        const data = await res.json()
        const newImages = [...(note.images || []), data.url]
        onChange?.(note.id, { images: newImages })
        await updateNote(note.id, { images: newImages })
      } catch {
        toast.error(t('notes.uploadFailed', { filename: file.name }))
      }
    }
    if (fileInputRef.current) fileInputRef.current.value = ''
  }

  const handleRemoveImage = async (index: number) => {
    const newImages = (note.images || []).filter((_, i) => i !== index)
    onChange?.(note.id, { images: newImages })
    await updateNote(note.id, { images: newImages })
  }

  // ── Link ──────────────────────────────────────────────────────────────────
  const handleAddLink = async () => {
    if (!linkUrl) return
    setIsAddingLink(true)
    try {
      const metadata = await fetchLinkMetadata(linkUrl)
      const newLink = metadata || { url: linkUrl, title: linkUrl }
      const newLinks = [...(note.links || []), newLink]
      onChange?.(note.id, { links: newLinks })
      await updateNote(note.id, { links: newLinks })
      toast.success(t('notes.linkAdded'))
    } catch {
      toast.error(t('notes.linkAddFailed'))
    } finally {
      setLinkUrl('')
      setShowLinkInput(false)
      setIsAddingLink(false)
    }
  }

  const handleRemoveLink = async (index: number) => {
    const newLinks = (note.links || []).filter((_, i) => i !== index)
    onChange?.(note.id, { links: newLinks })
    await updateNote(note.id, { links: newLinks })
  }

  // ── AI actions (called from Popover in toolbar) ───────────────────────────
  const callAI = async (option: 'clarify' | 'shorten' | 'improve') => {
    const wc = content.split(/\s+/).filter(Boolean).length
    if (!content || wc < 10) {
      toast.error(t('ai.reformulationMinWords', { count: wc }))
      return
    }
    setAiOpen(false)
    setShowTranslate(false)
    setPreviousContent(content) // save for undo
    setIsProcessingAI(true)
    try {
      const res = await fetch('/api/ai/reformulate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ text: content, option }),
      })
      const data = await res.json()
      if (!res.ok) throw new Error(data.error || 'Failed to reformulate')
      changeContent(data.reformulatedText || data.text)
      scheduleSave()
      toast.success(t('ai.reformulationApplied'))
    } catch {
      toast.error(t('ai.reformulationFailed'))
      setPreviousContent(null)
    } finally {
      setIsProcessingAI(false)
    }
  }

  const callTranslate = async (targetLanguage: string) => {
    const wc = content.split(/\s+/).filter(Boolean).length
    if (!content || wc < 3) { toast.error(t('ai.reformulationMinWords', { count: wc })); return }
    setAiOpen(false)
    setShowTranslate(false)
    setPreviousContent(content)
    setIsProcessingAI(true)
    try {
      const res = await fetch('/api/ai/translate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ text: content, targetLanguage }),
      })
      const data = await res.json()
      if (!res.ok) throw new Error(data.error || 'Translation failed')
      changeContent(data.translatedText)
      scheduleSave()
      toast.success(t('ai.translationApplied') || `Traduit en ${targetLanguage}`)
    } catch {
      toast.error(t('ai.translationFailed') || 'Traduction échouée')
      setPreviousContent(null)
    } finally {
      setIsProcessingAI(false)
    }
  }

  const handleTransformMarkdown = async () => {
    const wc = content.split(/\s+/).filter(Boolean).length
    if (!content || wc < 10) { toast.error(t('ai.reformulationMinWords', { count: wc })); return }
    setAiOpen(false)
    setShowTranslate(false)
    setPreviousContent(content)
    setIsProcessingAI(true)
    try {
      const res = await fetch('/api/ai/transform-markdown', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ text: content }),
      })
      const data = await res.json()
      if (!res.ok) throw new Error(data.error)
      changeContent(data.transformedText)
      setIsMarkdown(true)
      scheduleSave()
      toast.success(t('ai.transformSuccess'))
    } catch {
      toast.error(t('ai.transformError'))
      setPreviousContent(null)
    } finally {
      setIsProcessingAI(false)
    }
  }

  // ── Checklist helpers ─────────────────────────────────────────────────────
  const handleToggleCheckItem = (id: string) => {
    const updated = checkItems.map((ci) =>
      ci.id === id ? { ...ci, checked: !ci.checked } : ci
    )
    setCheckItems(updated)
    scheduleSave()
  }

  const handleUpdateCheckText = (id: string, text: string) => {
    const updated = checkItems.map((ci) => (ci.id === id ? { ...ci, text } : ci))
    setCheckItems(updated)
    scheduleSave()
  }

  const handleAddCheckItem = () => {
    const updated = [...checkItems, { id: Date.now().toString(), text: '', checked: false }]
    setCheckItems(updated)
    scheduleSave()
  }

  const handleRemoveCheckItem = (id: string) => {
    const updated = checkItems.filter((ci) => ci.id !== id)
    setCheckItems(updated)
    scheduleSave()
  }

  const dateLocale = getDateLocale(language)

  return (
    <div className="flex h-full flex-col overflow-hidden">

      {/* ── Toolbar ────────────────────────────────────────────────────────── */}
      <div className="flex shrink-0 items-center justify-between border-b border-border/30 px-4 py-2">
        <div className="flex items-center gap-1">
          {/* Image upload */}
          <Button
            variant="ghost" size="sm" className="h-8 w-8 p-0"
            title={t('notes.addImage') || 'Ajouter une image'}
            onClick={() => fileInputRef.current?.click()}
          >
            <ImageIcon className="h-4 w-4" />
          </Button>
          <input ref={fileInputRef} type="file" accept="image/*" multiple className="hidden" onChange={handleImageUpload} />

          {/* Link */}
          <Button
            variant="ghost" size="sm" className="h-8 w-8 p-0"
            title={t('notes.addLink') || 'Ajouter un lien'}
            onClick={() => setShowLinkInput(!showLinkInput)}
          >
            <LinkIcon className="h-4 w-4" />
          </Button>

          {/* Markdown toggle */}
          <Button
            variant="ghost" size="sm"
            className={cn('h-8 gap-1 px-2 text-xs', isMarkdown && 'text-primary')}
            onClick={() => { setIsMarkdown(!isMarkdown); if (isMarkdown) setShowMarkdownPreview(false); scheduleSave() }}
            title="Markdown"
          >
            <FileText className="h-3.5 w-3.5" />
            <span className="hidden sm:inline">MD</span>
          </Button>

          {isMarkdown && (
            <Button
              variant="ghost" size="sm" className="h-8 gap-1 px-2 text-xs"
              onClick={() => setShowMarkdownPreview(!showMarkdownPreview)}
            >
              <Eye className="h-3.5 w-3.5" />
              <span className="hidden sm:inline">{showMarkdownPreview ? t('notes.edit') || 'Éditer' : t('notes.preview') || 'Aperçu'}</span>
            </Button>
          )}

          {/* ── AI Popover (in toolbar, non-intrusive) ─────────────────────── */}
          {note.type === 'text' && (
            <Popover open={aiOpen} onOpenChange={(o) => { setAiOpen(o); if (!o) setShowTranslate(false) }}>
              <PopoverTrigger asChild>
                <Button
                  variant="ghost" size="sm"
                  className={cn(
                    'h-8 gap-1.5 px-2 text-xs transition-colors',
                    isProcessingAI && 'text-primary',
                    aiOpen && 'bg-muted text-primary',
                  )}
                  disabled={isProcessingAI}
                  title="Assistant IA"
                >
                  {isProcessingAI
                    ? <Loader2 className="h-3.5 w-3.5 animate-spin" />
                    : <Sparkles className="h-3.5 w-3.5" />
                  }
                  <span className="hidden sm:inline">IA</span>
                </Button>
              </PopoverTrigger>
              <PopoverContent align="start" className="w-56 p-1">
                {!showTranslate ? (
                  <div className="flex flex-col gap-0.5">
                    <button type="button"
                      className="flex items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-muted text-left"
                      onClick={() => callAI('clarify')}
                    >
                      <Lightbulb className="h-4 w-4 text-amber-500 shrink-0" />
                      <div>
                        <p className="font-medium">{t('ai.clarify') || 'Clarifier'}</p>
                        <p className="text-[11px] text-muted-foreground">{t('ai.clarifyDesc') || 'Rendre plus clair'}</p>
                      </div>
                    </button>
                    <button type="button"
                      className="flex items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-muted text-left"
                      onClick={() => callAI('shorten')}
                    >
                      <Minimize2 className="h-4 w-4 text-blue-500 shrink-0" />
                      <div>
                        <p className="font-medium">{t('ai.shorten') || 'Raccourcir'}</p>
                        <p className="text-[11px] text-muted-foreground">{t('ai.shortenDesc') || 'Version concise'}</p>
                      </div>
                    </button>
                    <button type="button"
                      className="flex items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-muted text-left"
                      onClick={() => callAI('improve')}
                    >
                      <AlignLeft className="h-4 w-4 text-emerald-500 shrink-0" />
                      <div>
                        <p className="font-medium">{t('ai.improve') || 'Améliorer'}</p>
                        <p className="text-[11px] text-muted-foreground">{t('ai.improveDesc') || 'Meilleure rédaction'}</p>
                      </div>
                    </button>
                    <button type="button"
                      className="flex items-center justify-between gap-2 rounded-md px-3 py-2 text-sm hover:bg-muted text-left w-full"
                      onClick={() => setShowTranslate(true)}
                    >
                      <div className="flex items-center gap-2">
                        <Languages className="h-4 w-4 text-sky-500 shrink-0" />
                        <div>
                          <p className="font-medium">{t('ai.translate') || 'Traduire'}</p>
                          <p className="text-[11px] text-muted-foreground">{t('ai.translateDesc') || 'Changer la langue'}</p>
                        </div>
                      </div>
                      <ChevronRight className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
                    </button>
                    <div className="my-0.5 border-t border-border/40" />
                    <button type="button"
                      className="flex items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-muted text-left"
                      onClick={handleTransformMarkdown}
                    >
                      <Wand2 className="h-4 w-4 text-violet-500 shrink-0" />
                      <div>
                        <p className="font-medium">{t('ai.toMarkdown') || 'En Markdown'}</p>
                        <p className="text-[11px] text-muted-foreground">{t('ai.toMarkdownDesc') || 'Formater en MD'}</p>
                      </div>
                    </button>
                  </div>
                ) : (
                  <div className="flex flex-col gap-0.5">
                    <button type="button"
                      className="flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground"
                      onClick={() => setShowTranslate(false)}
                    >
                      <RotateCcw className="h-3 w-3" />
                      {t('ai.translateBack') || 'Retour'}
                    </button>
                    <div className="my-0.5 border-t border-border/40" />
                    {[
                      { code: 'French', label: 'Français 🇫🇷' },
                      { code: 'English', label: 'English 🇬🇧' },
                      { code: 'Persian', label: 'فارسی 🇮🇷' },
                      { code: 'Spanish', label: 'Español 🇪🇸' },
                      { code: 'German', label: 'Deutsch 🇩🇪' },
                      { code: 'Italian', label: 'Italiano 🇮🇹' },
                      { code: 'Portuguese', label: 'Português 🇵🇹' },
                      { code: 'Arabic', label: 'العربية 🇸🇦' },
                      { code: 'Chinese', label: '中文 🇨🇳' },
                      { code: 'Japanese', label: '日本語 🇯🇵' },
                    ].map(({ code, label }) => (
                      <button key={code} type="button"
                        className="w-full rounded-md px-3 py-1.5 text-sm hover:bg-muted text-left"
                        onClick={() => callTranslate(code)}
                      >
                        {label}
                      </button>
                    ))}
                  </div>
                )}
              </PopoverContent>
            </Popover>
          )}

          {/* ── Undo AI button ─────────────────────────────────────────────── */}
          {previousContent !== null && (
            <Button
              variant="ghost" size="sm"
              className="h-8 gap-1.5 px-2 text-xs text-amber-600 hover:text-amber-700 hover:bg-amber-50 dark:hover:bg-amber-950/30"
              title={t('ai.undoAI') || 'Annuler transformation IA'}
              onClick={() => {
                changeContent(previousContent)
                setPreviousContent(null)
                scheduleSave()
                toast.info(t('ai.undoApplied') || 'Texte original restauré')
              }}
            >
              <RotateCcw className="h-3.5 w-3.5" />
              <span className="hidden sm:inline">{t('ai.undo') || 'Annuler IA'}</span>
            </Button>
          )}
        </div>

        <div className="flex items-center gap-1">
          {/* Save status indicator */}
          <span className="mr-1 flex items-center gap-1 text-[11px] text-muted-foreground/50 select-none">
            {isSaving ? (
              <><Loader2 className="h-3 w-3 animate-spin" /> Sauvegarde…</>
            ) : isDirty ? (
              <><span className="h-1.5 w-1.5 rounded-full bg-amber-400" /> Modifié</>
            ) : (
              <><Check className="h-3 w-3 text-emerald-500" /> Sauvegardé</>
            )}
          </span>

          {/* Pin */}
          <Button variant="ghost" size="sm" className="h-8 w-8 p-0"
            title={note.isPinned ? t('notes.unpin') : t('notes.pin')} onClick={handleTogglePin}>
            <Pin className={cn('h-4 w-4', note.isPinned && 'fill-current text-primary')} />
          </Button>

          {/* Color picker */}
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" size="sm" className="h-8 w-8 p-0" title={t('notes.changeColor')}>
                <Palette className="h-4 w-4" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <div className="grid grid-cols-5 gap-2 p-2">
                {Object.entries(NOTE_COLORS).map(([name, cls]) => (
                  <button type="button"
                    key={name}
                    className={cn(
                      'h-7 w-7 rounded-full border-2 transition-transform hover:scale-110',
                      cls.bg,
                      note.color === name ? 'border-gray-900 dark:border-gray-100' : 'border-gray-300 dark:border-gray-700'
                    )}
                    onClick={() => handleColorChange(name)}
                    title={name}
                  />
                ))}
              </div>
            </DropdownMenuContent>
          </DropdownMenu>

          {/* More actions */}
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" size="sm" className="h-8 w-8 p-0" title={t('notes.moreOptions')}>
                <span className="text-base leading-none text-muted-foreground">⋯</span>
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuItem onClick={handleToggleArchive}>
                {note.isArchived
                  ? <><ArchiveRestore className="h-4 w-4 mr-2" />{t('notes.unarchive')}</>
                  : <><Archive className="h-4 w-4 mr-2" />{t('notes.archive')}</>}
              </DropdownMenuItem>
              <DropdownMenuSeparator />
              <DropdownMenuItem className="text-red-600 dark:text-red-400" onClick={handleDelete}>
                <Trash2 className="h-4 w-4 mr-2" />{t('notes.delete')}
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </div>

      {/* ── Link input bar (inline) ───────────────────────────────────────── */}
      {showLinkInput && (
        <div className="flex shrink-0 items-center gap-2 border-b border-border/30 bg-muted/30 px-4 py-2">
          <input
            type="url"
            className="flex-1 rounded-md border border-border/60 bg-background px-3 py-1.5 text-sm outline-none focus:border-primary"
            placeholder="https://..."
            value={linkUrl}
            onChange={(e) => setLinkUrl(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') handleAddLink() }}
            autoFocus
          />
          <Button size="sm" disabled={!linkUrl || isAddingLink} onClick={handleAddLink}>
            {isAddingLink ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Ajouter'}
          </Button>
          <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={() => { setShowLinkInput(false); setLinkUrl('') }}>
            <X className="h-4 w-4" />
          </Button>
        </div>
      )}

      {/* ── Labels strip + AI suggestions — always visible outside scroll area ─ */}
      {((note.labels?.length ?? 0) > 0 || filteredSuggestions.length > 0 || isAnalyzing) && (
        <div className="flex shrink-0 flex-wrap items-center gap-1.5 border-b border-border/20 px-8 py-2">
          {/* Existing labels */}
          {(note.labels ?? []).map((label) => (
            <LabelBadge key={label} label={label} />
          ))}
          {/* AI-suggested tags inline with labels */}
          <GhostTags
            suggestions={filteredSuggestions}
            addedTags={note.labels || []}
            isAnalyzing={isAnalyzing}
            onSelectTag={handleSelectGhostTag}
            onDismissTag={(tag) => setDismissedTags((p) => [...p, tag])}
          />
        </div>
      )}

      {/* ── Scrollable editing area (takes all remaining height) ─────────── */}
      <div className="flex flex-1 flex-col overflow-y-auto px-8 py-5">
        {/* Title row with optional AI suggest button */}
        <div className="group relative flex items-start gap-2 shrink-0">
          <input
            type="text"
            dir="auto"
            className="flex-1 bg-transparent text-2xl font-bold tracking-tight text-foreground outline-none placeholder:text-muted-foreground/40"
            placeholder={t('notes.titlePlaceholder') || 'Titre…'}
            value={title}
            onChange={(e) => { changeTitle(e.target.value); scheduleSave() }}
          />
          {/* AI title suggestion — show when title is empty and there's content */}
          {!title && content.trim().split(/\s+/).filter(Boolean).length >= 5 && (
            <button type="button"
              onClick={async (e) => {
                e.preventDefault()
                setIsProcessingAI(true)
                try {
                  const res = await fetch('/api/ai/suggest-title', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ content }),
                  })
                  if (res.ok) {
                    const data = await res.json()
                    const suggested = data.title || data.suggestedTitle || ''
                    if (suggested) { changeTitle(suggested); scheduleSave() }
                  }
                } catch { /* silent */ } finally { setIsProcessingAI(false) }
              }}
              disabled={isProcessingAI}
              className="mt-1.5 shrink-0 rounded-md p-1 text-muted-foreground/40 opacity-0 transition-all hover:bg-muted hover:text-primary group-hover:opacity-100"
              title="Suggestion de titre par IA"
            >
              {isProcessingAI
                ? <Loader2 className="h-4 w-4 animate-spin" />
                : <Sparkles className="h-4 w-4" />}
            </button>
          )}
        </div>

        {/* Title Suggestions Dropdown / Inline list */}
        {!title && !dismissedTitleSuggestions && titleSuggestions.length > 0 && (
          <div className="mt-2 text-sm shrink-0">
            <TitleSuggestions
              suggestions={titleSuggestions}
              onSelect={(selectedTitle) => { changeTitle(selectedTitle); scheduleSave() }}
              onDismiss={() => setDismissedTitleSuggestions(true)}
            />
          </div>
        )}

        {/* Images */}
        {Array.isArray(note.images) && note.images.length > 0 && (
          <div className="mt-4">
            <EditorImages images={note.images} onRemove={handleRemoveImage} />
          </div>
        )}

        {/* Link previews */}
        {Array.isArray(note.links) && note.links.length > 0 && (
          <div className="mt-4 flex flex-col gap-2">
            {note.links.map((link, idx) => (
              <div key={idx} className="group relative flex overflow-hidden rounded-xl border border-border/60 bg-background/60">
                {link.imageUrl && (
                  <div className="h-auto w-24 shrink-0 bg-cover bg-center" style={{ backgroundImage: `url(${link.imageUrl})` }} />
                )}
                <div className="flex min-w-0 flex-col justify-center gap-0.5 p-3">
                  <p className="truncate text-sm font-medium">{link.title || link.url}</p>
                  {link.description && <p className="line-clamp-1 text-xs text-muted-foreground">{link.description}</p>}
                  <a href={link.url} target="_blank" rel="noopener noreferrer" className="text-[11px] text-primary hover:underline">
                    {(() => { try { return new URL(link.url).hostname } catch { return link.url } })()}
                  </a>
                </div>
                <button type="button"
                  className="absolute right-2 top-2 rounded-full bg-background/80 p-1 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-destructive/10"
                  onClick={() => handleRemoveLink(idx)}
                >
                  <X className="h-3 w-3" />
                </button>
              </div>
            ))}
          </div>
        )}

        {/* ── Text / Checklist content ───────────────────────────────────── */}
        <div className="mt-4 flex flex-1 flex-col">
          {note.type === 'text' ? (
            <div className="flex flex-1 flex-col">
              {showMarkdownPreview && isMarkdown ? (
                <div className="prose prose-sm dark:prose-invert max-w-none flex-1 rounded-lg border border-border/40 bg-muted/20 p-4">
                  <MarkdownContent content={content || ''} />
                </div>
              ) : (
                <textarea
                  dir="auto"
                  className="flex-1 w-full resize-none bg-transparent text-sm leading-relaxed text-foreground outline-none placeholder:text-muted-foreground/40"
                  placeholder={isMarkdown
                    ? t('notes.takeNoteMarkdown') || 'Écris en Markdown…'
                    : t('notes.takeNote') || 'Écris quelque chose…'
                  }
                  value={content}
                  onChange={(e) => { changeContent(e.target.value); scheduleSave() }}
                  style={{ minHeight: '200px' }}
                />
              )}

              {/* Ghost tag suggestions are now shown in the top labels strip */}
            </div>
          ) : (
            /* Checklist */
            <div className="space-y-1">
              {checkItems.filter((ci) => !ci.checked).map((ci, index) => (
                <div key={ci.id} className="group flex items-center gap-2 rounded-lg px-2 py-1 transition-colors hover:bg-muted/30">
                  <button type="button"
                    className="flex h-4 w-4 shrink-0 items-center justify-center rounded border border-border/60 transition-colors hover:border-primary"
                    onClick={() => handleToggleCheckItem(ci.id)}
                  />
                  <input
                    dir="auto"
                    className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground/40"
                    value={ci.text}
                    placeholder={t('notes.listItem') || 'Élément…'}
                    onChange={(e) => handleUpdateCheckText(ci.id, e.target.value)}
                  />
                  <button type="button" className="opacity-0 group-hover:opacity-100 transition-opacity" onClick={() => handleRemoveCheckItem(ci.id)}>
                    <X className="h-3.5 w-3.5 text-muted-foreground/60" />
                  </button>
                </div>
              ))}

              <button type="button"
                className="flex items-center gap-2 px-2 py-1 text-sm text-muted-foreground/60 hover:text-foreground"
                onClick={handleAddCheckItem}
              >
                <Plus className="h-4 w-4" />
                {t('notes.addItem') || 'Ajouter un élément'}
              </button>

              {checkItems.filter((ci) => ci.checked).length > 0 && (
                <div className="mt-3">
                  <p className="mb-1 px-2 text-xs text-muted-foreground/40 uppercase tracking-wider">
                    Complétés ({checkItems.filter((ci) => ci.checked).length})
                  </p>
                  {checkItems.filter((ci) => ci.checked).map((ci) => (
                    <div key={ci.id} className="group flex items-center gap-2 rounded-lg px-2 py-1 text-muted-foreground transition-colors hover:bg-muted/20">
                      <button type="button"
                        className="flex h-4 w-4 shrink-0 items-center justify-center rounded border border-border/40 bg-muted/40"
                        onClick={() => handleToggleCheckItem(ci.id)}
                      >
                        <CheckSquare className="h-3 w-3 opacity-60" />
                      </button>
                      <span dir="auto" className="flex-1 text-sm line-through">{ci.text}</span>
                      <button type="button" className="opacity-0 group-hover:opacity-100 transition-opacity" onClick={() => handleRemoveCheckItem(ci.id)}>
                        <X className="h-3.5 w-3.5" />
                      </button>
                    </div>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>
      </div>

      {/* ── Memory Echo Connections Section ── */}
      <EditorConnectionsSection
        noteId={note.id}
        onOpenNote={(connNoteId) => {
          window.open(`/?note=${connNoteId}`, '_blank')
        }}
        onCompareNotes={handleCompareNotes}
        onMergeNotes={handleMergeNotes}
      />

      {/* ── Footer ───────────────────────────────────────────────────────────── */}
      <div className="shrink-0 border-t border-border/20 px-8 py-2">
        <div className="flex items-center gap-3 text-[11px] text-muted-foreground/40">
          <span>{t('notes.modified') || 'Modifiée'} {formatDistanceToNow(new Date(note.updatedAt), { addSuffix: true, locale: dateLocale })}</span>
          <span>·</span>
          <span>{t('notes.created') || 'Créée'} {formatDistanceToNow(new Date(note.createdAt), { addSuffix: true, locale: dateLocale })}</span>
        </div>
      </div>

      {/* Fusion Modal */}
      {fusionNotes.length > 0 && (
        <FusionModal
          isOpen={fusionNotes.length > 0}
          onClose={() => setFusionNotes([])}
          notes={fusionNotes}
          onConfirmFusion={handleConfirmFusion}
        />
      )}

      {/* Comparison Modal */}
      {comparisonNotes.length > 0 && (
        <ComparisonModal
          isOpen={comparisonNotes.length > 0}
          onClose={() => setComparisonNotes([])}
          notes={comparisonNotes}
        />
      )}
    </div>
  )
}
