// ÉTIQUETTES QR — étiquettes imprimables (nom + latin + QR vers la fiche) à
// poser au jardin d'Opio. Deux portes d'entrée : bouton « Étiquette » d'une
// fiche (1 étiquette) et onglet Admin « Étiquettes » (planche A4 en lot).
// Le QR encode le domaine canonique en dur : une étiquette imprimée depuis
// localhost doit pointer la prod.

const ETIQ_SITE_URL = "https://herbierlaopio.fr";

// Chargement paresseux de qrcode-generator (UMD → window.qrcode) : les
// visiteurs qui n'impriment pas d'étiquette ne paient pas la lib. Version
// épinglée + SRI, même politique que React dans Herbier.html.
const QR_SRC = "https://unpkg.com/qrcode-generator@1.4.4/qrcode.js";
const QR_SRI = "sha384-8FWZA6BGMXhsfO+BLtrJK0We6gg5o1JyO8xQm6peWDEUs17ACA5ziE/NIAkl9z2k";
let _qrPromise = null;
function loadQrLib() {
  if (window.qrcode) return Promise.resolve(window.qrcode);
  if (_qrPromise) return _qrPromise;
  _qrPromise = new Promise((resolve, reject) => {
    const s = document.createElement("script");
    s.src = QR_SRC;
    s.integrity = QR_SRI;
    s.crossOrigin = "anonymous";
    s.onload = () => resolve(window.qrcode);
    s.onerror = () => { _qrPromise = null; reject(new Error("Générateur QR indisponible.")); };
    document.head.appendChild(s);
  });
  return _qrPromise;
}

// SVG du QR pour un texte donné (null tant que la lib charge, "erreur" si échec).
// Niveau de correction Q (25 %) : étiquettes exposées dehors, usure/salissures.
function useQrSvg(text) {
  const [svg, setSvg] = React.useState(null);
  React.useEffect(() => {
    let dead = false;
    loadQrLib()
      .then((qrcode) => {
        if (dead) return;
        const qr = qrcode(0, "Q"); // 0 = taille auto selon la longueur du texte
        qr.addData(text);
        qr.make();
        setSvg(qr.createSvgTag({ cellSize: 2, margin: 0, scalable: true }));
      })
      .catch(() => { if (!dead) setSvg("erreur"); });
    return () => { dead = true; };
  }, [text]);
  return svg;
}

// Carcasse commune des étiquettes (~90 × 55 mm) : QR + titre + sous-titre +
// mention. Noir sur blanc volontaire (impression encre + plastification) ;
// le cadre sert de trait de coupe.
function EtiquetteBase({ url, titre, sousTitre, sousTitreSize = "11pt" }) {
  const svg = useQrSvg(url);
  return (
    <div style={{ width: "90mm", height: "55mm", boxSizing: "border-box", background: "#fff", color: "#111", border: "0.3mm solid #111", padding: "4mm 5mm", display: "flex", alignItems: "center", gap: "5mm", fontFamily: "'Cormorant Garamond', 'EB Garamond', Georgia, serif", breakInside: "avoid", pageBreakInside: "avoid" }}>
      <div className="etiquette-qr" style={{ width: "30mm", height: "30mm", flexShrink: 0 }}>
        {svg && svg !== "erreur"
          ? <div style={{ width: "100%", height: "100%" }} dangerouslySetInnerHTML={{ __html: svg }} />
          : <div style={{ width: "100%", height: "100%", display: "grid", placeItems: "center", fontSize: 9, textAlign: "center", border: "0.2mm dashed #999", color: "#666" }}>{svg === "erreur" ? "QR indisponible" : "…"}</div>}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: "16pt", fontWeight: 600, lineHeight: 1.05 }}>{titre}</div>
        <div style={{ fontSize: sousTitreSize, fontStyle: "italic", marginTop: "1.5mm" }}>{sousTitre}</div>
        <div style={{ fontSize: "6.5pt", marginTop: "3mm", letterSpacing: ".08em", textTransform: "uppercase", fontFamily: "'JetBrains Mono', 'Courier New', monospace", color: "#444" }}>Herbier · Les Amis des Jardins d'Opio</div>
      </div>
    </div>
  );
}

// Étiquette d'une PLANTE : QR vers sa fiche.
function EtiquettePlante({ plant }) {
  return <EtiquetteBase url={ETIQ_SITE_URL + "/#/fiche/" + encodeURIComponent(plant.id)} titre={plant.nom} sousTitre={plant.latin} />;
}

// Étiquette d'une ZONE du jardin : QR vers le catalogue filtré sur la zone
// (#/catalogue/jardin/<slug>) — à poser à l'entrée du secteur.
function EtiquetteZone({ zone }) {
  return <EtiquetteBase url={ETIQ_SITE_URL + "/#/catalogue/jardin/" + window.slugifyZone(zone)} titre={zone} sousTitre="Les plantes de cette zone" sousTitreSize="10pt" />;
}

// Aperçu + impression. 1..N étiquettes, réparties en pages A4 de 10 (2 × 5).
// Même mécanique que FichePrint : classe printing-mode sur <body>, print.css
// cache l'app (#root) et montre cette modale (portal hors #root).
function EtiquettesPrintModal({ plants, zones, onClose }) {
  // Impression via un document DÉDIÉ dans une iframe invisible : l'aperçu de
  // Chrome ne rastérise que la planche (styles autoportés), plus le document
  // complet de l'app. Le mécanisme printing-mode (masquer #root, remettre la
  // modale en flux) produisait une page blanche sur certains postes alors que
  // DOM, classe et CSS étaient corrects — l'aperçu échouait à rendre le
  // document complexe. Les étiquettes étant stylées inline, leur outerHTML
  // est autoporteur ; seules les règles de mise en page sont répliquées ici.
  const handlePrint = () => {
    const planche = document.querySelector(".etiquettes-print-modal .print-outer-wrap");
    if (!planche) return;
    const frame = document.createElement("iframe");
    frame.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;visibility:hidden;";
    document.body.appendChild(frame);
    const doc = frame.contentDocument;
    doc.open();
    doc.write([
      "<!doctype html><html><head><meta charset='utf-8'><title>Étiquettes — Herbier</title>",
      "<link href='https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=JetBrains+Mono:wght@400&display=swap' rel='stylesheet'>",
      "<style>",
      "@page { size: A4 portrait; margin: 0; }",
      "html, body { margin: 0; padding: 0; background: #fff; }",
      ".print-outer-wrap { padding: 0 !important; display: block !important; }",
      ".etiquette-page { box-shadow: none !important; margin: 0 auto !important; }",
      ".etiquette-qr svg { width: 100%; height: 100%; display: block; }",
      "</style></head><body>",
      planche.outerHTML,
      "</body></html>",
    ].join(""));
    doc.close();
    const lancer = () => {
      frame.contentWindow.addEventListener("afterprint", () => frame.remove());
      frame.contentWindow.focus();
      frame.contentWindow.print();
    };
    // Attendre les polices du sous-document (rendu fidèle), sans jamais bloquer.
    Promise.race([doc.fonts.ready, new Promise((r) => setTimeout(r, 1500))]).then(lancer);
  };
  // Escape ferme ; Ctrl/Cmd+P passe par le document dédié (même chemin que le
  // bouton). Le filet printing-mode reste pour le menu Chrome → Imprimer.
  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "p") { e.preventDefault(); handlePrint(); }
    };
    const before = () => document.body.classList.add("printing-mode");
    const after = () => document.body.classList.remove("printing-mode");
    window.addEventListener("keydown", onKey);
    window.addEventListener("beforeprint", before);
    window.addEventListener("afterprint", after);
    return () => {
      window.removeEventListener("keydown", onKey);
      window.removeEventListener("beforeprint", before);
      window.removeEventListener("afterprint", after);
      document.body.classList.remove("printing-mode");
    };
  }, []);
  // Zones d'abord (étiquettes d'entrée de secteur), puis plantes.
  const items = [
    ...(zones || []).map((z) => ({ key: "z:" + z, el: <EtiquetteZone zone={z} /> })),
    ...(plants || []).map((p) => ({ key: "p:" + p.id, el: <EtiquettePlante plant={p} /> })),
  ];
  const PAR_PAGE = 10;
  const pages = [];
  for (let i = 0; i < items.length; i += PAR_PAGE) pages.push(items.slice(i, i + PAR_PAGE));
  return ReactDOM.createPortal(
    <div className="etiquettes-print-modal" style={{ position: "fixed", inset: 0, background: "#e8e2d4", zIndex: 1100, overflowY: "auto" }}>
      {/* Le SVG de qrcode-generator (scalable) n'a pas de width/height : on le force à remplir sa case. */}
      <style>{".etiquette-qr svg { width: 100%; height: 100%; display: block; }"}</style>
      <div className="print-toolbar" style={{ position: "sticky", top: 0, display: "flex", gap: 10, justifyContent: "center", padding: "16px 0", background: "rgba(232,226,212,0.95)", zIndex: 2 }}>
        <button className="btn btn-solid" onClick={handlePrint}>Imprimer</button>
        <button className="btn" onClick={onClose}>Fermer</button>
      </div>
      <div className="print-outer-wrap" style={{ padding: 24, display: "flex", flexDirection: "column", alignItems: "center", gap: 24 }}>
        {pages.map((page, i) => (
          <div key={i} className="etiquette-page" style={{ width: "210mm", minHeight: "297mm", background: "#fff", boxSizing: "border-box", padding: "12mm", display: "grid", gridTemplateColumns: "repeat(2, 90mm)", gridAutoRows: "55mm", gap: "5mm", justifyContent: "center", alignContent: "start", boxShadow: "0 2px 14px rgba(0,0,0,0.12)", pageBreakAfter: "always" }}>
            {page.map((it) => <React.Fragment key={it.key}>{it.el}</React.Fragment>)}
          </div>
        ))}
      </div>
    </div>,
    document.body
  );
}

// Panneau Admin « Étiquettes » : composer une planche d'étiquettes en lot.
// Sélection par zone du jardin (data.jardins de la liste légère) ou par
// recherche libre, puis aperçu/impression via EtiquettesPrintModal.
function EtiquettesPanel({ isMobile }) {
  const plants = window.PLANTS || [];
  // Seules les zones ayant au moins une fiche localisée sont proposées.
  const zones = (window.ZONES || []).filter((z) =>
    plants.some((p) => Array.isArray(p.jardins) && p.jardins.includes(z))
  );
  const [selected, setSelected] = React.useState(() => new Set());
  const [selectedZones, setSelectedZones] = React.useState(() => new Set());
  const [query, setQuery] = React.useState("");
  const [printOpen, setPrintOpen] = React.useState(false);
  const toggleZone = (z) => setSelectedZones((prev) => {
    const n = new Set(prev);
    if (n.has(z)) n.delete(z); else n.add(z);
    return n;
  });

  const toggle = (id) => setSelected((prev) => {
    const n = new Set(prev);
    if (n.has(id)) n.delete(id); else n.add(id);
    return n;
  });
  const addZone = (z) => setSelected((prev) => {
    const n = new Set(prev);
    plants.filter((p) => Array.isArray(p.jardins) && p.jardins.includes(z)).forEach((p) => n.add(p.id));
    return n;
  });

  const q = query.trim().toLowerCase();
  const found = q
    ? plants.filter((p) => (p.nom + " " + p.latin).toLowerCase().includes(q) && !selected.has(p.id)).slice(0, 12)
    : [];
  const chosen = plants.filter((p) => selected.has(p.id));
  const chosenZones = (window.ZONES || []).filter((z) => selectedZones.has(z)); // ordre canonique
  const total = chosen.length + chosenZones.length;

  return (
    <div>
      <p style={{ fontFamily: "var(--serif)", fontSize: 16, color: "var(--ink-soft)", lineHeight: 1.55, margin: "0 0 24px", maxWidth: 640 }}>
        Composez une planche d'étiquettes à imprimer et poser au jardin : chaque étiquette
        porte le nom, le latin et un QR code qui ouvre la fiche. Ajoutez une zone entière
        ou cherchez des fiches une à une.
      </p>

      <div className="kicker" style={{ marginBottom: 10, color: "var(--moss-deep)" }}>Par zone du jardin</div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 24 }}>
        {zones.map((z) => {
          const count = plants.filter((p) => Array.isArray(p.jardins) && p.jardins.includes(z)).length;
          return (
            <button key={z} type="button" className="btn" onClick={() => addZone(z)} title={`Ajouter les ${count} fiches de la zone`}>
              {z} <span style={{ opacity: 0.6, marginLeft: 4 }}>({count})</span>
            </button>
          );
        })}
        {!zones.length && (
          <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", color: "var(--ink-mute)" }}>
            Aucune fiche localisée par zone pour l'instant.
          </span>
        )}
      </div>

      <div className="kicker" style={{ marginBottom: 10, color: "var(--moss-deep)" }}>Étiquettes de zone</div>
      <p style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 14, color: "var(--ink-mute)", margin: "0 0 10px" }}>
        L'étiquette de la zone elle-même : son QR ouvre le catalogue filtré sur la zone.
      </p>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 24 }}>
        {zones.map((z) => (
          <button key={z} type="button" className={`tag ${selectedZones.has(z) ? "tag-active" : ""}`} onClick={() => toggleZone(z)} style={{ cursor: "pointer" }}>
            {z}
          </button>
        ))}
        {!zones.length && (
          <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", color: "var(--ink-mute)" }}>
            Aucune zone peuplée pour l'instant.
          </span>
        )}
      </div>

      <div className="kicker" style={{ marginBottom: 10, color: "var(--moss-deep)" }}>Ajouter une fiche</div>
      <input
        type="search"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Nom ou latin…"
        style={{ width: "100%", maxWidth: 420, padding: "10px 14px", fontFamily: "var(--serif)", fontSize: 16, border: "1px solid var(--line)", background: "var(--cream)", boxSizing: "border-box" }}
      />
      {found.length > 0 && (
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginTop: 10 }}>
          {found.map((p) => (
            <button key={p.id} type="button" className="btn" onClick={() => { toggle(p.id); setQuery(""); }}>
              + {p.nom}
            </button>
          ))}
        </div>
      )}

      <div className="kicker" style={{ margin: "28px 0 10px", color: "var(--moss-deep)" }}>
        Sélection — {total} étiquette{total > 1 ? "s" : ""}
      </div>
      {total ? (
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
          {chosenZones.map((z) => (
            <button key={"z:" + z} type="button" className="tag" onClick={() => toggleZone(z)} title="Retirer l'étiquette de zone" style={{ cursor: "pointer", border: "none" }}>
              ◈ {z} ✕
            </button>
          ))}
          {chosen.map((p) => (
            <button key={p.id} type="button" className="tag" onClick={() => toggle(p.id)} title="Retirer de la sélection" style={{ cursor: "pointer", border: "none" }}>
              {p.nom} ✕
            </button>
          ))}
        </div>
      ) : (
        <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", color: "var(--ink-mute)" }}>Sélection vide.</span>
      )}

      <div style={{ display: "flex", gap: 10, marginTop: 28 }}>
        <button className="btn btn-solid" disabled={!total} onClick={() => setPrintOpen(true)} style={{ opacity: total ? 1 : 0.4 }}>
          Aperçu &amp; impression ({Math.ceil(total / 10) || 0} page{total > 10 ? "s" : ""} A4)
        </button>
        {total > 0 && (
          <button className="btn" onClick={() => { setSelected(new Set()); setSelectedZones(new Set()); }}>Tout retirer</button>
        )}
      </div>

      {printOpen && <EtiquettesPrintModal plants={chosen} zones={chosenZones} onClose={() => setPrintOpen(false)} />}
    </div>
  );
}

// Admin.jsx monte le panneau via window.* (même mécanisme que window.Poles etc.).
window.EtiquettesPanel = EtiquettesPanel;
