// Rôle : affiche la librairie des outils avec des exemples locaux non persistés.
import React, { useEffect, useMemo, useState } from "react";
import { Icon } from "../components/Icon.jsx";
import { CalculatorModule } from "../features/toolboxes/modules/CalculatorModule.jsx";
import { ChecklistModule } from "../features/toolboxes/modules/ChecklistModule.jsx";
import { CombosModule } from "../features/toolboxes/modules/CombosModule.jsx";
import { CountersModule } from "../features/toolboxes/modules/CountersModule.jsx";
import { ImageAnnotationModule } from "../features/toolboxes/modules/ImageAnnotationModule.jsx";
import { ImagesModule } from "../features/toolboxes/modules/ImagesModule.jsx";
import { LinksModule } from "../features/toolboxes/modules/LinksModule.jsx";
import { NotepadModule } from "../features/toolboxes/modules/NotepadModule.jsx";
import { TableModule } from "../features/toolboxes/modules/TableModule.jsx";
import { TaskPlannerModule } from "../features/toolboxes/modules/TaskPlannerModule.jsx";
import { TimerModule } from "../features/toolboxes/modules/TimerModule.jsx";
import {
  clampQty,
  hostnameFromUrl,
  normalizeCalculatorData,
  normalizeChecklistData,
  normalizeCombosData,
  normalizeCountersData,
  normalizeImageAnnotationData,
  normalizeLinksData,
  normalizeNotepadData,
  normalizeTableData,
  normalizeTaskPlannerData,
  normalizeTimerData,
  normalizeUrl,
  uid
} from "../features/toolboxes/storage/toolboxStorage.js";

const LIBRARY_TOOLBOX_ID = "library";

const MODULE_COMPONENTS = {
  notepad: { label: "Bloc notes", mode: "Texte riche", icon: "notepad", Component: NotepadModule },
  checklist: { label: "Checklist", mode: "Catégories + sans catégorie", icon: "checklist", Component: ChecklistModule, editable: true, scrollable: true },
  images: { label: "Images", mode: "Média", icon: "picture", Component: ImagesModule, editable: true, scrollable: true },
  links: { label: "Liens", mode: "Liste simple", icon: "link", Component: LinksModule, editable: true, scrollable: true },
  counters: { label: "Compteurs", mode: "Valeurs", icon: "abacus", Component: CountersModule, editable: true, scrollable: true },
  combos: { label: "Combos", mode: "Catégories", icon: "controller", Component: CombosModule, editable: true, scrollable: true },
  calculator: { label: "Calculateur", mode: "Arborescence", icon: "calculator", Component: CalculatorModule },
  table: { label: "Tableau", mode: "Grille + formules", icon: "table", Component: TableModule, scrollable: true },
  timer: { label: "Timer", mode: "Chrono + comptes à rebours", icon: "clock", Component: TimerModule },
  taskPlanner: { label: "Planificateur de tâches", mode: "Catégories + parent/enfant", icon: "tasklist", Component: TaskPlannerModule, editable: true, scrollable: true },
  imageAnnotation: { label: "Annotation d'images", mode: "Image + marqueurs", icon: "map", Component: ImageAnnotationModule, editable: true }
};

function cloneData(value) {
  if (value === undefined) return {};
  if (typeof structuredClone === "function") return structuredClone(value);
  return JSON.parse(JSON.stringify(value));
}

function fileToDataUrl(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener("load", () => resolve(String(reader.result || "")));
    reader.addEventListener("error", () => reject(reader.error || new Error("Image illisible.")));
    reader.readAsDataURL(file);
  });
}

function createModuleDataFromPayload(payload) {
  return Object.fromEntries((payload?.toolbox?.modules || []).map((module) => [
    `${LIBRARY_TOOLBOX_ID}:${module.id}`,
    cloneData(payload?.modules?.[module.id] || {})
  ]));
}

function getLibraryAnchorId(module) {
  return `library-tool-${String(module?.id || module?.type || "outil").replace(/[^a-z0-9_-]+/gi, "-").toLowerCase()}`;
}

function getCurrentLibraryAnchor() {
  const match = location.hash.match(/^#\/library#(.+)$/);
  return match ? decodeURIComponent(match[1]) : "";
}

function scrollToLibraryTool(anchorId, replace = false) {
  const element = document.getElementById(anchorId);
  if (!element) return;
  if (replace) history.replaceState(null, "", `#/library#${encodeURIComponent(anchorId)}`);
  const top = element.getBoundingClientRect().top + window.scrollY - 24;
  window.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
}

function getToolDescription(siteContent, definition) {
  const tools = siteContent.about?.tools || [];
  return tools.find((tool) => tool.name === definition.label)?.description || "";
}

export function LibraryPage({ siteContent, actions }) {
  const content = siteContent.library;
  const [libraryPayload, setLibraryPayload] = useState(null);
  const [libraryError, setLibraryError] = useState("");
  const [moduleData, setModuleData] = useState({});

  useEffect(() => {
    let cancelled = false;
    fetch("/data/library.json")
      .then((response) => {
        if (!response.ok) throw new Error("Impossible de charger les exemples de librairie.");
        return response.json();
      })
      .then((payload) => {
        if (cancelled) return;
        setLibraryPayload(payload);
        setModuleData(createModuleDataFromPayload(payload));
      })
      .catch((error) => {
        if (!cancelled) setLibraryError(error.message);
      });
    return () => { cancelled = true; };
  }, []);

  useEffect(() => {
    if (!libraryPayload) return;
    const anchorId = getCurrentLibraryAnchor();
    if (!anchorId) return;
    requestAnimationFrame(() => scrollToLibraryTool(anchorId));
  }, [libraryPayload]);

  const moduleContext = useMemo(() => ({
    getModuleData: (toolboxId, moduleId, fallback) => moduleData[`${toolboxId}:${moduleId}`] || fallback,
    setModuleData: (toolboxId, moduleId, data) => setModuleData((current) => ({ ...current, [`${toolboxId}:${moduleId}`]: data })),
    moduleText: siteContent.toolboxes.modules,
    normalizeChecklistData,
    normalizeCombosData,
    normalizeLinksData,
    normalizeCountersData,
    normalizeCalculatorData,
    normalizeImageAnnotationData,
    normalizeNotepadData,
    normalizeTableData,
    normalizeTimerData,
    normalizeTaskPlannerData,
    normalizeUrl,
    hostnameFromUrl,
    clampQty,
    uid,
    copyText: async (value) => {
      await navigator.clipboard.writeText(value);
      return true;
    },
    notify: actions.notify,
    compressImageFile: fileToDataUrl,
    addImageFiles: async (toolboxId, moduleId, files) => {
      const imageFiles = [...files].filter((file) => file?.type?.startsWith("image/"));
      if (!imageFiles.length) return false;
      const images = await Promise.all(imageFiles.map(async (file) => ({
        id: uid("image"),
        label: file.name?.replace(/\.[^.]+$/, "").trim() || "",
        dataUrl: await fileToDataUrl(file)
      })));
      setModuleData((current) => {
        const key = `${toolboxId}:${moduleId}`;
        const data = current[key] || { images: [] };
        return { ...current, [key]: { ...data, images: [...(data.images || []), ...images] } };
      });
      return true;
    },
    setImage: actions.setImage,
    createImageAnnotationModule: (dataUrl) => {
      const annotationModule = libraryPayload?.toolbox?.modules?.find((module) => module.type === "imageAnnotation");
      if (!annotationModule || !dataUrl) return;
      setModuleData((current) => ({
        ...current,
        [`${LIBRARY_TOOLBOX_ID}:${annotationModule.id}`]: { image: dataUrl, markers: [], drawings: { strokes: [] } }
      }));
      requestAnimationFrame(() => scrollToLibraryTool(getLibraryAnchorId(annotationModule), true));
    }
  }), [actions, libraryPayload, moduleData, siteContent.toolboxes.modules]);

  return (
    <div className="library-page">
      <section className="page-hero library-hero">
        <div>
          <p className="eyebrow">{content.eyebrow}</p>
          <h1>{content.title}</h1>
          <p>{content.description}</p>
        </div>
      </section>
      <section className="library-summary nebula-panel" aria-label={content.summaryLabel}>
        {content.summaryItems.map((item) => (
          <article key={item.title}>
            <span className="library-summary-icon" aria-hidden="true">
              <span className={`module-icon-svg module-icon-${item.icon || "toolbox"}`} />
            </span>
            <div>
              <h2>{item.title}</h2>
              <p>{item.text}</p>
            </div>
          </article>
        ))}
      </section>
      {libraryError && <section className="empty"><h2>Librairie indisponible</h2><p>{libraryError}</p></section>}
      {!libraryError && !libraryPayload && <section className="empty"><p>Chargement des exemples...</p></section>}
      {libraryPayload && (
        <>
          <nav className="library-toc nebula-panel" aria-label={content.tocLabel || "Sommaire des outils"}>
            {libraryPayload.toolbox.modules.map((module) => {
              const definition = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
              const title = module.title || definition.label || "Outil";
              const anchorId = getLibraryAnchorId(module);
              return (
                <a
                  key={module.id}
                  href={`#/library#${anchorId}`}
                  onClick={(event) => {
                    event.preventDefault();
                    scrollToLibraryTool(anchorId, true);
                  }}
                >
                  <span className="module-icon" aria-hidden="true">
                    <span className={`module-icon-svg module-icon-${definition.icon}`} />
                  </span>
                  <span>{title}</span>
                </a>
              );
            })}
          </nav>
          <section className="library-tools" aria-label={content.toolsLabel}>
            {libraryPayload.toolbox.modules.map((module) => (
              <LibraryToolExample
                key={module.id}
                module={module}
                sourceData={libraryPayload.modules?.[module.id] || {}}
                description={getToolDescription(siteContent, MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad)}
                context={moduleContext}
              />
            ))}
          </section>
        </>
      )}
    </div>
  );
}

function LibraryToolExample({ module, sourceData, description, context }) {
  const definition = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
  const Component = definition.Component;
  const [scrollable, setScrollable] = useState(false);
  const [editing, setEditing] = useState(false);
  const title = module.title || definition.label || "Outil";

  return (
    <section id={getLibraryAnchorId(module)} className="library-tool-section">
      <div className="library-tool-intro">
        <div>
          <h2>{title}</h2>
          {description && <p>{description}</p>}
        </div>
      </div>
      <article className={`module library-tool-example ${scrollable ? "is-scrollable" : ""}`}>
        <header>
          <div>
            <span className="module-icon" aria-hidden="true">
              <span className={`module-icon-svg module-icon-${definition.icon}`} />
            </span>
            <div>
              <h2>{definition.label}</h2>
            </div>
          </div>
          <div className="library-example-actions">
            {definition.scrollable && (
              <button
                className={`module-scroll-button ${scrollable ? "active" : ""}`}
                type="button"
                onClick={() => setScrollable((value) => !value)}
                aria-label={`${scrollable ? "Désactiver" : "Activer"} le scroll de ${title}`}
                aria-pressed={scrollable}
                title={scrollable ? "Désactiver le scroll" : "Activer le scroll"}
              >
                <Icon name="scrollable" />
                <i aria-hidden="true" />
              </button>
            )}
            {definition.editable && (
              <button
                className={`module-edit-button ${editing ? "active" : ""}`}
                type="button"
                onClick={() => setEditing((value) => !value)}
                aria-label={`${editing ? "Masquer" : "Afficher"} l'ajout de ${title}`}
                aria-pressed={editing}
                title={editing ? "Masquer l'ajout" : "Ajouter"}
              >
                <Icon name="add" />
              </button>
            )}
            <button className="library-reset-button" type="button" onClick={() => context.setModuleData(LIBRARY_TOOLBOX_ID, module.id, cloneData(sourceData))} aria-label={`Réinitialiser ${title}`} title="Réinitialiser l'exemple">
              <Icon name="refresh" />
            </button>
          </div>
        </header>
        <div className={`module-content ${scrollable ? "is-scrollable legacy-scrollbar" : ""}`}>
          <Component toolboxId={LIBRARY_TOOLBOX_ID} moduleId={module.id} context={context} editing={editing} />
        </div>
      </article>
    </section>
  );
}
