// Rôle : affiche les images en modale, avec support des annotations.
import { useEffect, useRef, useState } from "react";
import { DrawingControls } from "../features/toolboxes/modules/DrawingControls.jsx";
import { DrawingOverlay } from "../features/toolboxes/modules/DrawingOverlay.jsx";
import { lockBodyScroll } from "../utils/bodyScrollLock.js";
import { Icon } from "./Icon.jsx";
import { Tooltip } from "./Tooltip.jsx";

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

function clampPercent(value) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) return 0;
  return Math.min(100, Math.max(0, parsed));
}

function dataUrlToBlob(dataUrl) {
  const [meta, payload] = String(dataUrl).split(",");
  const mime = meta.match(/^data:([^;]+);base64$/)?.[1] || "image/png";
  const binary = atob(payload || "");
  const bytes = new Uint8Array(binary.length);
  for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
  return new Blob([bytes], { type: mime });
}

function openImageInNewTab(dataUrl) {
  try {
    const url = URL.createObjectURL(dataUrlToBlob(dataUrl));
    window.open(url, "_blank", "noopener,noreferrer");
    setTimeout(() => URL.revokeObjectURL(url), 60000);
  } catch {
    window.open(dataUrl, "_blank", "noopener,noreferrer");
  }
}

export function ImageViewer({ image, onClose, createMarkerId = () => globalThis.crypto?.randomUUID?.() || `marker-${Date.now()}` }) {
  useEffect(() => lockBodyScroll(), []);
  const canAnnotate = Boolean(image.canAnnotate && image.onChangeMarkers);
  const canDraw = Boolean(canAnnotate && image.onChangeDrawings);
  const [viewerMarkers, setViewerMarkers] = useState(() => Array.isArray(image.markers) ? image.markers : []);
  const [viewerDrawings, setViewerDrawings] = useState(() => image.drawings?.strokes ? image.drawings : { strokes: [] });
  const [drawingMode, setDrawingMode] = useState(image.drawingMode === "temporary" ? "temporary" : "permanent");
  const [drawingActive, setDrawingActive] = useState(false);
  const [eraseActive, setEraseActive] = useState(false);
  const [drawingColor, setDrawingColor] = useState("#f6c453");
  const [drawingWidth, setDrawingWidth] = useState(4);
  const viewerRef = useRef(null);
  const mediaRef = useRef(null);
  const hasMarkers = viewerMarkers.length > 0;

  useEffect(() => {
    setViewerMarkers(Array.isArray(image.markers) ? image.markers : []);
    setViewerDrawings(image.drawings?.strokes ? image.drawings : { strokes: [] });
    setDrawingMode(image.drawingMode === "temporary" ? "temporary" : "permanent");
    setDrawingActive(false);
    setEraseActive(false);
  }, [image]);

  useEffect(() => {
    if (!viewerRef.current || !mediaRef.current) return undefined;
    const viewer = viewerRef.current;
    const frame = mediaRef.current;

    function syncImageHeight() {
      const maxHeight = Math.max(400, window.innerHeight * 0.8);
      const height = Math.min(maxHeight, Math.max(400, Math.round(frame.getBoundingClientRect().height)));
      viewer.style.setProperty("--viewer-image-height", `${height}px`);
    }

    syncImageHeight();
    const observer = new ResizeObserver(syncImageHeight);
    observer.observe(frame);
    window.addEventListener("resize", syncImageHeight);
    return () => {
      observer.disconnect();
      window.removeEventListener("resize", syncImageHeight);
    };
  }, [image.dataUrl, canAnnotate]);

  useEffect(() => {
    const onKeyDown = (event) => {
      if (event.key === "Escape") onClose();
    };
    document.addEventListener("keydown", onKeyDown);
    return () => document.removeEventListener("keydown", onKeyDown);
  }, [onClose]);

  function updateViewerMarkers(nextMarkers) {
    setViewerMarkers(nextMarkers);
    image.onChangeMarkers?.(nextMarkers);
  }

  function updateViewerDrawings(nextStrokes) {
    const nextDrawings = { strokes: nextStrokes };
    setViewerDrawings(nextDrawings);
    image.onChangeDrawings?.(nextDrawings, drawingMode);
  }

  function toggleDrawingMode() {
    const nextMode = drawingMode === "permanent" ? "temporary" : "permanent";
    setDrawingMode(nextMode);
    image.onChangeDrawingMode?.(nextMode, viewerDrawings);
  }

  function getMediaSurfaceSize() {
    return {
      width: mediaRef.current?.clientWidth || 0,
      height: mediaRef.current?.clientHeight || 0
    };
  }

  function addViewerMarker(event) {
    if (!canAnnotate || !mediaRef.current) return;
    if (drawingActive || event.target.closest(".drawing-controls-panel")) return;
    const rect = mediaRef.current.getBoundingClientRect();
    const nextMarkers = [
      ...viewerMarkers,
      {
        id: createMarkerId(),
        label: "",
        x: clampPercent(((event.clientX - rect.left) / rect.width) * 100),
        y: clampPercent(((event.clientY - rect.top) / rect.height) * 100)
      }
    ];
    updateViewerMarkers(nextMarkers);
  }

  function updateViewerMarker(markerId, updater) {
    updateViewerMarkers(viewerMarkers.map((marker) => marker.id === markerId ? updater(marker) : marker));
  }

  function removeViewerMarker(markerId) {
    updateViewerMarkers(viewerMarkers.filter((marker) => marker.id !== markerId));
  }

  return (
    <div className="image-viewer-root">
      <div className="image-viewer-backdrop" onClick={onClose} />
      <section ref={viewerRef} className="image-viewer" role="dialog" aria-modal="true" aria-label="Image">
        <header>
          {image.label && <strong className="image-viewer-title">{image.label}</strong>}
          <div className="image-viewer-actions">
            {!canAnnotate && !hasMarkers && (
              <button className="image-viewer-button" onClick={() => openImageInNewTab(image.dataUrl)} aria-label="Ouvrir l'image en taille réelle" title="Taille réelle"><Icon name="zoom" /></button>
            )}
            <button className="image-viewer-button" onClick={onClose} aria-label="Fermer" title="Fermer"><Icon name="close" /></button>
          </div>
        </header>
        <div className={`image-viewer-body ${canAnnotate ? "has-annotation-side" : ""}`}>
          <div className={`image-viewer-media ${canAnnotate ? "can-annotate" : ""}`}>
            <div
              ref={mediaRef}
              className="image-viewer-image-frame"
              onClick={addViewerMarker}
              role={canAnnotate ? "button" : undefined}
              tabIndex={canAnnotate ? 0 : undefined}
              aria-label={canAnnotate ? image.addMarkerAriaLabel || "Ajouter un marqueur sur l'image" : undefined}
            >
              <img src={image.dataUrl} alt={image.alt || "Image"} />
              <DrawingOverlay
                active={drawingActive}
                erase={eraseActive}
                strokes={viewerDrawings.strokes}
                color={drawingColor}
                width={drawingWidth}
                onChange={updateViewerDrawings}
                getSurfaceSize={getMediaSurfaceSize}
                createStrokeId={image.createStrokeId}
                coordinateMode="percent"
              />
              {canDraw && (
                <DrawingControls
                  textContent={image}
                  active={drawingActive}
                  onToggleActive={() => setDrawingActive((value) => !value)}
                  eraseActive={eraseActive}
                  onToggleErase={() => setEraseActive((value) => !value)}
                  color={drawingColor}
                  colors={DRAWING_COLORS}
                  onColorChange={setDrawingColor}
                  width={drawingWidth}
                  widths={DRAWING_WIDTHS}
                  onWidthChange={setDrawingWidth}
                  onUndo={() => updateViewerDrawings(viewerDrawings.strokes.slice(0, -1))}
                  onClear={() => updateViewerDrawings([])}
                  storageMode={drawingMode}
                  onToggleStorageMode={toggleDrawingMode}
                />
              )}
              {viewerMarkers.map((marker, index) => (
                <Tooltip
                  as="span"
                  className="annotation-marker image-viewer-marker"
                  key={marker.id || `${marker.x}-${marker.y}-${index}`}
                  content={marker.label || `${image.markerPrefix || "Marqueur"} ${index + 1}`}
                  position="top"
                  style={{ "--marker-x": `${marker.x}%`, "--marker-y": `${marker.y}%` }}
                >
                  {index + 1}
                </Tooltip>
              ))}
            </div>
          </div>
          {canAnnotate && (
            <aside className="image-viewer-side">
              <strong>{viewerMarkers.length} {viewerMarkers.length > 1 ? "marqueurs" : "marqueur"}</strong>
              {viewerMarkers.length ? (
                <ol className="annotation-marker-list themed-scrollbar">
                  {viewerMarkers.map((marker, index) => (
                    <li key={marker.id}>
                      <span>{index + 1}</span>
                      <input
                        value={marker.label}
                        placeholder={image.markerPlaceholder || "Libellé du marqueur"}
                        onChange={(event) => updateViewerMarker(marker.id, (item) => ({ ...item, label: event.target.value }))}
                        aria-label={`Libellé du marqueur ${index + 1}`}
                      />
                      <button className="tool-split-action-button danger" type="button" onClick={() => removeViewerMarker(marker.id)} aria-label={`${image.deleteMarkerTitle || "Supprimer"} ${marker.label || `${image.markerPrefix || "Marqueur"} ${index + 1}`}`} title={image.deleteMarkerTitle || "Supprimer"}>
                        <Icon name="trash" />
                      </button>
                    </li>
                  ))}
                </ol>
              ) : (
                <p className="muted">Cliquez sur l'image pour ajouter un marqueur.</p>
              )}
            </aside>
          )}
        </div>
      </section>
    </div>
  );
}
