// Rôle : fournit l'outil bloc-notes riche avec annotations dessinées.
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { CompactDropdown } from "../../../components/CompactDropdown.jsx";
import { DrawingControls, FormattingColorDropdown } from "./DrawingControls.jsx";
import { DrawingOverlay } from "./DrawingOverlay.jsx";

const TEXT_COLORS = ["#f5f7ff", "#b4bdd3", "#f6c453", "#22d3ee", "#8b5cf6", "#d946ef"];
const HIGHLIGHT_COLORS = ["#f6c453", "#22d3ee", "#8b5cf6", "#d946ef", "#202745"];
const DRAWING_WIDTHS = [2, 4, 8, 12];

function getPlainText(element) {
  return (element?.innerText || "").replace(/\n{3,}/g, "\n\n").trim();
}

function isHtmlEmpty(html, text) {
  return !text && !String(html || "").replace(/<br\s*\/?>/gi, "").replace(/<[^>]*>/g, "").replace(/&nbsp;/gi, " ").trim();
}

function formatUpdatedAt(value) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  return new Intl.DateTimeFormat("fr-FR", {
    dateStyle: "short",
    timeStyle: "short"
  }).format(date);
}

function queryCommandState(command) {
  try {
    return document.queryCommandState(command);
  } catch {
    return false;
  }
}

function queryBlockFormat() {
  try {
    return String(document.queryCommandValue("formatBlock") || "").replace(/[<>]/g, "").toLowerCase();
  } catch {
    return "";
  }
}

function ToolbarButton({ active, title, children, onClick }) {
  return (
    <button
      className={`notepad-toolbar-button ${active ? "active" : ""}`}
      type="button"
      aria-pressed={active}
      title={title}
      onMouseDown={(event) => event.preventDefault()}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

function ListTypeDropdown({ textContent, activeFormats, onCommand }) {
  return (
    <CompactDropdown
      className="notepad-list-dropdown"
      menuClassName="notepad-list-menu"
      label={textContent.listGroupLabel || "Listes"}
      closeOnMouseLeave
      preventMouseDown
      renderTrigger={({ toggle }) => (
        <button
          className={`notepad-toolbar-button ${activeFormats.bulletList || activeFormats.numberList ? "active" : ""}`}
          type="button"
          aria-pressed={activeFormats.bulletList || activeFormats.numberList}
          title={textContent.listGroupLabel || "Listes"}
          onClick={toggle}
        >
          <span className="notepad-list-icon" aria-hidden="true" />
        </button>
      )}
    >
      {({ close }) => (
        <>
          <button
            className={`notepad-list-option ${activeFormats.bulletList ? "active" : ""}`}
            type="button"
            aria-pressed={activeFormats.bulletList}
            onClick={() => {
              onCommand("insertUnorderedList");
              close();
            }}
          >
            •
          </button>
          <button
            className={`notepad-list-option ${activeFormats.numberList ? "active" : ""}`}
            type="button"
            aria-pressed={activeFormats.numberList}
            onClick={() => {
              onCommand("insertOrderedList");
              close();
            }}
          >
            1.
          </button>
        </>
      )}
    </CompactDropdown>
  );
}

export function NotepadModule({ toolboxId, moduleId, context }) {
  const storedData = context.getModuleData(toolboxId, moduleId, { text: "" });
  const normalizedData = useMemo(() => context.normalizeNotepadData(storedData), [context, storedData]);
  const textContent = context.moduleText?.notepad || {};
  const editorRef = useRef(null);
  const surfaceRef = useRef(null);
  const [html, setHtml] = useState(normalizedData.html);
  const [text, setText] = useState(normalizedData.text);
  const [updatedAt, setUpdatedAt] = useState(normalizedData.updatedAt);
  const [drawingMode, setDrawingMode] = useState(normalizedData.drawingMode);
  const [drawingActive, setDrawingActive] = useState(false);
  const [eraseActive, setEraseActive] = useState(false);
  const [drawingColor, setDrawingColor] = useState("#f6c453");
  const [drawingWidth, setDrawingWidth] = useState(4);
  const [textColor, setTextColor] = useState(TEXT_COLORS[0]);
  const [highlightColor, setHighlightColor] = useState(HIGHLIGHT_COLORS[0]);
  const [activeFormats, setActiveFormats] = useState({
    bold: false,
    italic: false,
    underline: false,
    strikeThrough: false,
    heading: false,
    bulletList: false,
    numberList: false
  });
  const sessionKey = `sokkog:notepad-drawings:${toolboxId}:${moduleId}`;
  const [temporaryStrokes, setTemporaryStrokes] = useState([]);

  useEffect(() => {
    setHtml(normalizedData.html);
    setText(normalizedData.text);
    setUpdatedAt(normalizedData.updatedAt);
    setDrawingMode(normalizedData.drawingMode);
    setDrawingActive(false);
    setEraseActive(false);
  }, [toolboxId, moduleId]);

  useEffect(() => {
    if (!editorRef.current || editorRef.current.innerHTML === html) return;
    editorRef.current.innerHTML = html;
  }, [html]);

  useEffect(() => {
    function updateActiveFormats() {
      const editor = editorRef.current;
      const selection = document.getSelection();
      if (!editor || !selection?.rangeCount || !editor.contains(selection.anchorNode)) {
        setActiveFormats((current) => Object.values(current).some(Boolean)
          ? { bold: false, italic: false, underline: false, strikeThrough: false, heading: false, bulletList: false, numberList: false }
          : current);
        return;
      }
      const block = queryBlockFormat();
      setActiveFormats({
        bold: queryCommandState("bold"),
        italic: queryCommandState("italic"),
        underline: queryCommandState("underline"),
        strikeThrough: queryCommandState("strikeThrough"),
        heading: block === "h3" || block === "heading 3",
        bulletList: queryCommandState("insertUnorderedList"),
        numberList: queryCommandState("insertOrderedList")
      });
    }

    document.addEventListener("selectionchange", updateActiveFormats);
    return () => document.removeEventListener("selectionchange", updateActiveFormats);
  }, []);

  useEffect(() => {
    try {
      const stored = JSON.parse(sessionStorage.getItem(sessionKey) || "[]");
      setTemporaryStrokes(Array.isArray(stored) ? stored : []);
    } catch {
      setTemporaryStrokes([]);
    }
  }, [sessionKey]);

  useEffect(() => {
    if (drawingMode !== "temporary") return;
    try {
      sessionStorage.setItem(sessionKey, JSON.stringify(temporaryStrokes));
    } catch {
      context.notify?.(textContent.sessionStorageError || "Les annotations temporaires n'ont pas pu être sauvegardées.");
    }
  }, [context, drawingMode, sessionKey, temporaryStrokes, textContent.sessionStorageError]);

  const activeStrokes = drawingMode === "permanent" ? normalizedData.drawings.strokes : temporaryStrokes;
  const formattedUpdatedAt = formatUpdatedAt(updatedAt);

  function saveContent(nextHtml, nextText) {
    const nextUpdatedAt = new Date().toISOString();
    setHtml(nextHtml);
    setText(nextText);
    setUpdatedAt(nextUpdatedAt);
    context.setModuleData(toolboxId, moduleId, {
      ...normalizedData,
      html: nextHtml,
      text: nextText,
      updatedAt: nextUpdatedAt,
      drawingMode,
      drawings: drawingMode === "permanent" ? { strokes: activeStrokes } : { strokes: [] }
    });
  }

  function saveDrawingMode(nextMode, nextStrokes) {
    setDrawingMode(nextMode);
    if (nextMode === "temporary") setTemporaryStrokes(nextStrokes);
    context.setModuleData(toolboxId, moduleId, {
      ...normalizedData,
      html,
      text,
      updatedAt,
      drawingMode: nextMode,
      drawings: nextMode === "permanent" ? { strokes: nextStrokes } : { strokes: [] }
    });
  }

  function saveStrokes(nextStrokes) {
    if (drawingMode === "permanent") {
      context.setModuleData(toolboxId, moduleId, {
        ...normalizedData,
        html,
        text,
        updatedAt,
        drawingMode,
        drawings: { strokes: nextStrokes }
      });
    } else {
      setTemporaryStrokes(nextStrokes);
    }
  }

  function handleEditorInput() {
    const nextHtml = editorRef.current?.innerHTML || "";
    const nextText = getPlainText(editorRef.current);
    saveContent(nextHtml, nextText);
    requestAnimationFrame(() => document.dispatchEvent(new Event("selectionchange")));
  }

  function runCommand(command, value = null) {
    editorRef.current?.focus();
    document.execCommand("styleWithCSS", false, true);
    document.execCommand(command, false, value);
    handleEditorInput();
  }

  function applyBlock(tag) {
    runCommand("formatBlock", tag);
  }

  function toggleHeading() {
    applyBlock(activeFormats.heading ? "p" : "h3");
  }

  function applyTextColor(color) {
    setTextColor(color);
    runCommand("foreColor", color);
  }

  function applyHighlightColor(color) {
    setHighlightColor(color);
    runCommand("hiliteColor", color);
  }

  function handlePaste(event) {
    const pastedText = event.clipboardData?.getData("text/plain");
    if (!pastedText) return;
    event.preventDefault();
    document.execCommand("insertText", false, pastedText);
    handleEditorInput();
  }

  const getSurfaceSize = useCallback(() => {
    const element = surfaceRef.current;
    return {
      width: element?.clientWidth || 0,
      height: Math.max(element?.scrollHeight || 0, element?.clientHeight || 0)
    };
  }, []);

  function toggleDrawingMode() {
    const nextMode = drawingMode === "permanent" ? "temporary" : "permanent";
    saveDrawingMode(nextMode, activeStrokes);
  }

  function undoStroke() {
    saveStrokes(activeStrokes.slice(0, -1));
  }

  function clearStrokes() {
    saveStrokes([]);
  }

  return (
    <div className="notepad-module">
      <div className="notepad-toolbar" aria-label={textContent.toolbarLabel || "Mise en page du bloc notes"}>
        <div className="notepad-format-controls">
          <div className="notepad-toolbar-group" role="group" aria-label={textContent.textFormatLabel || "Style du texte"}>
            <ToolbarButton active={activeFormats.bold} title={textContent.boldTitle || "Gras"} onClick={() => runCommand("bold")}>B</ToolbarButton>
            <ToolbarButton active={activeFormats.italic} title={textContent.italicTitle || "Italique"} onClick={() => runCommand("italic")}><em>I</em></ToolbarButton>
            <ToolbarButton active={activeFormats.underline} title={textContent.underlineTitle || "Souligné"} onClick={() => runCommand("underline")}><u>U</u></ToolbarButton>
            <ToolbarButton active={activeFormats.strikeThrough} title={textContent.strikeTitle || "Barré"} onClick={() => runCommand("strikeThrough")}><s>S</s></ToolbarButton>
            <ToolbarButton active={activeFormats.heading} title={textContent.headingTitle || "Titre"} onClick={toggleHeading}>T</ToolbarButton>
          </div>
          <div className="notepad-toolbar-group" role="group" aria-label={textContent.colorGroupLabel || "Couleurs"}>
            <ListTypeDropdown textContent={textContent} activeFormats={activeFormats} onCommand={runCommand} />
            <FormattingColorDropdown
              label={textContent.colorGroupLabel || "Couleurs"}
              sections={[
                {
                  label: textContent.textColorLabel || "Couleur du texte",
                  colors: TEXT_COLORS,
                  value: textColor,
                  onSelect: applyTextColor
                },
                {
                  label: textContent.highlightColorLabel || "Surlignage",
                  colors: HIGHLIGHT_COLORS,
                  value: highlightColor,
                  onSelect: applyHighlightColor
                }
              ]}
            />
          </div>
        </div>
      </div>

      <div className={`notepad-surface ${drawingActive ? "is-drawing" : ""}`} ref={surfaceRef}>
        <div
          ref={editorRef}
          className={`notepad-editor ${isHtmlEmpty(html, text) ? "is-empty" : ""}`}
          contentEditable={!drawingActive}
          suppressContentEditableWarning
          role="textbox"
          aria-multiline="true"
          data-placeholder={textContent.placeholder || "Notes rapides..."}
          onInput={handleEditorInput}
          onPaste={handlePaste}
        />
        <DrawingOverlay
          active={drawingActive}
          erase={eraseActive}
          strokes={activeStrokes}
          color={drawingColor}
          width={drawingWidth}
          onChange={saveStrokes}
          getSurfaceSize={getSurfaceSize}
          createStrokeId={() => context.uid("stroke")}
        />
        <DrawingControls
          textContent={textContent}
          active={drawingActive}
          onToggleActive={() => setDrawingActive((value) => !value)}
          eraseActive={eraseActive}
          onToggleErase={() => setEraseActive((value) => !value)}
          color={drawingColor}
          colors={TEXT_COLORS}
          onColorChange={setDrawingColor}
          width={drawingWidth}
          widths={DRAWING_WIDTHS}
          onWidthChange={setDrawingWidth}
          onUndo={undoStroke}
          onClear={clearStrokes}
          storageMode={drawingMode}
          onToggleStorageMode={toggleDrawingMode}
        />
      </div>
      <footer className="notepad-footer">
        {formattedUpdatedAt && <span>{`${textContent.updatedAtPrefix || "Modifié le"} ${formattedUpdatedAt}`}</span>}
      </footer>
    </div>
  );
}
