// app/components.jsx — Composants partagés de l'app

// ─── Hook & wrapper d'animation au scroll (parité avec le site) ───
function useInViewA({ 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];
}

function RevealA({ children, delay = 0, y = 14, duration = 0.55, style = {}, as: As = "div", ...rest }) {
  const [ref, seen] = useInViewA();
  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>
  );
}

// AppHeader — eyebrow + grand titre + trait doré qui s'étire sous le titre
function AppHeader({ title, eyebrow, children, rule = true }) {
  const [ref, seen] = useInViewA();
  const item = (delay) => ({
    opacity: seen ? 1 : 0,
    transform: seen ? "translateY(0)" : "translateY(12px)",
    transition: `opacity .5s cubic-bezier(.2,.7,.3,1) ${delay}s, transform .5s cubic-bezier(.2,.7,.3,1) ${delay}s`,
  });
  return (
    <div ref={ref} style={{ padding: "20px 0 16px", textAlign: "center" }}>
      {eyebrow && (
        <div className="eyebrow" style={{ marginBottom: 8, ...item(0) }}>{eyebrow}</div>
      )}
      <div style={{ position: "relative", display: "inline-block", maxWidth: "100%", ...item(0.08) }}>
        <div className="display-bold" style={{ fontSize: "clamp(28px, 7vw, 40px)", color: A.ink }}>{title}</div>
        {rule && (
          <div style={{
            position: "absolute", bottom: -8, left: 0, right: 0,
            height: 2, background: A.or,
            transformOrigin: "center",
            transform: seen ? "scaleX(1)" : "scaleX(0)",
            transition: "transform 1s cubic-bezier(.4,0,.2,1) .3s",
          }} />
        )}
      </div>
      {children}
    </div>
  );
}

// Section générique de page (sous la TabBar). `cascade` active l'apparition
// en cascade des enfants directs de .wrap (cascade interne).
function Page({ children, padding = "20px 0 120px", cascade = true }) {
  return (
    <div style={{ minHeight: "100vh", padding }}>
      <div className={`wrap${cascade ? " wrap-cascade" : ""}`}>{children}</div>
    </div>
  );
}

// Carte d'info — lift + accent glow sur press (variant B du comparatif).
function InfoCard({ children, accent = A.or, style = {}, onClick }) {
  const [pressed, setPressed] = React.useState(false);
  const interactive = !!onClick;
  const lifted = interactive && pressed;
  return (
    <div
      onClick={onClick}
      onMouseDown={interactive ? () => setPressed(true) : undefined}
      onMouseUp={interactive ? () => setPressed(false) : undefined}
      onMouseLeave={interactive ? () => setPressed(false) : undefined}
      onTouchStart={interactive ? () => setPressed(true) : undefined}
      onTouchEnd={interactive ? () => setPressed(false) : undefined}
      style={{
        background: A.card, padding: "20px 22px",
        border: `1px solid ${lifted ? accent : A.ruleSoft}`,
        boxShadow: lifted ? `0 14px 32px ${accent}40, 0 0 0 1px ${accent}55` : A.shadow,
        cursor: interactive ? "pointer" : "default",
        transform: lifted ? "translateY(-3px)" : "translateY(0)",
        transition: "transform .18s cubic-bezier(.2,.7,.3,1), box-shadow .18s, border-color .18s",
        userSelect: interactive ? "none" : "auto",
        ...style,
      }}
    >
      {children}
    </div>
  );
}

// Bouton primaire (rouge aquarelle)
function ButtonA({ children, onClick, primary = false, full = false, style = {} }) {
  const [h, setH] = React.useState(false);
  const bg = primary ? (h ? A.rougeDeep : A.rouge) : (h ? A.ink : "transparent");
  const fg = primary ? A.white : (h ? A.white : A.ink);
  return (
    <button onClick={onClick}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8,
        padding: "12px 22px", background: bg, color: fg,
        border: primary ? "none" : `1.5px solid ${A.ink}`,
        fontFamily: A.mono, fontSize: 11, letterSpacing: 2.5, textTransform: "uppercase",
        fontWeight: 600, cursor: "pointer", transition: "all .15s",
        width: full ? "100%" : "auto",
        ...style,
      }}>
      {children}
    </button>
  );
}

// Wash background (réutilisé du site)
function WashBg({ hue = 0, opacity = 0.22 }) {
  return (
    <div style={{
      position: "absolute", inset: 0, pointerEvents: "none", zIndex: 0, overflow: "hidden",
      maskImage: "linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%)",
      WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%)",
    }}>
      <img src="assets/wc-strokes.jpg" alt="" style={{
        position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover",
        mixBlendMode: "multiply", opacity,
        filter: `hue-rotate(${hue}deg) saturate(0.9)`, transform: "scale(1.3)",
      }}/>
    </div>
  );
}

// TabBar bottom (8 onglets dans l'ordre : Accueil · Plan · ★ Anecdotes · Quiz ·
// Paris · Carnet · Paparazzi · Galerie. L'icône Anecdotes est mise en avant
// avec une couleur rouge + halo léger même quand l'onglet n'est pas actif.
function TabBar({ current, onChange }) {
  const tabs = [
    { id: "home",   label: "Accueil",   icon: "♥" },
    { id: "plan",   label: "Plan",      icon: "♦" },
    { id: "anec",   label: "Anecdotes", icon: "★", highlight: true },
    { id: "quiz",   label: "Quiz",      icon: "Q" },
    { id: "bets",   label: "Paris",     icon: "♠" },
    { id: "carnet", label: "Carnet",    icon: "♣" },
    { id: "papa",   label: "Paparazzi", icon: "●" },
    { id: "gal",    label: "Galerie",   icon: "✦" },
  ];
  return (
    <nav className="tabbar tabbar-8">
      <div className="tabbar-inner">
        {tabs.map(t => (
          <button key={t.id} onClick={() => onChange(t.id)}
            className={`${current === t.id ? "active" : ""}${t.highlight ? " highlight" : ""}`}
          >
            <span className="icon">{t.icon}</span>
            <span>{t.label}</span>
          </button>
        ))}
      </div>
    </nav>
  );
}

// TopBanner — bandeau noir en haut. Si l'invité est identifié, on affiche
// son nom à droite avec un menu déroulant pour changer d'identité.
function AppTopBanner() {
  const guest = (typeof useGuest === "function") ? useGuest() : { identity: null, logout: () => {} };
  const [menu, setMenu] = React.useState(false);
  return (
    <div style={{
      width: "100%", background: A.ink, color: A.white,
      padding: "12px 16px",
      display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12, position: "relative",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", flex: 1, minWidth: 0 }}>
        <span style={{ fontFamily: A.mono, fontSize: 9, letterSpacing: 4, textTransform: "uppercase", color: A.or }}>
          ♥ App invité
        </span>
        <span style={{ fontFamily: A.italic, fontStyle: "italic", fontSize: 13, color: "rgba(255,255,255,0.85)" }}>
          E <span style={{ color: A.or, padding: "0 3px" }}>&amp;</span> A · 21 / 08 / 2027
        </span>
      </div>
      {guest?.identity && (
        <div style={{ position: "relative" }}>
          <button onClick={() => setMenu(m => !m)} style={{
            display: "flex", alignItems: "center", gap: 8,
            padding: "6px 12px 6px 6px",
            background: "rgba(255,255,255,0.06)", border: `1px solid rgba(255,255,255,0.14)`,
            color: A.white, cursor: "pointer",
          }}>
            <span style={{
              width: 24, height: 24, borderRadius: "50%",
              background: A.or, color: A.ink,
              display: "flex", alignItems: "center", justifyContent: "center",
              fontFamily: A.display, fontSize: 12, fontWeight: 700,
            }}>{(guest.identity.firstName || "?").trim()[0]?.toUpperCase()}</span>
            <span style={{ fontFamily: A.sans, fontSize: 12, fontWeight: 500, color: "rgba(255,255,255,0.92)" }}>
              {guest.identity.firstName || guest.identity.name}
            </span>
            <span style={{ color: A.or, fontSize: 10 }}>{menu ? "▲" : "▼"}</span>
          </button>
          {menu && (
            <div style={{
              position: "absolute", top: "calc(100% + 6px)", right: 0, zIndex: 100,
              background: A.ink, border: `1px solid ${A.or}`, minWidth: 220,
              padding: 14, color: A.white,
              boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
            }}>
              <div style={{ fontFamily: A.mono, fontSize: 9, letterSpacing: 2, color: A.or, textTransform: "uppercase" }}>Identifié·e en tant que</div>
              <div style={{ marginTop: 6, fontFamily: A.display, fontWeight: 700, fontSize: 17, lineHeight: 1.2 }}>{guest.identity.name}</div>
              <div style={{ marginTop: 4, fontFamily: A.italic, fontStyle: "italic", fontSize: 12, color: "rgba(255,255,255,0.65)" }}>
                {guest.identity.tableName ? `♦ ${guest.identity.tableName}` : guest.identity.source === "manual" ? "★ Saisie libre" : "Place à confirmer"}
                {guest.identity.giteName ? ` · ♣ ${guest.identity.giteName}` : ""}
              </div>
              <button onClick={() => { setMenu(false); guest.logout(); }} style={{
                marginTop: 12, width: "100%",
                padding: "9px 12px", background: A.rouge, color: A.white,
                border: "none", cursor: "pointer",
                fontFamily: A.mono, fontSize: 10, letterSpacing: 2, textTransform: "uppercase", fontWeight: 600,
              }}>⇋ Changer d'identité</button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// Hook compte-à-rebours (réutilisé)
function useCountdownA(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),
  };
}

// LocalStorage helpers
const Store = {
  get(key, fallback) {
    try { const v = localStorage.getItem(key); return v ? JSON.parse(v) : fallback; }
    catch { return fallback; }
  },
  set(key, value) {
    try { localStorage.setItem(key, JSON.stringify(value)); } catch {}
  },
};

// ─── Sticker Phila (remplace l'emoji 🐾 dans les easter eggs) ───
// variant "head" → photo recadrée tête (sticker quasi carré ~ 392x394)
// variant "wide" → photo "papattes" plus large (sticker ~ 692x631) — pour les hero
function Phila({ variant = "head", size = 24, style = {}, alt = "Phila", ...rest }) {
  const src = variant === "wide" ? "assets/phila-sticker-2.png" : "assets/phila-sticker-1.png";
  // ratios mesurés sur les PNG détourés
  const ar = variant === "wide" ? 692 / 631 : 392 / 394;
  return (
    <img
      src={src}
      alt={alt}
      loading="lazy"
      draggable={false}
      style={{
        display: "inline-block",
        height: size,
        width: size * ar,
        verticalAlign: "middle",
        objectFit: "contain",
        flexShrink: 0,
        userSelect: "none",
        WebkitUserDrag: "none",
        ...style,
      }}
      {...rest}
    />
  );
}

Object.assign(window, { AppHeader, Page, InfoCard, ButtonA, WashBg, TabBar, AppTopBanner, useCountdownA, Store, useInViewA, RevealA, Phila });
