// 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 { EquipmentPlannerModule } from "../features/toolboxes/modules/EquipmentPlannerModule.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,
  normalizeEquipmentPlannerData,
  normalizeImageAnnotationData,
  normalizeLinksData,
  normalizeNotepadData,
  normalizeTableData,
  normalizeTaskPlannerData,
  normalizeTimerData,
  summarizeEquipmentPlannerData,
  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 },
  equipmentPlanner: { label: "Planificateur d'équipements", mode: "Build + sertissages", icon: "chest-armor", Component: EquipmentPlannerModule, editable: true, scrollable: true },
  imageAnnotation: { label: "Annotation d'images", mode: "Image + marqueurs", icon: "map", Component: ImageAnnotationModule, editable: true }
};

const LIBRARY_CATEGORY_DEFINITIONS = [
  { key: "notesTracking", types: ["notepad", "checklist", "counters"] },
  { key: "references", types: ["images", "imageAnnotation", "links"] },
  { key: "calculationData", types: ["calculator", "table"] },
  { key: "timeRoutines", types: ["timer", "taskPlanner"] },
  { key: "buildsCommands", types: ["combos", "equipmentPlanner"] }
];

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 getLibraryCategoryAnchorId(category) {
  return `library-category-${category.key}`;
}

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 findCategoryForAnchor(categories, anchorId) {
  return categories.find((category) => (
    getLibraryCategoryAnchorId(category) === anchorId ||
    category.modules.some((module) => getLibraryAnchorId(module) === anchorId)
  )) || null;
}

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

function getLibraryCategories(modules, content) {
  const modulesByType = new Map((modules || []).map((module) => [module.type, module]));
  return LIBRARY_CATEGORY_DEFINITIONS.map((category) => ({
    ...category,
    title: content.categories?.[category.key] || category.key,
    description: content.categoryDescriptions?.[category.key] || "",
    modules: category.types.map((type) => modulesByType.get(type)).filter(Boolean)
  })).filter((category) => category.modules.length);
}

export function LibraryPage({ siteContent, actions }) {
  const content = siteContent.library;
  const [libraryPayload, setLibraryPayload] = useState(null);
  const [libraryError, setLibraryError] = useState("");
  const [moduleData, setModuleData] = useState({});
  const [activeCategoryKey, setActiveCategoryKey] = useState("");
  const libraryCategories = useMemo(() => getLibraryCategories(libraryPayload?.toolbox?.modules || [], content), [content, libraryPayload]);
  const activeCategory = libraryCategories.find((category) => category.key === activeCategoryKey) || libraryCategories[0] || null;

  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 || !libraryCategories.length) return;
    const anchorId = getCurrentLibraryAnchor();
    const category = findCategoryForAnchor(libraryCategories, anchorId) || libraryCategories[0];
    setActiveCategoryKey(category.key);
    if (!anchorId) return;
    requestAnimationFrame(() => scrollToLibraryTool(anchorId));
  }, [libraryPayload, libraryCategories]);

  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,
    normalizeEquipmentPlannerData,
    normalizeCalculatorData,
    normalizeImageAnnotationData,
    normalizeNotepadData,
    normalizeTableData,
    normalizeTimerData,
    normalizeTaskPlannerData,
    summarizeEquipmentPlannerData,
    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 && (
        <>
          <div className="library-doc-layout">
            <LibraryDocNav
              content={content}
              categories={libraryCategories}
              activeCategoryKey={activeCategory?.key || ""}
              onSelectCategory={(category, anchorId = getLibraryCategoryAnchorId(category)) => {
                setActiveCategoryKey(category.key);
                requestAnimationFrame(() => scrollToLibraryTool(anchorId, true));
              }}
            />
            <section className="library-tools" aria-label={content.toolsLabel}>
              {activeCategory && (
                <section className="library-tool-category" key={activeCategory.key} aria-labelledby={getLibraryCategoryAnchorId(activeCategory)}>
                  <div className="library-category-hero">
                    <div>
                      <p className="eyebrow">{content.categoryLabel || "Catégorie"}</p>
                      <h2 id={getLibraryCategoryAnchorId(activeCategory)}>{activeCategory.title}</h2>
                      {activeCategory.description && <p>{activeCategory.description}</p>}
                    </div>
                  </div>
                  {activeCategory.modules.map((module) => (
                    <LibraryToolExample
                      key={module.id}
                      module={module}
                      sourceData={libraryPayload.modules?.[module.id] || {}}
                      description={getToolDescription(siteContent, MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad)}
                      categoryTitle={activeCategory.title}
                      docs={content.toolDocs?.[module.type]}
                      featureHeading={content.featureHeading}
                      controlLegendHeading={content.controlLegendHeading}
                      context={moduleContext}
                    />
                  ))}
                </section>
              )}
            </section>
          </div>
        </>
      )}
    </div>
  );
}

function LibraryDocNav({ content, categories, activeCategoryKey, onSelectCategory }) {
  return (
    <nav className="library-doc-nav nebula-panel" aria-label={content.tocLabel || "Sommaire des outils"}>
      <div className="library-toc-heading">
        <h2>{content.docTocTitle || content.tocTitle || "Sommaire"}</h2>
        <p>{content.tocDescription || "Accédez directement à un exemple d’outil dans la page."}</p>
      </div>
      <div className="library-doc-nav-groups">
        {categories.map((category) => (
          <div className={`library-doc-nav-group ${category.key === activeCategoryKey ? "active" : ""}`} key={category.key}>
            <a href={`#/library#${getLibraryCategoryAnchorId(category)}`} onClick={(event) => {
              event.preventDefault();
              onSelectCategory(category);
            }}>{category.title}</a>
            <ul hidden={category.key !== activeCategoryKey}>
              {category.modules.map((module) => {
                const definition = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
                const title = module.title || definition.label || "Outil";
                const anchorId = getLibraryAnchorId(module);
                return (
                  <li key={module.id}>
                    <a
                      href={`#/library#${anchorId}`}
                      onClick={(event) => {
                        event.preventDefault();
                        onSelectCategory(category, anchorId);
                      }}
                    >
                      <span className="module-icon" aria-hidden="true">
                        <span className={`module-icon-svg module-icon-${definition.icon}`} />
                      </span>
                      <span>{title}</span>
                    </a>
                  </li>
                );
              })}
            </ul>
          </div>
        ))}
      </div>
    </nav>
  );
}

function LibraryToolExample({ module, sourceData, description, categoryTitle, docs, featureHeading, controlLegendHeading, 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>
          <div className="library-tool-title-row">
            <span className="module-icon" aria-hidden="true">
              <span className={`module-icon-svg module-icon-${definition.icon}`} />
            </span>
            <h2>{title}</h2>
          </div>
          <span className="library-tool-badge">{categoryTitle}</span>
          {description && <p>{description}</p>}
        </div>
      </div>
      <div className={`library-example-layout ${Array.isArray(docs?.controls) && docs.controls.length ? "has-legend" : ""}`}>
        <ToolControlLegend items={docs?.controls} heading={controlLegendHeading || "Repères"} />
        <article className={`module library-tool-example ${scrollable ? "is-scrollable" : ""}`}>
          <header>
            <div>
              <h2>{definition.label}</h2>
              <p>{definition.mode}</p>
            </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>
      </div>
      <ToolFeatureList docs={docs} heading={featureHeading || "Fonctionnalités"} />
    </section>
  );
}

function ToolControlLegend({ items, heading }) {
  const legendItems = Array.isArray(items) ? items : [];
  if (!legendItems.length) return null;
  const groups = legendItems.reduce((accumulator, item) => {
    const groupTitle = item.group || "Contrôles";
    const existingGroup = accumulator.find((group) => group.title === groupTitle);
    if (existingGroup) existingGroup.items.push(item);
    else accumulator.push({ title: groupTitle, items: [item] });
    return accumulator;
  }, []);

  return (
    <aside className="library-control-legend" aria-label={heading}>
      <h3>{heading}</h3>
      {groups.map((group) => {
        const genericSingleGroup = groups.length === 1 && group.title === "Contrôles";
        return (
          <section className={`library-control-legend-group ${genericSingleGroup ? "is-generic-single" : ""}`} key={group.title}>
            {!genericSingleGroup && <h4>{group.title}</h4>}
            <div className="library-control-legend-items">
              {group.items.map((item) => (
                <div className="library-control-legend-item" key={item.title}>
                  <ControlPreview item={item} />
                  <div>
                    <strong>{item.title}</strong>
                    {item.text && <p>{item.text}</p>}
                  </div>
                </div>
              ))}
            </div>
          </section>
        );
      })}
    </aside>
  );
}

function ControlPreview({ item }) {
  const preview = item.preview || {};
  const kind = preview.kind || "iconButton";

  if (kind === "textFormats") {
    return (
      <span className="library-control-preview notepad-toolbar-group" aria-hidden="true">
        <span className="notepad-toolbar-button">B</span>
        <span className="notepad-toolbar-button"><em>I</em></span>
        <span className="notepad-toolbar-button"><u>U</u></span>
        <span className="notepad-toolbar-button"><s>S</s></span>
      </span>
    );
  }

  if (kind === "textButton") {
    return (
      <span className="library-control-preview" aria-hidden="true">
        <span className={`notepad-toolbar-button ${preview.active ? "active" : ""}`}>{preview.label || item.title.slice(0, 1)}</span>
      </span>
    );
  }

  if (kind === "listDropdown") {
    return (
      <span className="library-control-preview" aria-hidden="true">
        <span className="notepad-toolbar-button active"><span className="notepad-list-icon" /></span>
        <span className="notepad-toolbar-button">•</span>
        <span className="notepad-toolbar-button">1.</span>
      </span>
    );
  }

  if (kind === "color") {
    return (
      <span className="library-control-preview" aria-hidden="true">
        <span className="notepad-color-toggle is-rainbow active" />
      </span>
    );
  }

  if (kind === "drawingWidth") {
    return (
      <span className="library-control-preview" aria-hidden="true">
        <span className="drawing-width-toggle active"><span style={{ "--line-width": `${preview.width || 4}px` }} /></span>
      </span>
    );
  }

  if (kind === "switch") {
    return (
      <span className="library-control-preview" aria-hidden="true">
        <span className={`module-scroll-button drawing-storage-switch ${preview.active ? "active" : ""}`}>
          <Icon name={preview.icon || item.icon || "settings"} />
          <i />
        </span>
      </span>
    );
  }

  if (kind === "buttonGroup") {
    const buttons = Array.isArray(preview.buttons) ? preview.buttons : [];
    return (
      <span className="library-control-preview" aria-hidden="true">
        {buttons.map((button, index) => (
          <span className={`notepad-toolbar-button ${button.label && String(button.label).length > 2 ? "is-wide" : ""} ${button.active ? "active" : ""} ${button.danger ? "danger" : ""}`} key={`${button.label || button.icon || index}-${index}`}>
            {button.icon ? <Icon name={button.icon} /> : button.label}
          </span>
        ))}
      </span>
    );
  }

  return (
    <span className="library-control-preview" aria-hidden="true">
      <span className={`notepad-toolbar-button ${preview.active ? "active" : ""} ${preview.danger ? "danger" : ""}`}>
        <Icon name={preview.icon || item.icon || "settings"} />
      </span>
    </span>
  );
}

function ToolFeatureList({ docs, heading }) {
  const features = Array.isArray(docs?.features) ? docs.features : [];
  if (!features.length && !docs?.importFormat) return null;

  return (
    <section className="library-tool-docs">
      <details className="library-tool-feature-list">
        <summary>
          <h3>{heading}</h3>
          <Icon name="chevron-down" />
        </summary>
        <div className="library-tool-feature-content">
          <dl>
            {features.map((feature) => (
              <div key={feature.title}>
                <dt>{feature.title}</dt>
                <dd>
                  <p>{feature.text}</p>
                  {Array.isArray(feature.details) && feature.details.length > 0 && (
                    <ul>
                      {feature.details.map((detail) => <li key={detail}>{detail}</li>)}
                    </ul>
                  )}
                </dd>
              </div>
            ))}
          </dl>
          {docs?.importFormat && (
            <div className="library-tool-import-format">
              <h3>{docs.importFormat.title}</h3>
              <p>{docs.importFormat.text}</p>
              <pre><code>{docs.importFormat.example}</code></pre>
            </div>
          )}
        </div>
      </details>
    </section>
  );
}
