// components.jsx — Shared atoms for Spree Ravers
// BlurText, MarkerTag, FadingVideo, AnimatedHeroBg, Glass primitives, Nav, Footer.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ─── i18n hook ────────────────────────────────────────────────────────
function useT(lang) {
  return useCallback((key) => {
    const dict = window.I18N[lang] || window.I18N.en;
    return dict[key] || window.I18N.en[key] || key;
  }, [lang]);
}

// ─── Icons (inline SVG, no external lib) ───────────────────────────────
const Icon = {
  ArrowUR: (props) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"
         strokeLinecap="round" strokeLinejoin="round" {...props}>
      <path d="M7 17 17 7" /><path d="M8 7h9v9" />
    </svg>
  ),
  Shield: (props) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"
         strokeLinecap="round" strokeLinejoin="round" {...props}>
      <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
      <path d="m9 12 2 2 4-4" />
    </svg>
  ),
  Telegram: (props) => (
    <svg viewBox="0 0 24 24" fill="currentColor" {...props}>
      <path d="m21.94 4.93-3.04 14.34c-.23 1.03-.83 1.28-1.69.8l-4.67-3.44-2.25 2.17c-.25.25-.46.46-.94.46l.34-4.77 8.7-7.86c.38-.34-.08-.52-.59-.19l-10.76 6.78L1.4 11.8c-1-.31-1.03-1 .21-1.49L20.66 3.5c.84-.31 1.58.19 1.28 1.43Z" />
    </svg>
  ),
  Marker: (props) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"
         strokeLinecap="round" strokeLinejoin="round" {...props}>
      <path d="M12 21s-7-5.5-7-12a7 7 0 1 1 14 0c0 6.5-7 12-7 12Z" />
      <circle cx="12" cy="9" r="2.5" />
    </svg>
  ),
  Instagram: (props) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"
         strokeLinecap="round" strokeLinejoin="round" {...props}>
      <rect x="3" y="3" width="18" height="18" rx="5" />
      <circle cx="12" cy="12" r="4" />
      <circle cx="17.5" cy="6.5" r="0.6" fill="currentColor" />
    </svg>
  ),
  Facebook: (props) => (
    <svg viewBox="0 0 24 24" fill="currentColor" {...props}>
      <path d="M22 12a10 10 0 1 0-11.56 9.88v-6.99H7.9V12h2.54V9.8c0-2.5 1.49-3.89 3.77-3.89 1.09 0 2.24.2 2.24.2v2.46h-1.26c-1.24 0-1.63.77-1.63 1.56V12h2.77l-.44 2.89h-2.33v6.99A10 10 0 0 0 22 12Z" />
    </svg>
  ),
};

// ─── BlurText: word-by-word blur-in stagger ────────────────────────────
function BlurText({ children, className = "", style = {}, delay = 0, stagger = 100, asInline = false }) {
  const text = typeof children === "string" ? children : "";
  const words = text.split(" ");
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduced) { setVisible(true); return; }
    // Safety: always reveal after 1.5s even if observer doesn't fire
    const safety = setTimeout(() => setVisible(true), 1500);
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setVisible(true); obs.disconnect(); clearTimeout(safety); }
    }, { threshold: 0.05 });
    obs.observe(ref.current);
    return () => { obs.disconnect(); clearTimeout(safety); };
  }, []);
  return (
    <span
      ref={ref}
      className={className}
      style={{
        display: asInline ? "inline-flex" : "flex",
        flexWrap: "wrap",
        rowGap: "0.1em",
        ...style,
      }}
    >
      {words.map((w, i) => (
        <span key={i} style={{
          display: "inline-block",
          marginRight: "0.28em",
          animation: visible
            ? `blurIn 700ms ease-out ${delay + i * stagger}ms both`
            : "none",
          // Pre-visible: hide via animation fill 'both' once visible flips;
          // before then, keep at near-0 so layout reserves space but text is hidden.
          opacity: visible ? undefined : 0,
          // Safety: if animations are disabled (snapshot tools etc), always show.
          ...(typeof window !== "undefined" && window.matchMedia &&
              window.matchMedia("(prefers-reduced-motion: reduce)").matches
              ? { opacity: 1, animation: "none" } : {}),
        }}>
          {w}
        </span>
      ))}
    </span>
  );
}

// ─── MarkerTag — rotated Permanent Marker text "slapped" on layout ────
function MarkerTag({ children, color = "var(--c-cyan)", rotate = -3, size = "1.5rem",
                    className = "", drift = true, style = {} }) {
  return (
    <span
      className={className}
      style={{
        fontFamily: "var(--f-marker)",
        color,
        fontSize: size,
        display: "inline-block",
        transform: `rotate(${rotate}deg)`,
        animation: drift ? "markerDrift 6s ease-in-out infinite" : "none",
        textShadow: `0 0 24px ${color}40`,
        ...style,
      }}
    >
      {children}
    </span>
  );
}

// ─── FadingVideo — rAF crossfade per the brief ────────────────────────
function FadingVideo({ src, poster, style = {}, scale = 1.2 }) {
  const ref = useRef(null);
  useEffect(() => {
    const v = ref.current;
    if (!v) return;
    let raf;
    const fadeTo = (target, duration = 500) => {
      cancelAnimationFrame(raf);
      const start = performance.now();
      const from = parseFloat(v.style.opacity || "0");
      const step = (now) => {
        const t = Math.min(1, (now - start) / duration);
        v.style.opacity = String(from + (target - from) * t);
        if (t < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
    };
    const onLoaded = () => {
      v.style.opacity = "0";
      v.play().catch(() => {});
      fadeTo(1, 700);
    };
    const onTime = () => {
      if (v.duration && v.duration - v.currentTime <= 0.55) fadeTo(0, 550);
    };
    const onEnded = () => {
      v.style.opacity = "0";
      setTimeout(() => { v.currentTime = 0; v.play().catch(() => {}); fadeTo(1, 700); }, 100);
    };
    v.addEventListener("loadeddata", onLoaded);
    v.addEventListener("timeupdate", onTime);
    v.addEventListener("ended", onEnded);
    return () => {
      cancelAnimationFrame(raf);
      v.removeEventListener("loadeddata", onLoaded);
      v.removeEventListener("timeupdate", onTime);
      v.removeEventListener("ended", onEnded);
    };
  }, [src]);
  return (
    <video
      ref={ref}
      autoPlay muted playsInline preload="auto"
      src={src} poster={poster}
      style={{
        position: "absolute", inset: 0,
        width: `${scale * 100}%`, height: `${scale * 100}%`,
        objectFit: "cover", objectPosition: "center 25%",
        opacity: 0, pointerEvents: "none",
        left: `${(1 - scale) * 50}%`, top: `${(1 - scale) * 50}%`,
        ...style,
      }}
    />
  );
}

// ─── PhotoHero — high-contrast still with grain ───────────────────────
function PhotoHero({ src, accent }) {
  return (
    <div style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
      <img src={src} alt=""
           style={{
             position: "absolute", inset: 0, width: "120%", height: "120%",
             objectFit: "cover", objectPosition: "center 30%",
             left: "-10%", top: "-10%",
             filter: "contrast(1.08) saturate(0.95) brightness(0.55)",
           }} />
      {/* grain */}
      <div style={{
        position: "absolute", inset: 0, pointerEvents: "none", mixBlendMode: "overlay",
        opacity: 0.18,
        backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>")`,
      }} />
      {/* accent vignette */}
      <div style={{
        position: "absolute", inset: 0, pointerEvents: "none",
        background: `radial-gradient(60% 50% at 50% 50%, transparent 0%, transparent 50%, rgba(0,0,0,0.4) 100%), radial-gradient(40% 30% at 80% 20%, ${accent}30 0%, transparent 60%)`,
      }} />
    </div>
  );
}

// ─── AnimatedHeroBg — pure CSS / canvas blobs ─────────────────────────
function AnimatedHeroBg({ accent }) {
  return (
    <div style={{ position: "absolute", inset: 0, overflow: "hidden", background: "#000" }}>
      {/* slow moving blobs */}
      {[0, 1, 2].map(i => (
        <div key={i}
             style={{
               position: "absolute",
               width: "70vw", height: "70vw",
               borderRadius: "50%",
               background: i === 0 ? `radial-gradient(circle, ${accent}, transparent 60%)`
                         : i === 1 ? `radial-gradient(circle, #00d4ff, transparent 60%)`
                                   : `radial-gradient(circle, #d4ff00, transparent 60%)`,
               filter: "blur(80px)",
               opacity: 0.35,
               top: i === 0 ? "-20%" : i === 1 ? "30%" : "60%",
               left: i === 0 ? "-15%" : i === 1 ? "50%" : "10%",
               animation: `blobDrift${i} ${22 + i * 4}s ease-in-out infinite alternate`,
             }} />
      ))}
      {/* scanline */}
      <div style={{
        position: "absolute", inset: 0, pointerEvents: "none",
        backgroundImage: "repeating-linear-gradient(0deg, rgba(255,255,255,0.02) 0px, rgba(255,255,255,0.02) 1px, transparent 1px, transparent 3px)",
      }} />
      {/* grain */}
      <div style={{
        position: "absolute", inset: 0, pointerEvents: "none", mixBlendMode: "overlay",
        opacity: 0.14,
        backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>")`,
      }} />
    </div>
  );
}

// ─── Navigation ───────────────────────────────────────────────────────
function Nav({ page, setPage, lang, setLang, t }) {
  const links = [
    { id: "meetup", label: t("nav_meetup") },
    { id: "sets",   label: t("nav_sets") },
  ];
  const [mobileOpen, setMobileOpen] = useState(false);
  return (
    <>
      <nav style={{
        position: "fixed", top: 16, left: 0, right: 0, zIndex: 50,
        padding: "0 24px", display: "flex", justifyContent: "space-between",
        alignItems: "center", pointerEvents: "none",
      }}>
        <button onClick={() => setPage("meetup")} className="liquid-glass" style={{
          width: 48, height: 48, borderRadius: "50%",
          display: "flex", alignItems: "center", justifyContent: "center",
          color: "#fff", cursor: "pointer",
          pointerEvents: "auto", border: "none",
        }}>
          <SLogo />
        </button>

        <div className="liquid-glass nav-center" style={{
          borderRadius: "var(--r-pill)", padding: 6, gap: 2,
          alignItems: "center", pointerEvents: "auto",
        }}>
          {links.map(l => (
            <button key={l.id} onClick={() => setPage(l.id)}
                    style={{
                      padding: "8px 14px", fontSize: 13, fontWeight: 500,
                      color: page === l.id ? "#fff" : "rgba(255,255,255,0.7)",
                      background: page === l.id ? "rgba(255,255,255,0.08)" : "transparent",
                      borderRadius: "var(--r-pill)",
                      fontFamily: "var(--f-body)",
                      transition: "color 200ms, background 200ms",
                    }}>
              {l.label}
            </button>
          ))}
          <span style={{ width: 1, height: 18, background: "rgba(255,255,255,0.12)", margin: "0 4px" }} />
          <LangToggle lang={lang} setLang={setLang} />
        </div>

        <button className="nav-mobile-btn liquid-glass" onClick={() => setMobileOpen(o => !o)}
                style={{
                  width: 48, height: 48, borderRadius: "50%",
                  display: "none", alignItems: "center", justifyContent: "center",
                  pointerEvents: "auto", color: "#fff",
                }}>
          <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.8">
            <path d={mobileOpen ? "M6 6l12 12M6 18L18 6" : "M4 7h16M4 12h16M4 17h16"} strokeLinecap="round" />
          </svg>
        </button>
      </nav>

      {mobileOpen && (
        <div className="nav-mobile-sheet" style={{
          position: "fixed", top: 72, right: 24, left: 24, zIndex: 49,
          padding: 16, display: "flex", flexDirection: "column", gap: 4,
        }}>
          <div className="liquid-glass" style={{
            borderRadius: 20, padding: 16, display: "flex", flexDirection: "column", gap: 6,
          }}>
            {links.map(l => (
              <button key={l.id} onClick={() => { setPage(l.id); setMobileOpen(false); }}
                      style={{
                        padding: "10px 14px", textAlign: "left",
                        fontSize: 15, fontWeight: 500, color: "#fff",
                        background: page === l.id ? "rgba(255,255,255,0.08)" : "transparent",
                        borderRadius: 12, fontFamily: "var(--f-body)",
                      }}>
                {l.label}
              </button>
            ))}
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 14px" }}>
              <LangToggle lang={lang} setLang={setLang} />
            </div>
          </div>
        </div>
      )}
    </>
  );
}

function LangToggle({ lang, setLang }) {
  return (
    <div style={{
      display: "inline-flex", alignItems: "center",
      fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.12em",
    }}>
      <button onClick={() => setLang("en")}
              style={{
                padding: "6px 8px", color: lang === "en" ? "#fff" : "rgba(255,255,255,0.4)",
                fontWeight: lang === "en" ? 600 : 400,
              }}>EN</button>
      <span style={{ color: "rgba(255,255,255,0.25)" }}>|</span>
      <button onClick={() => setLang("de")}
              style={{
                padding: "6px 8px", color: lang === "de" ? "#fff" : "rgba(255,255,255,0.4)",
                fontWeight: lang === "de" ? 600 : 400,
              }}>DE</button>
    </div>
  );
}

// ─── S/R logo mark (the wave) ─────────────────────────────────────────
function SLogo({ size = 28 }) {
  return (
    <img src="assets/logo/logo-icon-white.png"
         alt="Spree Ravers"
         width={size} height={size}
         style={{ display: "block", borderRadius: "50%" }} />
  );
}

// ─── Footer ───────────────────────────────────────────────────────────
function Footer({ t, accent }) {
  return (
    <footer style={{ borderTop: "1px solid var(--c-border)", marginTop: 0 }}>
      {/* privacy strip */}
      <div style={{
        padding: "64px 24px",
        borderBottom: "1px solid var(--c-border)",
        background: "linear-gradient(180deg, #000 0%, var(--c-near-black) 100%)",
      }}>
        <div style={{ maxWidth: 1200, margin: "0 auto" }}>
          <div style={{
            fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.12em",
            textTransform: "uppercase", color: accent, marginBottom: 16,
            display: "flex", alignItems: "center", gap: 8,
          }}>
            <Icon.Shield style={{ width: 14, height: 14 }} />
            {t("privacy_eyebrow")}
          </div>
          <h3 style={{
            fontFamily: "var(--f-display)", fontStyle: "italic",
            fontSize: "clamp(36px, 5vw, 56px)", letterSpacing: "-0.025em",
            lineHeight: 1, color: "#fff", margin: 0, marginBottom: 20,
          }}>
            {t("privacy_h")}
          </h3>
          <p style={{
            fontFamily: "var(--f-body)", fontWeight: 300,
            fontSize: 16, lineHeight: 1.55, color: "rgba(255,255,255,0.7)",
            maxWidth: 720, margin: 0, marginBottom: 24, textWrap: "pretty",
          }}>
            {t("privacy_p")}
          </p>
          <ul style={{
            listStyle: "none", padding: 0, margin: 0,
            display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
            gap: 12, maxWidth: 980,
          }}>
            {[1, 2, 3, 4].map(i => (
              <li key={i} style={{
                fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.08em",
                textTransform: "uppercase", color: "rgba(255,255,255,0.7)",
                display: "flex", alignItems: "center", gap: 10,
              }}>
                <span style={{
                  width: 8, height: 8, borderRadius: "50%",
                  background: accent, boxShadow: `0 0 14px ${accent}`,
                }} />
                {t(`privacy_list_${i}`)}
              </li>
            ))}
          </ul>
        </div>
      </div>

      {/* socials strip — real handles, opens in new tab */}
      <div style={{
        padding: "40px 24px 24px",
        maxWidth: 1200, margin: "0 auto",
      }}>
        <div style={{
          fontFamily: "var(--f-mono)", fontSize: 10, letterSpacing: "0.18em",
          textTransform: "uppercase", color: "rgba(255,255,255,0.5)",
          marginBottom: 14,
        }}>
          {t("social_eyebrow")}
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 10 }}>
          {[
            { id: "telegram",  href: "https://t.me/SpreeRaversBerlin",                  icon: <Icon.Telegram  style={{ width: 14, height: 14 }} />, label: "Telegram",  handle: "@SpreeRaversBerlin" },
            { id: "instagram", href: "https://www.instagram.com/spree.ravers.berlin/", icon: <Icon.Instagram style={{ width: 14, height: 14 }} />, label: "Instagram", handle: "@spree.ravers.berlin" },
            { id: "facebook",  href: "https://www.facebook.com/spree.ravers.berlin/",  icon: <Icon.Facebook  style={{ width: 14, height: 14 }} />, label: "Facebook",  handle: "/spree.ravers.berlin" },
          ].map(s => (
            <a key={s.id} href={s.href} target="_blank" rel="noopener noreferrer"
               className="liquid-glass"
               style={{
                 padding: "8px 14px", borderRadius: "var(--r-pill)",
                 display: "inline-flex", alignItems: "center", gap: 10,
                 color: "#fff", textDecoration: "none",
                 fontFamily: "var(--f-body)", fontSize: 12, fontWeight: 500,
                 transition: "transform 200ms",
               }}
               onMouseEnter={(e) => { e.currentTarget.style.transform = "translateY(-2px)"; }}
               onMouseLeave={(e) => { e.currentTarget.style.transform = "translateY(0)"; }}>
              {s.icon}
              <span>{s.label}</span>
              <span style={{
                color: "rgba(255,255,255,0.45)",
                fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.04em",
              }}>{s.handle}</span>
            </a>
          ))}
        </div>
      </div>

      {/* bottom strip */}
      <div style={{
        padding: "20px 24px 32px",
        display: "flex", flexWrap: "wrap", gap: 24,
        alignItems: "center", justifyContent: "space-between",
        maxWidth: 1200, margin: "0 auto",
        borderTop: "1px solid rgba(255,255,255,0.06)",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
          <span style={{
            fontFamily: "var(--f-display)", fontStyle: "italic", fontSize: 22, color: "#fff",
          }}>Spree</span>
          <MarkerTag color="var(--c-magenta)" size="1.5rem" rotate={-2} drift={false}>×</MarkerTag>
          <span style={{
            fontFamily: "var(--f-display)", fontStyle: "italic", fontSize: 22, color: "#fff",
          }}>Ravers</span>
        </div>
        <div style={{
          display: "flex", gap: 24, flexWrap: "wrap",
          fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.12em",
          textTransform: "uppercase", color: "rgba(255,255,255,0.5)",
        }}>
          <span>{t("foot_made")} · {t("foot_year")}</span>
        </div>
      </div>
    </footer>
  );
}

// ─── Export ────────────────────────────────────────────────────────────
Object.assign(window, {
  useT, Icon, BlurText, MarkerTag, FadingVideo, PhotoHero, AnimatedHeroBg,
  Nav, LangToggle, SLogo, Footer,
});
