// CALENDRIER — deux vues enluminées de la floraison du recueil :
//   • La frise enluminée (défaut) — panorama plantes × 12 mois, cliquer un mois
//     rassemble ses floraisons en tête ; survol → aperçu de la planche.
//   • L'Astrolabe Végétal — anneaux concentriques (une plante = un anneau),
//     aiguille du jour, bandeau d'ambiance + vedettes du mois.
//
// Porté de la maquette « Calendrier Variantes », rebranché sur les VRAIES
// données : window.PLANTS (floraison en noms de mois), vraies photos via <Plate>,
// clic → vraie fiche. Tokens de couleur hérités du thème (Papier/Nocturne/Éditorial).
(function () {
  const { useState, useEffect, useRef, useMemo } = React;

  const MOIS_FR = ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"];
  const MOIS_AB = ["jan","fév","mar","avr","mai","juin","juil","août","sep","oct","nov","déc"];

  const CAL_AMBIANCE = [
    "Le sommeil des graines — l'herbier se repose, quelques audacieuses persistent.",
    "Sous le givre, les premières promesses : noisetiers et primevères s'éveillent.",
    "L'année bascule — la sève monte, les talus se constellent.",
    "Tout s'accélère : haies blanches, prairies qui se piquètent de couleurs.",
    "Le grand déploiement — ombelles, aubépines et premiers corymbes.",
    "Le pic de l'année. Tout fleurit à la fois, les prairies bourdonnent.",
    "Plein été — les aromatiques embaument, les achillées blanchissent les talus.",
    "La maturité dorée : derniers corymbes, premières graines.",
    "L'arrière-saison — floraisons tardives et fruits qui rougissent.",
    "Les dernières lueurs : arbousiers et asters ferment le bal.",
    "Le repli — l'herbier se fait rare, le sol se couvre de feuilles.",
    "L'année se referme. Temps de relire les planches au coin du feu.",
  ];
  // Saison par mois (0=hiver, 1=printemps, 2=été, 3=automne) + teintes subtiles
  const CAL_SAISON = [0,0,1,1,1,2,2,2,3,3,3,0];
  const CAL_TINTS = ["rgba(91,127,176,0.07)","rgba(122,151,80,0.09)","rgba(201,164,68,0.10)","rgba(168,116,77,0.10)"];
  const CAL_TINTS_STRONG = ["rgba(91,127,176,0.16)","rgba(122,151,80,0.18)","rgba(201,164,68,0.20)","rgba(168,116,77,0.20)"];
  const CAL_SAISON_NOM = ["Hiver","Printemps","Été","Automne"];

  // floraison (noms de mois) → indices triés ; ex. ["Mai","Juin","Août"] → [4,5,7]
  const moisOf = (p) => (Array.isArray(p.floraison) ? p.floraison : [])
    .map((n) => MOIS_FR.indexOf(n)).filter((i) => i >= 0).sort((a, b) => a - b);

  // Plages contiguës : [5,6,7,9] → [[5,7],[9,9]]
  function calRanges(mois) {
    const m = [...mois].sort((a, b) => a - b);
    const out = [];
    for (const x of m) {
      if (out.length && x === out[out.length - 1][1] + 1) out[out.length - 1][1] = x;
      else out.push([x, x]);
    }
    return out;
  }
  // Position du jour dans l'année (fraction de mois)
  function calToday() {
    const d = new Date();
    const m = d.getMonth();
    const days = new Date(d.getFullYear(), m + 1, 0).getDate();
    return { month: m, frac: (m + (d.getDate() - 1) / days) / 12 };
  }

  // Liste enrichie (ajoute `mois`), plantes sans floraison écartées
  function usePlants() {
    const len = (window.PLANTS || []).length;
    return useMemo(() => (window.PLANTS || [])
      .map((p) => ({ ...p, mois: moisOf(p) }))
      .filter((p) => p.mois.length > 0), [len]);
  }
  const plantsOfMonth = (plants, m) => plants
    .filter((p) => p.mois.includes(m))
    .sort((a, b) => a.nom.localeCompare(b.nom, "fr"));

  /* ---------- Révélation fail-safe au scroll ---------- */
  function CalReveal({ children, className = "", style = {}, delay = 0 }) {
    const ref = useRef(null);
    useEffect(() => {
      const el = ref.current;
      if (!el) return;
      let done = false;
      const reveal = (force) => {
        if (done) return;
        done = true;
        if (force) { el.style.transition = "none"; el.style.opacity = "1"; el.style.transform = "none"; }
        el.classList.add("cal-in");
      };
      let io = null;
      try {
        io = new IntersectionObserver((es) => es.forEach((e) => { if (e.isIntersecting) { setTimeout(() => reveal(false), delay); io && io.unobserve(el); } }), { threshold: 0.1 });
        io.observe(el);
      } catch (e) { reveal(true); }
      const t = setTimeout(() => reveal(true), 700 + delay);
      return () => { clearTimeout(t); io && io.disconnect(); };
    }, []);
    return <div ref={ref} className={`cal-reveal ${className}`} style={style}>{children}</div>;
  }

  /* ---------- Particules de pollen ---------- */
  function Pollen({ n = 14 }) {
    const dots = useMemo(() => Array.from({ length: n }).map(() => ({
      left: Math.random() * 100, top: 20 + Math.random() * 70,
      s: 2.5 + Math.random() * 3.5, dur: 9 + Math.random() * 10, delay: -Math.random() * 12,
      drift: 14 + Math.random() * 26,
    })), [n]);
    return (
      <div className="pollen" aria-hidden="true">
        {dots.map((d, i) => (
          <span key={i} style={{
            left: `${d.left}%`, top: `${d.top}%`, width: d.s, height: d.s,
            animationDuration: `${d.dur}s`, animationDelay: `${d.delay}s`,
            "--drift": `${d.drift}px`,
          }} />
        ))}
      </div>
    );
  }

  /* ---------- Vraie planche / photo ---------- */
  function CalPhoto({ plant, aspect = "4/5", cover = false }) {
    const attribution = plant.thumbFromWikipedia && plant.latin
      ? `https://fr.wikipedia.org/wiki/${encodeURIComponent(plant.latin.replace(/ /g, "_"))}` : null;
    return (
      <Plate src={plant.thumb || null} frame={false} cover={cover}
        attribution={attribution} label={(plant.nom || "").toUpperCase()} aspect={aspect} />
    );
  }

  /* ---------- Aperçu flottant au survol d'une ligne ---------- */
  function useFloatPreview() {
    const [prev, setPrev] = useState(null);
    const canHover = useMemo(() => window.matchMedia && window.matchMedia("(hover: hover)").matches, []);
    const onMove = (plant) => (e) => { if (canHover) setPrev({ plant, x: e.clientX, y: e.clientY }); };
    const onLeave = () => setPrev(null);
    const node = prev ? (
      <div className="float-prev" style={{ left: Math.min(prev.x + 20, window.innerWidth - 230), top: Math.max(prev.y - 170, 12) }}>
        <CalPhoto plant={prev.plant} aspect="4/3" />
        <div className="fp-nom h-display">{prev.plant.nom}</div>
        <div className="fp-lat h-italic">{prev.plant.latin}</div>
        <div className="fp-fl">{calRanges(prev.plant.mois).map(([a, b]) => a === b ? MOIS_AB[a] : `${MOIS_AB[a]} → ${MOIS_AB[b]}`).join(" · ")}</div>
      </div>
    ) : null;
    return { onMove, onLeave, node };
  }

  /* ---------- Bandeau d'ambiance d'un mois ---------- */
  function MonthBandeau({ month, count, onPrev, onNext }) {
    const s = CAL_SAISON[month];
    const isNow = month === new Date().getMonth();
    const touchX = useRef(null);
    return (
      <div className="bandeau" style={{ background: `linear-gradient(120deg, ${CAL_TINTS_STRONG[s]}, transparent 65%)` }}
        onTouchStart={(e) => { touchX.current = e.touches[0].clientX; }}
        onTouchEnd={(e) => {
          if (touchX.current == null) return;
          const dx = e.changedTouches[0].clientX - touchX.current; touchX.current = null;
          if (dx > 55) onPrev(); else if (dx < -55) onNext();
        }}>
        <Pollen n={10} />
        <button className="band-arrow" onClick={onPrev} aria-label="Mois précédent">←</button>
        <div className="band-center">
          <div className="kicker" style={{ marginBottom: 8 }}>{CAL_SAISON_NOM[s]} · {count} plante{count > 1 ? "s" : ""} en fleur</div>
          <h2 className={`h-display band-month ${isNow ? "breathe" : ""}`}>{MOIS_FR[month]}</h2>
          <p className="band-poesie">{CAL_AMBIANCE[month]}</p>
        </div>
        <button className="band-arrow" onClick={onNext} aria-label="Mois suivant">→</button>
      </div>
    );
  }

  /* ---------- Vedettes + grille du mois ---------- */
  function MonthVedettes({ plants, month, onOpen }) {
    const stars = plants.slice(0, 3);
    const rest = plants.slice(3);
    return (
      <div>
        {stars.length > 0 && (
          <div className="vedettes">
            {stars.map((p, i) => (
              <CalReveal key={p.id} delay={i * 90}>
                <article className="vedette" onClick={() => onOpen(p.id)}>
                  <CalPhoto plant={p} aspect="4/5" />
                  <div className="ved-body">
                    <span className="kicker">{p.famille}</span>
                    <span className="h-display ved-nom">{p.nom}</span>
                    <span className="h-italic ved-lat">{p.latin}</span>
                    {p.mois[0] === month && <span className="ved-badge">débute ce mois-ci</span>}
                    {p.mois[p.mois.length - 1] === month && p.mois[0] !== month && <span className="ved-badge fin">dernière chance</span>}
                  </div>
                </article>
              </CalReveal>
            ))}
          </div>
        )}
        {rest.length > 0 && (
          <div className="mois-grid">
            {rest.map((p, i) => (
              <CalReveal key={p.id} delay={Math.min(i, 8) * 50}>
                <article className="mois-card" onClick={() => onOpen(p.id)}>
                  <CalPhoto plant={p} aspect="1/1" />
                  <span className="mc-nom">{p.nom}</span>
                  <span className="mc-lat h-italic">{p.latin}</span>
                </article>
              </CalReveal>
            ))}
          </div>
        )}
        {plants.length === 0 && (
          <p className="cal-empty">Aucune floraison documentée ce mois-ci — le recueil hiverne.</p>
        )}
      </div>
    );
  }

  /* ============================================================
     LA ROUE DE L'ANNÉE
     ============================================================ */
  function polar(angleDeg, r) {
    const a = (angleDeg - 90) * Math.PI / 180;
    return [Math.cos(a) * r, Math.sin(a) * r];
  }
  function ringArc(a0, a1, r) {
    const [x0, y0] = polar(a0, r), [x1, y1] = polar(a1, r);
    const large = a1 - a0 > 180 ? 1 : 0;
    return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1}`;
  }
  function Roue({ goFiche }) {
    const allPlants = usePlants();
    const today = calToday();
    const [month, setMonth] = useState(today.month);
    const [hov, setHov] = useState(null);
    const plants = useMemo(() => [...allPlants].sort((a, b) => a.mois[0] - b.mois[0] || a.mois.length - b.mois.length), [allPlants]);
    const monthPlants = plantsOfMonth(allPlants, month);
    const todayAngle = today.frac * 360;
    // Géométrie de l'astrolabe. Les anneaux remplissent la bande [R0, RMAX] et ne
    // dépassent jamais le disque des mois (RSECT), quel que soit le nombre de plantes.
    const R0 = 66, RSECT = 184, RLABEL = 193, VB = 200;
    const RMAX = RSECT - 6;
    const STEP = Math.min(4, (RMAX - R0) / Math.max(plants.length - 1, 1));

    return (
      <div className="cv1">
        <header className="cal-head">
          <div className="kicker">Calendrier · floraison &amp; cueillette</div>
          <h1 className="h-display cal-title">L'Astrolabe <span className="h-italic" style={{ color: "var(--moss-deep)" }}>Végétal.</span></h1>
          <p className="cal-lede">« Surnommé la Machine d'Opiocythère, cet astrolabe végétal mesure le rythme de notre terre. Chaque anneau est une plante, chaque arc sa saison de floraison. »</p>
        </header>

        <div className="cv1-wheelzone">
          <svg viewBox={`${-VB} ${-VB} ${VB * 2} ${VB * 2}`} className="cv1-svg">
            {MOIS_FR.map((m, i) => {
              const a0 = i * 30 + 0.6, a1 = (i + 1) * 30 - 0.6;
              const active = i === month;
              const s = CAL_SAISON[i];
              const [lx, ly] = polar(i * 30 + 15, RLABEL);
              const p0 = polar(a0, R0 - 8), p1 = polar(a1, R0 - 8), p2 = polar(a1, RSECT), p3 = polar(a0, RSECT);
              return (
                <g key={m} onClick={() => setMonth(i)} style={{ cursor: "pointer" }}>
                  <path d={`M ${p0[0]} ${p0[1]} A ${R0 - 8} ${R0 - 8} 0 0 1 ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]} A ${RSECT} ${RSECT} 0 0 0 ${p3[0]} ${p3[1]} Z`}
                    fill={active ? CAL_TINTS_STRONG[s] : "transparent"}
                    stroke="var(--line-soft)" strokeWidth="0.5" className="cv1-sector" />
                  <text x={lx} y={ly} textAnchor="middle" dominantBaseline="middle"
                    className={`cv1-mlabel ${active ? "on" : ""} ${i === today.month ? "now" : ""}`}>
                    {MOIS_AB[i]}
                  </text>
                </g>
              );
            })}

            {plants.map((p, i) => {
              const r = R0 + i * STEP;
              const inMonth = p.mois.includes(month);
              const isHov = hov === p.id;
              return (
                <g key={p.id}
                  onMouseEnter={() => setHov(p.id)} onMouseLeave={() => setHov(null)}
                  onClick={() => goFiche(p.id)} style={{ cursor: "pointer" }}>
                  {calRanges(p.mois).map(([a, b], j) => (
                    <path key={j}
                      d={ringArc(a * 30 + 2.5, (b + 1) * 30 - 2.5, r)}
                      pathLength="100"
                      style={{ "--ad": `${Math.min(i, 24) * 28}ms` }}
                      fill="none"
                      stroke={isHov ? "var(--rust)" : "var(--moss-deep)"}
                      strokeWidth={isHov ? 3.2 : 1.9}
                      strokeLinecap="round"
                      opacity={inMonth ? (isHov ? 1 : 0.8) : 0.14}
                      className="cv1-arc" />
                  ))}
                </g>
              );
            })}

            <g transform={`rotate(${todayAngle})`}>
              <line x1="0" y1={-(R0 - 14)} x2="0" y2={-(RMAX + 2)} stroke="var(--rust)" strokeWidth="1.2" strokeDasharray="3 3" />
              <circle cy={-(RMAX + 2)} r="3" fill="var(--rust)" />
            </g>

            <circle r={R0 - 16} fill="var(--cream)" stroke="var(--line)" strokeWidth="0.8" />
            <text y="-12" textAnchor="middle" className="cv1-center-n">{monthPlants.length}</text>
            <text y="6" textAnchor="middle" className="cv1-center-l">EN FLEUR</text>
            <text y="22" textAnchor="middle" className="cv1-center-m">{MOIS_FR[month].toUpperCase()}</text>
          </svg>

          <div className="cv1-side">
            <div className="kicker" style={{ marginBottom: 12 }}>{hov ? "Sous le curseur" : "Légende"}</div>
            {hov ? (() => {
              const p = allPlants.find((x) => x.id === hov);
              if (!p) return null;
              return (
                <div className="cv1-hovcard">
                  <CalPhoto plant={p} aspect="4/3" />
                  <div className="h-display" style={{ fontSize: 22, marginTop: 10 }}>{p.nom}</div>
                  <div className="h-italic" style={{ fontSize: 15, color: "var(--moss-deep)" }}>{p.latin}</div>
                  <div className="fp-fl" style={{ marginTop: 8 }}>{calRanges(p.mois).map(([a, b]) => a === b ? MOIS_AB[a] : `${MOIS_AB[a]} → ${MOIS_AB[b]}`).join(" · ")}</div>
                </div>
              );
            })() : (
              <ul className="cv1-legend">
                <li><span className="lg-arc" /> un anneau = une plante</li>
                <li><span className="lg-arc dim" /> hors du mois choisi</li>
                <li><span className="lg-needle" /> aiguille — nous sommes ici</li>
                <li><span className="lg-sector" /> mois sélectionné</li>
              </ul>
            )}
          </div>
        </div>

        <section className="cal-month-section">
          <MonthBandeau month={month} count={monthPlants.length}
            onPrev={() => setMonth((m) => (m + 11) % 12)} onNext={() => setMonth((m) => (m + 1) % 12)} />
          <MonthVedettes plants={monthPlants} month={month} onOpen={goFiche} />
        </section>
      </div>
    );
  }

  /* ============================================================
     LA FRISE ENLUMINÉE
     ============================================================ */
  function Frise({ goFiche }) {
    const allPlants = usePlants();
    const today = calToday();
    const [selMonth, setSelMonth] = useState(null);
    const { onMove, onLeave, node } = useFloatPreview();

    const rows = useMemo(() => {
      const all = [...allPlants].sort((a, b) => a.nom.localeCompare(b.nom, "fr"));
      if (selMonth == null) return all;
      return [
        ...all.filter((p) => p.mois.includes(selMonth)).sort((a, b) => a.mois[0] - b.mois[0]),
        ...all.filter((p) => !p.mois.includes(selMonth)),
      ];
    }, [selMonth, allPlants]);

    return (
      <div className="cv2">
        <header className="cal-head">
          <div className="kicker">Calendrier · floraison &amp; cueillette</div>
          <h1 className="h-display cal-title">La frise <span className="h-italic" style={{ color: "var(--moss-deep)" }}>qui défrise.</span></h1>
          <p className="cal-lede">Toute l'année d'un regard. Cliquez un mois pour rassembler ses floraisons en tête de frise ; survolez une ligne pour apercevoir la planche, cliquez pour ouvrir la fiche.</p>
        </header>

        <div className="cv2-frise">
          <div className="cv2-row cv2-headrow">
            <div className="cv2-label" />
            <div className="cv2-cells">
              {MOIS_AB.map((m, i) => (
                <button key={i}
                  className={`cv2-mh ${selMonth === i ? "on" : ""} ${i === today.month ? "now" : ""}`}
                  onClick={() => setSelMonth(selMonth === i ? null : i)}>
                  {m}
                  <span className="cv2-mh-count">{plantsOfMonth(allPlants, i).length}</span>
                </button>
              ))}
            </div>
          </div>

          <div className="cv2-body">
            <div className="cv2-overlay" aria-hidden="true">
              {selMonth != null && (
                <span className="cv2-colsel" style={{ left: `${selMonth / 12 * 100}%`, width: `${100 / 12}%`, background: CAL_TINTS_STRONG[CAL_SAISON[selMonth]] }} />
              )}
              <span className="cv2-today" style={{ left: `${today.frac * 100}%` }}>
                <i>aujourd'hui</i>
              </span>
            </div>

            {rows.map((p, idx) => {
              const inSel = selMonth == null || p.mois.includes(selMonth);
              return (
                <div key={p.id} className={`cv2-row cv2-plantrow ${inSel ? "" : "dim"}`}
                  onMouseMove={onMove(p)} onMouseLeave={onLeave}
                  onClick={() => goFiche(p.id)}
                  style={{ "--d": `${Math.min(idx, 16) * 45}ms`, cursor: "pointer" }}>
                  <div className="cv2-label">
                    <span className="cv2-nom">{p.nom}</span>
                    <span className="cv2-lat h-italic">{p.latin}</span>
                  </div>
                  <div className="cv2-cells">
                    {calRanges(p.mois).map(([a, b], j) => (
                      <span key={j} className="cv2-bar"
                        style={{
                          left: `calc(${a / 12 * 100}% + 3px)`,
                          width: `calc(${(b - a + 1) / 12 * 100}% - 6px)`,
                        }} />
                    ))}
                  </div>
                </div>
              );
            })}
          </div>

          <div className="cv2-foot">
            <span className="lg"><span className="lg-bar" /> floraison</span>
            <span className="lg"><span className="lg-today" /> date du jour</span>
            {selMonth != null && <button className="cv2-clear" onClick={() => setSelMonth(null)}>× Tout réafficher</button>}
          </div>
        </div>
        {node}
      </div>
    );
  }

  /* ============================================================
     PAGE — switch Frise (défaut) / Roue
     ============================================================ */
  function Calendrier({ setRoute, setPlantId }) {
    const goFiche = (id) => { setPlantId(id); setRoute("fiche"); };
    const [v, setV] = useState(() => {
      try { return localStorage.getItem("cal-view") || "frise"; } catch (e) { return "frise"; }
    });
    useEffect(() => { try { localStorage.setItem("cal-view", v); } catch (e) {} }, [v]);

    return (
      <main className="page-enter cal-immersive anim">
        <div className="cal-vswitch" role="group" aria-label="Type de vue">
          <div className="cal-vswitch-pill">
            {[["frise", "La Frise"], ["roue", "L'Astrolabe"]].map(([k, l]) => (
              <button key={k} className={v === k ? "on" : ""} onClick={() => setV(k)}>{l}</button>
            ))}
          </div>
        </div>
        {v === "roue" ? <Roue goFiche={goFiche} /> : <Frise goFiche={goFiche} />}
      </main>
    );
  }

  window.Calendrier = Calendrier;
})();
