"use client";

import React, { useRef, useState, useEffect } from "react";
import {
  Undo, Redo, Bold, Italic,
  AlignLeft, AlignCenter, AlignRight, AlignJustify,
  Outdent, Indent,
  ChevronDown, LayoutTemplate, Code2
} from "lucide-react";
import { cn } from "@/shared/lib/utils";
import { Button } from "@/presentation/components/ui/button";
import type { HelpArticleBlock } from "@/domain/entities/help-article";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuTrigger,
  DropdownMenuSeparator,
} from "@/presentation/components/ui/dropdown-menu";

interface RichTextEditorProps {
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  className?: string;
  /** Layout blocks insertable at the caret (see `useHelpArticleBlocks`). */
  blocks?: HelpArticleBlock[];
  /** Whole-article skeletons, offered while the editor is empty. */
  templates?: HelpArticleBlock[];
}

/**
 * Returns the step blocks of an article, in document order.
 *
 * Blocks inserted from the library carry `data-hc="step"`. Articles written before that marker
 * existed — everything the demo seeder produced — are matched on their shape instead: a table whose
 * first cell holds nothing but a numbered badge.
 */
function findStepBlocks(root: HTMLElement): HTMLTableElement[] {
  return Array.from(root.querySelectorAll("table")).filter((table) => {
    if (table.getAttribute("data-hc") === "step") return true;
    const badge = table.querySelector("tr > td:first-child > div");
    return !!badge && /^\d+$/.test((badge.textContent || "").trim());
  });
}

/**
 * Strip the markup Word and Outlook attach to a copy/paste.
 *
 * The help centre prints article bodies with no stylesheet of its own, so `class` attributes carry
 * nothing — a pasted `MsoNormal` body only looks like a Word document. Inline styles are kept: they
 * are what the layout is made of.
 */
function cleanPastedHtml(html: string): string {
  const doc = new DOMParser().parseFromString(html, "text/html");

  doc.querySelectorAll("style, meta, link, xml, script").forEach((el) => el.remove());

  // Word's conditional comments (<!--[if gte mso 9]>…), plus any other comment node.
  const comments = doc.createTreeWalker(doc.body, NodeFilter.SHOW_COMMENT);
  const stale: Comment[] = [];
  let comment: Node | null;
  while ((comment = comments.nextNode())) stale.push(comment as Comment);
  stale.forEach((c) => c.remove());

  doc.body.querySelectorAll("*").forEach((el) => {
    // Namespaced Office elements (<o:p>, <w:sdt>, …) survive parsing as unknown tags: unwrap them.
    if (el.tagName.includes(":")) {
      el.replaceWith(...Array.from(el.childNodes));
      return;
    }

    el.removeAttribute("class");
    el.removeAttribute("lang");

    const style = el.getAttribute("style");
    if (style) {
      const kept = style
        .split(";")
        .map((rule) => rule.trim())
        .filter((rule) => rule.length > 0 && !/^mso-/i.test(rule))
        .join(";");
      if (kept) el.setAttribute("style", `${kept};`);
      else el.removeAttribute("style");
    }
  });

  return doc.body.innerHTML;
}

export function RichTextEditor({ value, onChange, placeholder, className, blocks, templates }: RichTextEditorProps) {
  const editorRef = useRef<HTMLDivElement>(null);
  const [isFocused, setIsFocused] = useState(false);
  const [savedRange, setSavedRange] = useState<Range | null>(null);
  const [activeFormats, setActiveFormats] = useState<Record<string, boolean>>({});
  const [activeBlock, setActiveBlock] = useState("Paragraphe");
  const [showSource, setShowSource] = useState(false);

  const hasLibrary = (blocks?.length ?? 0) > 0 || (templates?.length ?? 0) > 0;

  const updateActiveFormats = () => {
    setActiveFormats({
      bold: document.queryCommandState("bold"),
      italic: document.queryCommandState("italic"),
      justifyLeft: document.queryCommandState("justifyLeft"),
      justifyCenter: document.queryCommandState("justifyCenter"),
      justifyRight: document.queryCommandState("justifyRight"),
      justifyFull: document.queryCommandState("justifyFull"),
    });

    // Determine active block format
    const formatBlock = document.queryCommandValue("formatBlock");
    if (formatBlock) {
      if (formatBlock.includes("h1")) setActiveBlock("Titre 1");
      else if (formatBlock.includes("h2")) setActiveBlock("Titre 2");
      else if (formatBlock.includes("h3")) setActiveBlock("Titre 3");
      else if (formatBlock.includes("h4")) setActiveBlock("Titre 4");
      else setActiveBlock("Paragraphe");
    } else {
      setActiveBlock("Paragraphe");
    }
  };

  const ensureLinksOpenInNewTab = (root: HTMLElement | null) => {
    if (!root) return;
    root.querySelectorAll("a").forEach((a) => {
      a.setAttribute("target", "_blank");
      a.setAttribute("rel", "noopener noreferrer");
    });
  };

  const URL_REGEX_END = /(https?:\/\/[^\s<>"']+|www\.[^\s<>"']+)$/i;
  const URL_REGEX_GLOBAL = /(https?:\/\/[^\s<>"']+|www\.[^\s<>"']+)/gi;

  const isInsideAnchor = (node: Node | null): boolean => {
    let cur: Node | null = node;
    while (cur && cur !== editorRef.current) {
      if ((cur as HTMLElement).tagName === "A") return true;
      cur = cur.parentNode;
    }
    return false;
  };

  const buildAnchor = (raw: string): HTMLAnchorElement => {
    const a = document.createElement("a");
    a.href = raw.startsWith("http") ? raw : `https://${raw}`;
    a.target = "_blank";
    a.rel = "noopener noreferrer";
    a.textContent = raw;
    return a;
  };

  // Linkify the URL just before the caret (called on space keyup).
  const linkifyBeforeCaret = (): boolean => {
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0 || !editorRef.current) return false;
    const range = selection.getRangeAt(0);
    if (!range.collapsed) return false;
    const node = range.startContainer;
    if (node.nodeType !== Node.TEXT_NODE) return false;
    if (isInsideAnchor(node.parentNode)) return false;

    const offset = range.startOffset;
    if (offset < 2) return false;
    const before = (node as Text).data.slice(0, offset - 1);
    const match = before.match(URL_REGEX_END);
    if (!match) return false;

    const url = match[1];
    const urlStart = before.length - url.length;

    const urlRange = document.createRange();
    urlRange.setStart(node, urlStart);
    urlRange.setEnd(node, urlStart + url.length);
    urlRange.deleteContents();

    const anchor = buildAnchor(url);
    urlRange.insertNode(anchor);

    const next = anchor.nextSibling;
    const newRange = document.createRange();
    if (next && next.nodeType === Node.TEXT_NODE) {
      newRange.setStart(next, Math.min(1, (next as Text).data.length));
    } else {
      newRange.setStartAfter(anchor);
    }
    newRange.collapse(true);
    selection.removeAllRanges();
    selection.addRange(newRange);
    setSavedRange(newRange.cloneRange());
    return true;
  };

  // Linkify all URLs anywhere in the editor (called on blur).
  const linkifyAll = (): boolean => {
    if (!editorRef.current) return false;
    const walker = document.createTreeWalker(editorRef.current, NodeFilter.SHOW_TEXT);
    const textNodes: Text[] = [];
    let n: Node | null;
    while ((n = walker.nextNode())) {
      if (isInsideAnchor(n.parentNode)) continue;
      if (/(https?:\/\/|www\.)/i.test((n as Text).data)) textNodes.push(n as Text);
    }
    if (textNodes.length === 0) return false;
    textNodes.forEach((tn) => {
      const text = tn.data;
      const frag = document.createDocumentFragment();
      let lastIdx = 0;
      const re = new RegExp(URL_REGEX_GLOBAL.source, "gi");
      let m: RegExpExecArray | null;
      while ((m = re.exec(text)) !== null) {
        if (m.index > lastIdx) frag.appendChild(document.createTextNode(text.slice(lastIdx, m.index)));
        frag.appendChild(buildAnchor(m[1]));
        lastIdx = m.index + m[1].length;
      }
      if (lastIdx < text.length) frag.appendChild(document.createTextNode(text.slice(lastIdx)));
      tn.parentNode?.replaceChild(frag, tn);
    });
    return true;
  };

  // Synchronize external value changes
  useEffect(() => {
    if (editorRef.current && value !== editorRef.current.innerHTML) {
      if (document.activeElement !== editorRef.current) {
        editorRef.current.innerHTML = value || "";
        ensureLinksOpenInNewTab(editorRef.current);
      }
    }
  }, [value]);

  const saveSelection = () => {
    const selection = window.getSelection();
    if (selection && selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      if (editorRef.current?.contains(range.commonAncestorContainer)) {
        setSavedRange(range.cloneRange());
      }
    }
    updateActiveFormats();
  };

  const restoreSelection = () => {
    if (editorRef.current) {
      editorRef.current.focus();
      if (savedRange) {
        const selection = window.getSelection();
        selection?.removeAllRanges();
        selection?.addRange(savedRange);
      }
    }
  };

  const handleInput = () => {
    if (editorRef.current) {
      ensureLinksOpenInNewTab(editorRef.current);
      onChange(editorRef.current.innerHTML);
    }
  };

  const execCommand = (command: string, val: string | undefined = undefined) => {
    restoreSelection();
    document.execCommand(command, false, val);
    saveSelection();
    updateActiveFormats();
    if (editorRef.current) {
      onChange(editorRef.current.innerHTML);
    }
  };

  const formatBlock = (block: string) => {
    execCommand("formatBlock", block);
  };

  /** Renumber every step badge from 1, so inserting or deleting a step in the middle stays correct. */
  const renumberSteps = () => {
    if (!editorRef.current) return;
    findStepBlocks(editorRef.current).forEach((table, index) => {
      const badge =
        table.querySelector('[data-hc="step-number"]') ??
        table.querySelector("tr > td:first-child > div");
      if (badge) badge.textContent = String(index + 1);
    });
  };

  /** Select the first piece of text of an inserted block, so typing overwrites the placeholder. */
  const selectFirstText = (node: Node) => {
    const root = node.nodeType === Node.ELEMENT_NODE ? (node as HTMLElement) : null;
    const target = root
      ? (document.createTreeWalker(root, NodeFilter.SHOW_TEXT).nextNode() as Text | null)
      : (node as Text);
    if (!target || !target.data.trim()) return;

    const range = document.createRange();
    range.selectNodeContents(target);
    const selection = window.getSelection();
    selection?.removeAllRanges();
    selection?.addRange(range);
    setSavedRange(range.cloneRange());
  };

  /**
   * Drop a block into the article at top level.
   *
   * Not `insertHTML`: the caret usually sits inside a paragraph of another block, and browsers would
   * nest the new table there. The block is inserted after whichever top-level element holds the
   * caret instead — which is also what makes the step numbering predictable.
   */
  const insertBlock = (html: string) => {
    const editor = editorRef.current;
    if (!editor) return;

    const template = document.createElement("template");
    template.innerHTML = html;
    const inserted = Array.from(template.content.childNodes);
    if (inserted.length === 0) return;

    editor.focus();

    let anchor: Node | null = null;
    if (savedRange && editor.contains(savedRange.commonAncestorContainer)) {
      let node: Node | null = savedRange.commonAncestorContainer;
      while (node && node.parentNode && node.parentNode !== editor) node = node.parentNode;
      if (node && node.parentNode === editor) anchor = node;
    }

    const fragment = document.createDocumentFragment();
    inserted.forEach((node) => fragment.appendChild(node));

    if (anchor) anchor.parentNode?.insertBefore(fragment, anchor.nextSibling);
    else editor.appendChild(fragment);

    renumberSteps();
    selectFirstText(inserted[0]);
    onChange(editor.innerHTML);
  };

  /** Replace the whole body with a template — confirmed first, since it discards what is there. */
  const applyTemplate = (html: string) => {
    const editor = editorRef.current;
    if (!editor) return;

    const hasContent = editor.innerText.trim().length > 0;
    if (hasContent && !window.confirm("Remplacer tout le contenu de l'article par ce modèle ?")) return;

    editor.innerHTML = html;
    editor.focus();
    if (editor.firstChild) selectFirstText(editor.firstChild);
    onChange(editor.innerHTML);
  };

  const handlePaste = (event: React.ClipboardEvent<HTMLDivElement>) => {
    const editor = editorRef.current;
    if (!editor) return;

    const html = event.clipboardData.getData("text/html");
    const text = event.clipboardData.getData("text/plain");
    if (!html && !text) return;

    event.preventDefault();

    if (html) {
      document.execCommand("insertHTML", false, cleanPastedHtml(html));
    } else {
      document.execCommand("insertText", false, text);
    }

    renumberSteps();
    ensureLinksOpenInNewTab(editor);
    onChange(editor.innerHTML);
  };

  const handleImageUpload = () => {
    const input = document.createElement("input");
    input.type = "file";
    input.accept = "image/*";
    input.multiple = true;
    input.onchange = async (e) => {
      const files = (e.target as HTMLInputElement).files;
      if (!files) return;

      const promises = Array.from(files).map((file) => {
        return new Promise<string>((resolve) => {
          const reader = new FileReader();
          reader.onload = (event) => resolve(event.target?.result as string);
          reader.readAsDataURL(file);
        });
      });

      const base64Images = await Promise.all(promises);

      restoreSelection();
      const html = base64Images.map(src => `<img src="${src}" alt="image" />`).join('');
      document.execCommand("insertHTML", false, html);

      if (editorRef.current) {
        onChange(editorRef.current.innerHTML);
      }
    };
    input.click();
  };

  const insertLink = () => {
    const url = prompt("Entrez l'URL du lien:");
    if (!url || !editorRef.current) return;

    editorRef.current.focus();

    let range: Range | null = null;
    if (savedRange && editorRef.current.contains(savedRange.commonAncestorContainer)) {
      range = savedRange.cloneRange();
    } else {
      range = document.createRange();
      range.selectNodeContents(editorRef.current);
      range.collapse(false);
    }

    const anchor = document.createElement("a");
    anchor.href = url;
    anchor.target = "_blank";
    anchor.rel = "noopener noreferrer";

    if (range.collapsed) {
      anchor.textContent = url;
      range.insertNode(anchor);
    } else {
      const contents = range.extractContents();
      const hasText = !!(contents.textContent && contents.textContent.length > 0);
      if (hasText) {
        anchor.appendChild(contents);
      } else {
        anchor.textContent = url;
      }
      range.insertNode(anchor);
    }

    const newRange = document.createRange();
    newRange.setStartAfter(anchor);
    newRange.collapse(true);
    const selection = window.getSelection();
    selection?.removeAllRanges();
    selection?.addRange(newRange);
    setSavedRange(newRange.cloneRange());

    onChange(editorRef.current.innerHTML);
    updateActiveFormats();
  };

  const blockMenu = (align: "start" | "end" = "start") => (
    <DropdownMenuContent align={align} className="max-h-[420px] w-72 overflow-y-auto">
      {(templates?.length ?? 0) > 0 && (
        <>
          <DropdownMenuLabel className="text-xs text-muted-foreground">
            Modèles d&apos;article
          </DropdownMenuLabel>
          {templates!.map((template) => (
            <DropdownMenuItem
              key={template.key}
              className="flex-col items-start gap-0.5"
              onClick={() => applyTemplate(template.html)}
            >
              <span className="font-medium">{template.label}</span>
              <span className="text-xs text-muted-foreground whitespace-normal">
                {template.description}
              </span>
            </DropdownMenuItem>
          ))}
          <DropdownMenuSeparator />
        </>
      )}
      <DropdownMenuLabel className="text-xs text-muted-foreground">Blocs</DropdownMenuLabel>
      {(blocks ?? []).map((block) => (
        <DropdownMenuItem
          key={block.key}
          className="flex-col items-start gap-0.5"
          onClick={() => insertBlock(block.html)}
        >
          <span className="font-medium">{block.label}</span>
          <span className="text-xs text-muted-foreground whitespace-normal">{block.description}</span>
        </DropdownMenuItem>
      ))}
    </DropdownMenuContent>
  );

  return (
    <div className={cn("flex flex-col border border-border rounded-md overflow-hidden bg-card h-full", className)}>
      {/* Top Menu Bar */}
      <div className="flex items-center gap-2 px-3 py-1 border-b border-border bg-muted/20 text-sm">
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <button type="button" className="hover:bg-muted px-2 py-1 rounded cursor-pointer text-muted-foreground transition-colors">File</button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="start">
            <DropdownMenuItem onClick={() => { if(editorRef.current) { editorRef.current.innerHTML = ""; onChange(""); } }}>Nouveau</DropdownMenuItem>
            <DropdownMenuItem onClick={() => window.print()}>Imprimer</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <button type="button" className="hover:bg-muted px-2 py-1 rounded cursor-pointer text-muted-foreground transition-colors">Edit</button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="start">
            <DropdownMenuItem onClick={() => execCommand("undo")}>Annuler</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("redo")}>Rétablir</DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem onClick={() => execCommand("cut")}>Couper</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("copy")}>Copier</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("paste")}>Coller</DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem onClick={() => execCommand("selectAll")}>Sélectionner tout</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <button type="button" className="hover:bg-muted px-2 py-1 rounded cursor-pointer text-muted-foreground transition-colors">Insert</button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="start">
            <DropdownMenuItem onClick={handleImageUpload}>Image...</DropdownMenuItem>
            <DropdownMenuItem onClick={insertLink}>Lien...</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("insertHorizontalRule")}>Ligne horizontale</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <button type="button" className="hover:bg-muted px-2 py-1 rounded cursor-pointer text-muted-foreground transition-colors">Format</button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="start">
            <DropdownMenuItem onClick={() => execCommand("bold")}>Gras</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("italic")}>Italique</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("underline")}>Souligné</DropdownMenuItem>
            <DropdownMenuItem onClick={() => execCommand("strikeThrough")}>Barré</DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem onClick={() => execCommand("removeFormat")}>Effacer le formatage</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>

        {hasLibrary && (
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <button type="button" className="hover:bg-muted px-2 py-1 rounded cursor-pointer text-muted-foreground transition-colors">Blocs</button>
            </DropdownMenuTrigger>
            {blockMenu()}
          </DropdownMenu>
        )}
      </div>

      {/* Toolbar */}
      <div className="flex items-center gap-1 p-1 border-b border-border bg-muted/10 flex-wrap">
        <Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground" onClick={() => execCommand("undo")} type="button" title="Undo">
          <Undo className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground" onClick={() => execCommand("redo")} type="button" title="Redo">
          <Redo className="w-4 h-4" />
        </Button>

        <div className="w-px h-6 bg-border mx-1" />

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" size="sm" className="h-8 text-muted-foreground hover:text-foreground gap-2 px-2" type="button">
              {activeBlock} <ChevronDown className="w-3 h-3" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent>
            <DropdownMenuItem onClick={() => formatBlock("P")}>Paragraphe</DropdownMenuItem>
            <DropdownMenuItem onClick={() => formatBlock("H1")}><span className="text-2xl font-bold">Titre 1</span></DropdownMenuItem>
            <DropdownMenuItem onClick={() => formatBlock("H2")}><span className="text-xl font-bold">Titre 2</span></DropdownMenuItem>
            <DropdownMenuItem onClick={() => formatBlock("H3")}><span className="text-lg font-bold">Titre 3</span></DropdownMenuItem>
            <DropdownMenuItem onClick={() => formatBlock("H4")}><span className="text-base font-bold">Titre 4</span></DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>

        <div className="w-px h-6 bg-border mx-1" />

        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.bold && "bg-muted text-foreground")} onClick={() => execCommand("bold")} type="button" title="Bold">
          <Bold className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.italic && "bg-muted text-foreground")} onClick={() => execCommand("italic")} type="button" title="Italic">
          <Italic className="w-4 h-4" />
        </Button>

        <div className="w-px h-6 bg-border mx-1" />

        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.justifyLeft && "bg-muted text-foreground")} onClick={() => execCommand("justifyLeft")} type="button" title="Align Left">
          <AlignLeft className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.justifyCenter && "bg-muted text-foreground")} onClick={() => execCommand("justifyCenter")} type="button" title="Align Center">
          <AlignCenter className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.justifyRight && "bg-muted text-foreground")} onClick={() => execCommand("justifyRight")} type="button" title="Align Right">
          <AlignRight className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className={cn("h-8 w-8 text-muted-foreground hover:text-foreground", activeFormats.justifyFull && "bg-muted text-foreground")} onClick={() => execCommand("justifyFull")} type="button" title="Justify">
          <AlignJustify className="w-4 h-4" />
        </Button>

        <div className="w-px h-6 bg-border mx-1" />

        <Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground" onClick={() => execCommand("outdent")} type="button" title="Decrease Indent">
          <Outdent className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground" onClick={() => execCommand("indent")} type="button" title="Increase Indent">
          <Indent className="w-4 h-4" />
        </Button>

        {hasLibrary && (
          <>
            <div className="w-px h-6 bg-border mx-1" />
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button variant="ghost" size="sm" className="h-8 gap-2 px-2 text-muted-foreground hover:text-foreground" type="button" title="Insérer un bloc de mise en page">
                  <LayoutTemplate className="w-4 h-4" />
                  Blocs
                  <ChevronDown className="w-3 h-3" />
                </Button>
              </DropdownMenuTrigger>
              {blockMenu()}
            </DropdownMenu>
          </>
        )}

        <div className="ml-auto flex items-center">
          <Button
            variant="ghost"
            size="sm"
            className={cn("h-8 gap-2 px-2 text-muted-foreground hover:text-foreground", showSource && "bg-muted text-foreground")}
            onClick={() => setShowSource((v) => !v)}
            type="button"
            title="Afficher le code HTML"
          >
            <Code2 className="w-4 h-4" />
            HTML
          </Button>
        </div>
      </div>

      {/* Editor Area */}
      <div
        ref={editorRef}
        className={cn(
          "flex-1 p-4 outline-none overflow-y-auto",
          "empty:before:content-[attr(data-placeholder)] empty:before:text-muted-foreground empty:before:pointer-events-none empty:before:block",
          isFocused ? "ring-inset ring-2 ring-ring/50" : "",
          showSource && "hidden",
          "[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:my-4 [&_h2]:text-2xl [&_h2]:font-bold [&_h2]:my-3 [&_h3]:text-xl [&_h3]:font-bold [&_h3]:my-2 [&_h4]:text-lg [&_h4]:font-bold [&_h4]:my-2 [&_p]:my-2 [&_ul]:list-disc [&_ul]:ml-5 [&_ul]:my-2 [&_ol]:list-decimal [&_ol]:ml-5 [&_ol]:my-2 [&_a]:text-blue-500 [&_a]:underline [&_blockquote]:border-l-4 [&_blockquote]:border-muted-foreground [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-4 [&_img]:max-w-full [&_img]:h-auto [&_img]:max-h-[250px] [&_img]:object-contain [&_img]:rounded-md [&_img]:my-4"
        )}
        contentEditable
        onInput={handleInput}
        onPaste={handlePaste}
        onFocus={() => setIsFocused(true)}
        onBlur={() => {
          setIsFocused(false);
          saveSelection();
          if (linkifyAll() && editorRef.current) {
            onChange(editorRef.current.innerHTML);
          }
        }}
        onKeyUp={(e) => {
          saveSelection();
          if (e.key === " " || e.key === "Spacebar") {
            if (linkifyBeforeCaret() && editorRef.current) {
              onChange(editorRef.current.innerHTML);
            }
          }
        }}
        onMouseUp={saveSelection}
        suppressContentEditableWarning
        data-placeholder={placeholder}
      />

      {/* Raw HTML, for pasting or fine-tuning a block by hand. */}
      {showSource && (
        <textarea
          value={value}
          onChange={(e) => onChange(e.target.value)}
          spellCheck={false}
          className="flex-1 w-full resize-none p-4 font-mono text-xs outline-none bg-muted/20 text-foreground"
        />
      )}
    </div>
  );
}
