// site/components.jsx — Primitives partagées : Section, Eyebrow, Card, Marker

// ─── Animation au scroll ──────────────────────────────────────────
// Hook : se déclenche à chaque entrée dans le viewport (re-joue l'animation
// quand on remonte / redescend sur l'élément). Pass `{ once: true }` pour
// ne déclencher qu'une fois.
function useInView({ once = false, ...opts } = {}) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    if (typeof IntersectionObserver === "undefined") { setSeen(true); return; }
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) {
        setSeen(true);
        if (once) obs.disconnect();
      } else if (!once) {
        setSeen(false);
      }
    }, { rootMargin: "0px 0px -8% 0px", threshold: 0, ...opts });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  return [ref, seen];
}

// Composant : enveloppe ses enfants avec un fade + translate qui se
// déclenche quand l'élément passe à l'écran. Stagger via `delay`.
function Reveal({ children, delay = 0, y = 16, duration = 0.55, style = {}, as: As = "div", ...rest }) {
  const [ref, seen] = useInView();
  return (
    <As ref={ref} {...rest} style={{
      ...style,
      opacity: seen ? 1 : 0,
      transform: seen ? "translateY(0)" : `translateY(${y}px)`,
      transition: `opacity ${duration}s cubic-bezier(.2,.7,.3,1) ${delay}s, transform ${duration}s cubic-bezier(.2,.7,.3,1) ${delay}s`,
      willChange: seen ? "auto" : "opacity, transform",
    }}>{children}</As>
  );
}

// Section header — eyebrow mono + grand titre serif + sous-titre optionnel
function SectionHeader({ eyebrow, suit, title, subtitle, align = "left", marker, rule = true, ruleColor }) {
  const [ref, seen] = useInView();
  const item = (delay) => ({
    opacity: seen ? 1 : 0,
    transform: seen ? "translateY(0)" : "translateY(16px)",
    transition: `opacity .55s cubic-bezier(.2,.7,.3,1) ${delay}s, transform .55s cubic-bezier(.2,.7,.3,1) ${delay}s`,
  });
  const accent = ruleColor || T.or;
  return (
    <div ref={ref} style={{
      textAlign: align, display: "flex", flexDirection: "column",
      alignItems: align === "center" ? "center" : "flex-start",
      gap: 8, marginBottom: rule ? 32 : 28,
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, ...item(0) }}>
        {suit && <span style={{ color: T.or, fontFamily: T.bold, fontSize: 16 }}>{suit}</span>}
        <span className="eyebrow">{eyebrow}</span>
        {marker && <span className="eyebrow-small" style={{ color: T.inkMute }}>· {marker}</span>}
      </div>
      <div style={{ position: "relative", display: "inline-block", maxWidth: "100%", ...item(0.1) }}>
        <div className="display-bold" style={{ fontSize: "clamp(38px, 6vw, 64px)", color: T.ink }}>
          {title}
        </div>
        {rule && (
          <div style={{
            position: "absolute", bottom: -12, left: 0, right: 0,
            height: 2, background: accent,
            transformOrigin: align === "center" ? "center" : "left",
            transform: seen ? "scaleX(1)" : "scaleX(0)",
            transition: "transform 1.2s cubic-bezier(.4,0,.2,1) .35s",
          }} />
        )}
      </div>
      {subtitle && (
        <div style={{
          fontFamily: T.italic, fontStyle: "italic", fontSize: "clamp(16px, 2vw, 19px)",
          color: T.inkSoft, lineHeight: 1.5, maxWidth: 540, marginTop: rule ? 14 : 4,
          ...item(0.2),
        }}>
          {subtitle}
        </div>
      )}
    </div>
  );
}

// Section wrapper — padding vertical, optionnel fond + lavis aquarelle
// Le lavis est volontairement plus grand que la section (110% + scale) et
// masqué avec un radial-gradient pour fondre les bords — pas d'effet
// "bord coupé" même si la section est plus haute que l'image.
function Section({ id, bg = "transparent", paddingTop = 80, paddingBottom = 80, children, style = {}, washHue, washOpacity = 0.3, washScale = 1.3 }) {
  return (
    <section id={id} style={{
      background: bg, padding: `${paddingTop}px 0 ${paddingBottom}px`,
      position: "relative", overflow: "hidden", ...style,
    }}>
      {washHue !== undefined && (
        <div style={{
          position: "absolute", inset: 0, pointerEvents: "none", zIndex: 0,
          // Mask radial qui fond les bords vers transparent
          maskImage: "linear-gradient(to bottom, transparent 0%, #000 20%, #000 70%, transparent 100%)",
WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, #000 20%, #000 70%, transparent 100%)",
        }}>
          <img src="assets/wc-strokes.jpg" alt="" style={{
            position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover",
            mixBlendMode: "multiply", opacity: washOpacity,
            filter: `hue-rotate(${washHue}deg) saturate(0.9)`,
            transform: `scale(${washScale})`, transformOrigin: "center",
          }}/>
        </div>
      )}
      <div className="wrap" style={{ position: "relative", zIndex: 1 }}>{children}</div>
    </section>
  );
}

// Bandeau noir top — miroir du footer, ouvre le site
function TopBanner() {
  return (
    <div style={{
      width: "100%", background: T.ink, color: T.white,
      padding: "18px 24px", textAlign: "center",
      display: "flex", justifyContent: "center", alignItems: "center", gap: 18,
      flexWrap: "wrap",
    }}>
      <span style={{ fontFamily: T.mono, fontSize: 10, letterSpacing: 4, textTransform: "uppercase", color: T.or }}>
        ★ Save the date ★
      </span>
      <span style={{ fontFamily: T.italic, fontStyle: "italic", fontSize: 15, color: "rgba(255,255,255,0.85)" }}>
        Enora <span style={{ color: T.or, padding: "0 4px" }}>&amp;</span> Antoine · 21 / 08 / 2027 · Château Sentout
      </span>
    </div>
  );
}

// Carte (style playing card light) — utilisée pour les blocs d'info
function Card({ children, accent = T.or, suit, style = {}, hover = true }) {
  const [h, setH] = React.useState(false);
  return (
    <div onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        position: "relative", background: T.card, padding: "24px 24px 24px",
        border: `1px solid ${T.ruleSoft}`,
        boxShadow: hover && h ? T.shadowCard : T.shadow,
        transform: hover && h ? "translateY(-2px)" : "translateY(0)",
        transition: "transform .2s ease, box-shadow .2s ease",
        ...style,
      }}>
      {suit && (
        <>
          <div style={{ position: "absolute", top: 14, left: 14, color: accent, fontFamily: T.bold, fontSize: 14, fontWeight: 700 }}>{suit}</div>
          <div style={{ position: "absolute", bottom: 14, right: 14, color: accent, fontFamily: T.bold, fontSize: 14, fontWeight: 700, transform: "rotate(180deg)" }}>{suit}</div>
        </>
      )}
      {children}
    </div>
  );
}

// "&" doré stylisé — utilisé pour le hero et entre les noms
function GoldAmpersand({ size = 48 }) {
  return (
    <span style={{
      fontFamily: T.italic, fontStyle: "italic", fontWeight: 400, fontSize: size,
      color: T.or, lineHeight: 1, letterSpacing: 0,
    }}>
      &amp;
    </span>
  );
}

// Bouton primaire (rouge cardinal)
function ButtonPrimary({ children, onClick, type = "button", style = {}, full = false }) {
  const [h, setH] = React.useState(false);
  return (
    <button type={type} onClick={onClick}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 10,
        padding: "14px 28px", background: h ? T.rougeDeep : T.rouge, color: T.white,
        border: "none", fontFamily: T.mono, fontSize: 11, letterSpacing: 3,
        textTransform: "uppercase", fontWeight: 600, cursor: "pointer",
        transition: "background .15s",
        width: full ? "100%" : "auto",
        ...style,
      }}>
      {children}
    </button>
  );
}

// Bouton secondaire (outline noir)
function ButtonSecondary({ children, onClick, href, style = {}, full = false }) {
  const [h, setH] = React.useState(false);
  const Comp = href ? "a" : "button";
  return (
    <Comp onClick={onClick} href={href} target={href ? "_blank" : undefined} rel={href ? "noopener noreferrer" : undefined}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 10,
        padding: "13px 26px", background: h ? T.ink : "transparent", color: h ? T.white : T.ink,
        border: `1.5px solid ${T.ink}`, fontFamily: T.mono, fontSize: 11, letterSpacing: 3,
        textTransform: "uppercase", fontWeight: 600, cursor: "pointer",
        transition: "all .15s", textDecoration: "none",
        width: full ? "100%" : "auto",
        ...style,
      }}>
      {children}
    </Comp>
  );
}

// Suit marker (petit ♠♥♦♣ pour distinguer les sections)
function SuitMarker({ suit = "♥", color = T.or, size = 14 }) {
  return (
    <span style={{ fontFamily: T.bold, fontWeight: 700, fontSize: size, color, letterSpacing: 0 }}>{suit}</span>
  );
}

// Séparateur ornemental (filet + suit central)
function OrnamentDivider({ suit = "♠", color = T.or }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 14, color }}>
      <div style={{ flex: 1, height: 1, background: color, opacity: 0.4 }} />
      <SuitMarker suit={suit} color={color} size={12} />
      <div style={{ flex: 1, height: 1, background: color, opacity: 0.4 }} />
    </div>
  );
}

// Compte à rebours hook
function useCountdownTo(iso) {
  const [now, setNow] = React.useState(() => Date.now());
  React.useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);
  const diff = Math.max(0, new Date(iso).getTime() - now);
  return {
    d: Math.floor(diff / 86400000),
    h: Math.floor((diff % 86400000) / 3600000),
    m: Math.floor((diff % 3600000) / 60000),
    s: Math.floor((diff % 60000) / 1000),
  };
}

// Compte à rebours visuel — variant compact ou large
function Countdown({ iso, variant = "default" }) {
  const cd = useCountdownTo(iso);
  const items = [
    { v: cd.d, l: "jours" }, { v: cd.h, l: "h" }, { v: cd.m, l: "min" }, { v: cd.s, l: "s" },
  ];
  if (variant === "compact") {
    return (
      <div style={{ display: "flex", gap: 14, fontVariantNumeric: "tabular-nums", justifyContent: "center" }}>
        {items.map((x) => (
          <div key={x.l} style={{ textAlign: "center" }}>
            <div style={{ fontFamily: T.bold, fontWeight: 700, fontSize: 24, lineHeight: 1, color: T.ink }}>{String(x.v).padStart(2, "0")}</div>
            <div style={{ fontFamily: T.mono, fontSize: 9, color: T.inkSoft, letterSpacing: 2, marginTop: 4, textTransform: "uppercase" }}>{x.l}</div>
          </div>
        ))}
      </div>
    );
  }
  return (
    <div style={{
      display: "flex", justifyContent: "space-between", gap: 16,
      padding: "20px 28px", background: T.ink, color: T.white,
      fontVariantNumeric: "tabular-nums",
    }}>
      {items.map((x) => (
        <div key={x.l} style={{ flex: 1, textAlign: "center", minWidth: 0 }}>
          <div style={{ fontFamily: T.bold, fontWeight: 700, fontSize: "clamp(28px, 5vw, 44px)", lineHeight: 1, color: T.or }}>{String(x.v).padStart(2, "0")}</div>
          <div style={{ fontFamily: T.mono, fontSize: 9, opacity: 0.7, letterSpacing: 2, marginTop: 6, textTransform: "uppercase" }}>{x.l}</div>
        </div>
      ))}
    </div>
  );
}

// Image avec ratio fixe + treatment papier
function VisualPlate({ src, alt = "", ratio = "4/3", caption, style = {}, treatment = "default" }) {
  const isLow = treatment === "low";
  return (
    <figure style={{ margin: 0, ...style }}>
      <div style={{
        position: "relative", width: "100%", aspectRatio: ratio,
        overflow: "hidden", background: T.paper,
        boxShadow: T.shadow,
      }}>
        <img src={src} alt={alt} style={{
          width: "100%", height: "100%", objectFit: "cover",
          filter: isLow ? "saturate(0.85) contrast(0.95)" : "none",
        }} loading="lazy" />
        {/* Léger overlay sépia pour homogénéiser les photos basse qualité */}
        {isLow && (
          <div style={{
            position: "absolute", inset: 0,
            background: "linear-gradient(180deg, rgba(190,154,72,0.03), rgba(26,22,18,0.04))",
            pointerEvents: "none",
          }} />
        )}
      </div>
      {caption && (
        <figcaption style={{
          fontFamily: T.mono, fontSize: 10, letterSpacing: 2, color: T.inkSoft,
          textTransform: "uppercase", marginTop: 8,
        }}>{caption}</figcaption>
      )}
    </figure>
  );
}

Object.assign(window, {
  TopBanner, SectionHeader, Section, Card, GoldAmpersand, ButtonPrimary, ButtonSecondary,
  SuitMarker, OrnamentDivider, useCountdownTo, Countdown, VisualPlate,
  useInView, Reveal,
});
