// Rôle : registre des outils toolbox, rendu commun et contrôles d'ajout/réorganisation.
import { useEffect, useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { CompactDropdown } from "../../../components/CompactDropdown.jsx";
import { Icon } from "../../../components/Icon.jsx";
import { useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
import { useInlineEdit } from "../../../hooks/useInlineEdit.js";
import { lockBodyScroll } from "../../../utils/bodyScrollLock.js";
import { CalculatorModule } from "./CalculatorModule.jsx";
import { ChecklistModule } from "./ChecklistModule.jsx";
import { CombosModule } from "./CombosModule.jsx";
import { CountersModule } from "./CountersModule.jsx";
import { ImageAnnotationModule } from "./ImageAnnotationModule.jsx";
import { EquipmentPlannerModule } from "./EquipmentPlannerModule.jsx";
import { LinksModule } from "./LinksModule.jsx";
import { NotepadModule } from "./NotepadModule.jsx";
import { ImagesModule } from "./ImagesModule.jsx";
import { TableModule } from "./TableModule.jsx";
import { TaskPlannerModule } from "./TaskPlannerModule.jsx";
import { TimerModule } from "./TimerModule.jsx";

const MODULE_COMPONENTS = {
  notepad: { label: "Bloc notes", icon: "notepad", Component: NotepadModule, editable: false },
  checklist: { label: "Checklist", icon: "checklist", Component: ChecklistModule, editable: true, scrollable: true },
  images: { label: "Images", icon: "picture", Component: ImagesModule, editable: true, scrollable: true },
  links: { label: "Liens", icon: "link", Component: LinksModule, editable: true, scrollable: true },
  counters: { label: "Compteurs", icon: "abacus", Component: CountersModule, editable: true, scrollable: true },
  combos: { label: "Combos", icon: "controller", Component: CombosModule, editable: true, scrollable: true },
  calculator: { label: "Calculateur", icon: "calculator", Component: CalculatorModule, editable: true },
  table: { label: "Tableau", icon: "table", Component: TableModule, editable: true, scrollable: true },
  timer: { label: "Timer", icon: "clock", Component: TimerModule, editable: true },
  taskPlanner: { label: "Planificateur de tâches", icon: "tasklist", Component: TaskPlannerModule, editable: true, scrollable: true },
  equipmentPlanner: { label: "Planificateur d'équipements", icon: "chest-armor", Component: EquipmentPlannerModule, editable: true, scrollable: true },
  imageAnnotation: { label: "Annotation d'images", icon: "map", Component: ImageAnnotationModule, editable: true }
};

const MODULE_COLUMN_IDS = ["left", "right"];

export const TOOLBOX_MODULES = Object.fromEntries(Object.entries(MODULE_COMPONENTS).map(([type, module]) => [
  type,
  { label: module.label, icon: module.icon }
]));

function getModuleMap(modules) {
  return new Map(modules.map((module) => [module.id, module]));
}

function getModulesByIds(modules, ids) {
  const moduleMap = getModuleMap(modules);
  return (Array.isArray(ids) ? ids : []).map((id) => moduleMap.get(id)).filter(Boolean);
}

function getModuleColumnId(moduleId, twoColumnOrder) {
  return twoColumnOrder?.[1]?.includes(moduleId) ? MODULE_COLUMN_IDS[1] : MODULE_COLUMN_IDS[0];
}

function moveId(ids, sourceId, targetId, placement = "before") {
  const nextIds = ids.filter((id) => id !== sourceId);
  const targetIndex = nextIds.indexOf(targetId);
  if (targetIndex < 0) return ids;
  nextIds.splice(placement === "after" ? targetIndex + 1 : targetIndex, 0, sourceId);
  return nextIds;
}

function moveModuleInOneColumnOrder(order, operation) {
  if (!operation.sourceId || !operation.targetId || operation.sourceId === operation.targetId) return order;
  return {
    ...order,
    one: moveId(order.one, operation.sourceId, operation.targetId, operation.placement)
  };
}

function moveModuleInTwoColumnOrder(order, operation) {
  const columns = [
    [...(order.two?.[0] || [])],
    [...(order.two?.[1] || [])]
  ];
  const sourceColumnIndex = columns.findIndex((column) => column.includes(operation.sourceId));
  if (sourceColumnIndex < 0) return order;
  const targetColumnIndex = operation.targetType === "item"
    ? columns.findIndex((column) => column.includes(operation.targetId))
    : MODULE_COLUMN_IDS.indexOf(operation.targetGroup);
  if (targetColumnIndex < 0) return order;

  const [movedId] = columns[sourceColumnIndex].splice(columns[sourceColumnIndex].indexOf(operation.sourceId), 1);
  if (operation.targetType === "item") {
    const targetIndex = columns[targetColumnIndex].indexOf(operation.targetId);
    if (targetIndex < 0) return order;
    columns[targetColumnIndex].splice(operation.placement === "after" ? targetIndex + 1 : targetIndex, 0, movedId);
  } else {
    columns[targetColumnIndex].splice(operation.placement === "after" ? columns[targetColumnIndex].length : 0, 0, movedId);
  }
  return { ...order, two: columns };
}

export function AddToolControls({ onAdd }) {
  const [open, setOpen] = useState(false);
  const modules = Object.entries(TOOLBOX_MODULES);

  useEffect(() => {
    if (!open) return undefined;
    return lockBodyScroll();
  }, [open]);

  function addTool(type) {
    onAdd(type);
    setOpen(false);
  }

  return (
    <>
      <div
        className="tool-add-controls"
        aria-label="Ajouter un outil"
      >
        <button
          className="primary tool-add-modal-button"
          type="button"
          onClick={() => setOpen(true)}
        >
          Ajouter un outil
        </button>
        <CompactDropdown
          className="tool-add-quick-dropdown"
          menuClassName="tool-quick-add"
          label="Ajout rapide"
          openOnHover
          closeOnMouseLeave
          renderTrigger={({ open: quickOpen, toggle }) => (
            <button
              className={`primary tool-add-quick-toggle ${quickOpen ? "active" : ""}`}
              type="button"
              onClick={toggle}
              aria-label="Afficher l'ajout rapide"
              aria-expanded={quickOpen}
              title="Ajout rapide"
            >
              <Icon name="dropdown" />
            </button>
          )}
        >
          {({ close }) => (
            <>
              {modules.map(([type, module]) => (
                <button
                  key={type}
                  className="tool-quick-add-button"
                  type="button"
                  onClick={() => {
                    onAdd(type);
                    close();
                  }}
                  aria-label={`Ajouter ${module.label}`}
                  title={module.label}
                >
                  <span className="module-icon" aria-hidden="true">
                    <span className={`module-icon-svg module-icon-${module.icon}`} />
                  </span>
                </button>
              ))}
            </>
          )}
        </CompactDropdown>
      </div>
      {open && createPortal(
        <div className="tool-add-modal-root" role="dialog" aria-modal="true" aria-labelledby="tool-add-modal-title">
          <div className="confirm-backdrop" onClick={() => setOpen(false)} />
          <section className="confirm-modal tool-add-modal">
            <header>
              <h2 id="tool-add-modal-title">Ajouter un outil</h2>
              <button className="drawer-close-button" type="button" onClick={() => setOpen(false)} aria-label="Fermer" title="Fermer">
                <Icon name="close" />
              </button>
            </header>
            <div className="tool-add-grid">
              {modules.map(([type, module]) => (
                <button key={type} className="tool-add-card" type="button" onClick={() => addTool(type)}>
                  <span className="module-icon" aria-hidden="true">
                    <span className={`module-icon-svg module-icon-${module.icon}`} />
                  </span>
                  <span>{module.label}</span>
                </button>
              ))}
            </div>
          </section>
        </div>,
        document.body
      )}
    </>
  );
}

export function ToolboxModules({ toolbox, moduleColumns, context, onRename, onUpdateModule, onDelete, onModuleOrderChange }) {
  const moduleIdSignature = useMemo(() => toolbox.modules.map((module) => module.id).join("|"), [toolbox.modules]);
  const twoColumnOrder = toolbox.moduleOrder?.two || [[], []];
  const orderedModules = useMemo(() => getModulesByIds(toolbox.modules, toolbox.moduleOrder?.one || []), [toolbox.modules, toolbox.moduleOrder?.one, moduleIdSignature]);
  const columns = useMemo(() => [
    getModulesByIds(toolbox.modules, twoColumnOrder[0]),
    getModulesByIds(toolbox.modules, twoColumnOrder[1])
  ], [toolbox.modules, twoColumnOrder, moduleIdSignature]);
  const {
    itemReorder,
    getItemProps,
    getGroupBoundaryProps,
    isItemDragging,
    isItemDropTarget,
    isBoundaryDropTarget,
    getDropPlacement
  } = useGroupedReorder({
    namespace: "toolbox-modules",
    items: toolbox.modules,
    getItemId: (module) => module.id,
    getItemGroup: (module) => moduleColumns === 2 ? getModuleColumnId(module.id, twoColumnOrder) : "",
    getEffectiveGroup: (module) => moduleColumns === 2 ? getModuleColumnId(module.id, twoColumnOrder) : "",
    getParentId: () => toolbox.id,
    reorderFeatures: {
      item: {
        groupChange: moduleColumns === 2,
        boundaryDrop: moduleColumns === 2
      }
    },
    onItemMove: (operation) => {
      const nextOrder = moduleColumns === 2
        ? moveModuleInTwoColumnOrder(toolbox.moduleOrder, operation)
        : moveModuleInOneColumnOrder(toolbox.moduleOrder, operation);
      onModuleOrderChange(nextOrder);
    },
    hierarchy: { enabled: true, stickyParents: true }
  });

  if (moduleColumns === 1) {
    return (
      <section className="modules" data-toolbox-id={toolbox.id} data-layout-cols={moduleColumns}>
        {orderedModules.map((module) => (
          <ModuleShell
            key={module.id}
            toolbox={toolbox}
            module={module}
            context={context}
            reorder={{ itemReorder, getItemProps, isItemDragging, isItemDropTarget, getDropPlacement }}
            itemGroup=""
            onRename={onRename}
            onUpdateModule={onUpdateModule}
            onDelete={onDelete}
          />
        ))}
      </section>
    );
  }

  const hasEmptyColumn = toolbox.modules.length > 1 && columns.some((modules) => modules.length === 0);

  return (
    <section className="modules" data-toolbox-id={toolbox.id} data-layout-cols={moduleColumns}>
      {columns.map((modules, index) => (
        <div className={`module-column ${hasEmptyColumn && !modules.length ? "is-empty-warning" : ""}`} key={MODULE_COLUMN_IDS[index]}>
          <div
            className={`module-column-boundary-drop-zone ${isBoundaryDropTarget({ groupId: MODULE_COLUMN_IDS[index], parentId: toolbox.id, placement: "before" }) ? "is-drop-target" : ""}`}
            {...getGroupBoundaryProps({ groupId: MODULE_COLUMN_IDS[index], parentId: toolbox.id, placement: "before" })}
          />
          {modules.map((module) => (
            <ModuleShell
              key={module.id}
              toolbox={toolbox}
              module={module}
              context={context}
              reorder={{ itemReorder, getItemProps, isItemDragging, isItemDropTarget, getDropPlacement }}
              itemGroup={MODULE_COLUMN_IDS[index]}
              onRename={onRename}
              onUpdateModule={onUpdateModule}
              onDelete={onDelete}
            />
          ))}
          <div
            className={`module-column-boundary-drop-zone ${isBoundaryDropTarget({ groupId: MODULE_COLUMN_IDS[index], parentId: toolbox.id, placement: "after" }) ? "is-drop-target" : ""}`}
            {...getGroupBoundaryProps({ groupId: MODULE_COLUMN_IDS[index], parentId: toolbox.id, placement: "after" })}
          />
        </div>
      ))}
    </section>
  );
}

function ModuleShell({ toolbox, module, context, reorder, itemGroup = "", onRename, onUpdateModule, onDelete }) {
  const definition = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
  const Component = definition.Component;
  const label = definition.label || module.type;
  const [editing, setEditing] = useState(false);
  const scrollable = definition.scrollable && module.scrollable === true;
  const className = [
    "module",
    reorder.isItemDragging(module.id) ? "is-dragging" : "",
    reorder.isItemDropTarget(module.id) ? "is-drop-target" : "",
    reorder.getDropPlacement("item", module.id) === "after" ? "drop-after" : "",
    scrollable ? "is-scrollable" : ""
  ].filter(Boolean).join(" ");

  return (
    <article
      className={className}
      {...reorder.getItemProps({ itemId: module.id, groupId: itemGroup, parentId: toolbox.id })}
    >
      <header>
        <div>
          <button
            className="module-drag-handle"
            type="button"
            onPointerDown={(event) => reorder.itemReorder.startDrag(event, module.id)}
            aria-label={`Déplacer ${module.title || label}`}
            title="Déplacer"
          >
            <Icon name="drag" />
          </button>
          <span className="module-icon" aria-hidden="true">
            <span className={`module-icon-svg module-icon-${definition.icon || "notepad"}`} />
          </span>
          <EditableModuleTitle value={module.title || label} fallback={label} onSave={(title) => onRename(module.id, title)} />
        </div>
        <div>
          {definition.scrollable && (
            <button
              className={`module-scroll-button ${scrollable ? "active" : ""}`}
              onClick={() => onUpdateModule(module.id, (currentModule) => {
                const nextModule = { ...currentModule };
                if (scrollable) {
                  delete nextModule.scrollable;
                } else {
                  nextModule.scrollable = true;
                }
                return nextModule;
              })}
              aria-label={`${scrollable ? "Désactiver" : "Activer"} le scroll de ${module.title || label}`}
              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" : ""}`}
              onClick={() => setEditing((value) => !value)}
              aria-label={`${editing ? "Masquer" : "Afficher"} l'ajout de ${module.title || label}`}
              aria-pressed={editing}
              title={editing ? "Masquer l'ajout" : "Ajouter"}
            >
              <Icon name="add" />
            </button>
          )}
          <button className="module-delete-button danger" onClick={() => onDelete(module.id)} aria-label={`Retirer ${module.title || label}`} title="Retirer">
            <span className="ui-icon ui-icon-trash" aria-hidden="true" />
          </button>
        </div>
      </header>
      <div className={`module-content ${scrollable ? "is-scrollable legacy-scrollbar" : ""}`}>
        <Component toolboxId={toolbox.id} moduleId={module.id} context={context} editing={editing} />
      </div>
    </article>
  );
}

function EditableModuleTitle({ value, fallback, onSave }) {
  const inlineEdit = useInlineEdit({
    value,
    onCommit: (title) => onSave(title || fallback),
    blurOnEscape: true
  });

  return (
    <h2
      {...inlineEdit.getContentEditableProps({
        className: "module-title",
        title: "Cliquer pour renommer"
      })}
    >
      {value}
    </h2>
  );
}
