// Connelly Gospel — main site. Hero, Message, Full Message, Clips, Footer.
// Language: EN default; ES via /es path, ?lang=es, or #es. Persisted.

const { useState, useEffect, useRef } = React;

function detectLang() {
  try {
    const p = location.pathname.toLowerCase();
    const q = new URLSearchParams(location.search).get("lang");
    const h = location.hash.replace("#", "").toLowerCase();
    if (q) return q.toUpperCase() === "ES" ? "ES" : "EN";
    if (/(^|\/)es(\/|$)/.test(p)) return "ES";
    if (h === "es") return "ES";
    const saved = localStorage.getItem("cgLang");
    if (saved) return saved;
  } catch {}
  return "EN";
}

// ─── Small shared bits ───────────────────────────────────────────────────────
function Eyebrow({ children, color }) {
  return <div style={{ fontFamily: FONT.display, fontSize: 12, letterSpacing: "0.34em", textTransform: "uppercase", color: color || C.goldDeep }}>{children}</div>;
}
function Rule({ w = 60 }) {
  return <div style={{ width: w, height: 1, background: `linear-gradient(90deg, ${C.gold}, transparent)`, margin: "0 auto" }} />;
}
function GoldBtn({ children, onClick, solid, href, target }) {
  const base = {
    display: "inline-flex", alignItems: "center", gap: 9, padding: "15px 30px", cursor: "pointer",
    fontFamily: FONT.display, fontSize: 13, letterSpacing: "0.18em", textTransform: "uppercase",
    textDecoration: "none", transition: "all 0.25s", whiteSpace: "nowrap",
    border: `1px solid ${C.gold}`,
    background: solid ? C.gold : "transparent",
    color: solid ? C.ink : C.gold,
  };
  const onEnter = (e) => { e.currentTarget.style.background = solid ? C.ivory : "rgba(227,189,110,0.12)"; };
  const onLeave = (e) => { e.currentTarget.style.background = solid ? C.gold : "transparent"; };
  if (href) return <a href={href} target={target} rel="noopener" style={base} onMouseEnter={onEnter} onMouseLeave={onLeave}>{children}</a>;
  return <button onClick={onClick} style={base} onMouseEnter={onEnter} onMouseLeave={onLeave}>{children}</button>;
}

// ─── Top nav ─────────────────────────────────────────────────────────────────
function Nav({ tt, lang, setLang, onClips }) {
  const [solid, setSolid] = useState(false);
  useEffect(() => {
    const on = () => setSolid(window.scrollY > 80);
    on(); window.addEventListener("scroll", on, { passive: true });
    return () => window.removeEventListener("scroll", on);
  }, []);
  return (
    <div style={{ position: "fixed", top: 0, left: 0, right: 0, zIndex: 90, display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 clamp(16px, 4vw, 48px)", height: 66, background: solid ? "rgba(10,8,6,0.92)" : "transparent", backdropFilter: solid ? "blur(12px)" : "none", borderBottom: solid ? `1px solid ${C.line}` : "1px solid transparent", transition: "all 0.3s" }}>
      <a href="#top" style={{ fontFamily: FONT.display, fontSize: 16, letterSpacing: "0.22em", textTransform: "uppercase", color: C.ivory, textDecoration: "none" }}>
        Nick Connelly
      </a>
      <div style={{ display: "flex", alignItems: "center", gap: "clamp(10px, 2vw, 22px)" }}>
        <button onClick={onClips} style={{ background: "none", border: "none", color: C.ivoryDim, cursor: "pointer", fontFamily: FONT.display, fontSize: 12, letterSpacing: "0.2em", textTransform: "uppercase", padding: 0 }} className="nav-link">{tt.clipsEyebrow}</button>
        <a href="#full" style={{ color: C.ivoryDim, textDecoration: "none", fontFamily: FONT.display, fontSize: 12, letterSpacing: "0.2em", textTransform: "uppercase" }}>{tt.fullEyebrow}</a>
        <div style={{ display: "flex", border: `1px solid ${C.gold}55` }}>
          {["EN", "ES"].map((l) => (
            <button key={l} onClick={() => setLang(l)} style={{ padding: "6px 11px", background: lang === l ? C.gold : "transparent", color: lang === l ? C.ink : C.ivory, border: "none", cursor: "pointer", fontFamily: FONT.display, fontSize: 11, letterSpacing: "0.12em", fontWeight: lang === l ? 700 : 400 }}>{l}</button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── Hero ────────────────────────────────────────────────────────────────────
function Hero({ tt, onFull, onClips }) {
  const vRef = useRef(null);
  useEffect(() => { const v = vRef.current; if (v) { v.muted = true; v.play().catch(() => {}); } }, []);
  return (
    <section id="top" style={{ position: "relative", minHeight: "100svh", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", textAlign: "center", padding: "90px 20px 70px" }}>
      <video ref={vRef} src={ASSETS.bgVideo} autoPlay loop muted playsInline
        style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", zIndex: 0 }} />
      <div aria-hidden style={{ position: "absolute", inset: 0, zIndex: 1, background: "radial-gradient(ellipse at center, rgba(10,8,6,0.45) 0%, rgba(10,8,6,0.82) 70%, rgba(10,8,6,0.96) 100%)" }} />
      <div aria-hidden style={{ position: "absolute", inset: 0, zIndex: 1, background: "linear-gradient(180deg, rgba(10,8,6,0.7) 0%, transparent 25%, transparent 60%, #0a0806 100%)" }} />

      <div style={{ position: "relative", zIndex: 2, maxWidth: 880 }}>
        <Eyebrow color={C.gold}>{tt.eyebrow}</Eyebrow>
        <h1 style={{ fontFamily: FONT.display, fontWeight: 400, fontSize: "clamp(52px, 12vw, 132px)", lineHeight: 0.98, letterSpacing: "0.02em", margin: "22px 0 0", color: C.ivory, textShadow: "0 4px 40px rgba(0,0,0,0.6)" }}>
          {tt.title}
        </h1>
        <p style={{ fontFamily: FONT.accent, fontStyle: "italic", fontSize: "clamp(20px, 3.4vw, 30px)", color: C.gold, margin: "18px 0 0", letterSpacing: "0.01em" }}>
          {tt.tagline}
        </p>
        <p style={{ fontFamily: FONT.serif, fontSize: "clamp(16px, 2vw, 19px)", lineHeight: 1.6, color: C.ivoryDim, maxWidth: 600, margin: "26px auto 0" }}>
          {tt.heroLede}
        </p>
        <div style={{ display: "flex", gap: 14, justifyContent: "center", flexWrap: "wrap", marginTop: 40 }}>
          <GoldBtn solid onClick={onFull}>▶ {tt.watchFull}</GoldBtn>
          <GoldBtn onClick={onClips}>{tt.watchClips}</GoldBtn>
        </div>
      </div>

      <div style={{ position: "absolute", bottom: 26, left: 0, right: 0, zIndex: 2, textAlign: "center" }}>
        <Eyebrow color={C.ivoryFaint}>{tt.presenter}</Eyebrow>
      </div>
    </section>
  );
}

// ─── Message / About ─────────────────────────────────────────────────────────
function MessageSection({ tt }) {
  return (
    <section style={{ position: "relative", padding: "clamp(70px, 12vw, 140px) clamp(20px, 6vw, 80px)", background: C.ink }}>
      <div style={{ maxWidth: 1080, margin: "0 auto", display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: "clamp(40px, 7vw, 90px)", alignItems: "center" }}>
        <div>
          <Eyebrow>{tt.aboutEyebrow}</Eyebrow>
          <h2 style={{ fontFamily: FONT.display, fontWeight: 400, fontSize: "clamp(30px, 5vw, 46px)", lineHeight: 1.1, letterSpacing: "0.01em", margin: "18px 0 22px", color: C.ivory }}>
            {tt.aboutTitle}
          </h2>
          <p style={{ fontFamily: FONT.serif, fontSize: "clamp(17px, 2.1vw, 20px)", lineHeight: 1.7, color: C.ivoryDim, margin: 0 }}>
            {tt.aboutBody}
          </p>
        </div>
        <div style={{ position: "relative", padding: "clamp(30px, 5vw, 54px)", border: `1px solid ${C.line}`, background: "linear-gradient(160deg, #15110b, #0d0b08)" }}>
          <div aria-hidden style={{ position: "absolute", top: 22, left: 26, fontFamily: FONT.accent, fontSize: 90, lineHeight: 0.6, color: C.gold, opacity: 0.25 }}>&ldquo;</div>
          <Eyebrow color={C.goldDeep}>{tt.versesEyebrow}</Eyebrow>
          <p style={{ fontFamily: FONT.accent, fontStyle: "italic", fontSize: "clamp(21px, 3vw, 28px)", lineHeight: 1.45, color: C.ivory, margin: "20px 0 18px" }}>
            {tt.verseText}
          </p>
          <div style={{ fontFamily: FONT.display, fontSize: 13, letterSpacing: "0.24em", textTransform: "uppercase", color: C.gold }}>— {tt.verseRef}</div>
        </div>
      </div>
    </section>
  );
}

// ─── Full Message player ─────────────────────────────────────────────────────
function FullMessage({ tt, lang }) {
  const ref = useRef(null);
  const rootRef = useRef(null);
  const [playing, setPlaying] = useState(false);
  const [dl, setDl] = useState(null); // { kind, pct }
  const src = fullVideo(lang, "16x9");

  // Reload source when language changes if already started
  useEffect(() => {
    const v = ref.current;
    if (v && playing) { const t = v.currentTime; v.src = src; v.load(); v.currentTime = t || 0; v.play().catch(() => {}); }
  }, [lang]);

  function start() {
    setPlaying(true);
    setTimeout(() => { const v = ref.current; if (v) { v.src = src; v.play().catch(() => {}); } }, 0);
  }
  function goFs() {
    const el = rootRef.current;
    const v = ref.current;
    const tryEl = () => {
      if (!el) return Promise.reject();
      const req = el.requestFullscreen || el.webkitRequestFullscreen || el.msRequestFullscreen;
      if (req) { try { const p = req.call(el); return p && p.catch ? p : Promise.resolve(); } catch (e) { return Promise.reject(e); } }
      return Promise.reject();
    };
    const tryVideo = () => {
      if (!v) return;
      // iOS Safari: the <video> has its own native fullscreen even inside iframes.
      if (v.webkitEnterFullscreen) { try { v.webkitEnterFullscreen(); return; } catch {} }
      const req = v.requestFullscreen || v.webkitRequestFullscreen;
      if (req) { try { req.call(v); } catch {} }
    };
    Promise.resolve(tryEl()).catch(() => tryVideo());
  }
  async function download(kind) {
    const href = kind === "hd" ? fullMaster(lang, "16x9") : fullVideo(lang, "16x9");
    const filename = decodeURIComponent(href.split("/").pop());
    if (dl) return;
    try {
      setDl({ kind, pct: 0 });
      const res = await fetch(href);
      if (!res.ok) throw new Error(res.status);
      const total = +(res.headers.get("content-length") || 0);
      const reader = res.body.getReader();
      const chunks = []; let recv = 0;
      for (;;) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); recv += value.length; if (total) setDl({ kind, pct: Math.round((recv / total) * 100) }); }
      const url = URL.createObjectURL(new Blob(chunks, { type: "video/mp4" }));
      const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 15000);
      setDl(null);
    } catch { setDl(null); window.open(href, "_blank", "noopener"); }
  }

  return (
    <section id="full" style={{ padding: "clamp(70px, 11vw, 130px) clamp(20px, 6vw, 80px)", background: C.inkSoft, borderTop: `1px solid ${C.line}`, borderBottom: `1px solid ${C.line}` }}>
      <div style={{ maxWidth: 1100, margin: "0 auto", textAlign: "center" }}>
        <Eyebrow>{tt.fullEyebrow}</Eyebrow>
        <h2 style={{ fontFamily: FONT.display, fontWeight: 400, fontSize: "clamp(28px, 5vw, 46px)", lineHeight: 1.12, margin: "18px 0 0", color: C.ivory, letterSpacing: "0.01em" }}>
          {tt.fullTitle}
        </h2>
        <p style={{ fontFamily: FONT.serif, fontSize: "clamp(15px, 1.9vw, 18px)", lineHeight: 1.65, color: C.ivoryDim, maxWidth: 620, margin: "16px auto 0" }}>
          {tt.fullNote}
        </p>

        <div ref={rootRef} style={{ position: "relative", marginTop: 40, aspectRatio: "16/9", background: "#000", border: `1px solid ${C.gold}33`, overflow: "hidden" }}>
          {playing ? (
            <video ref={ref} controls playsInline style={{ width: "100%", height: "100%", objectFit: "contain", background: "#000" }} />
          ) : (
            <button onClick={start} aria-label={tt.play} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", border: "none", cursor: "pointer", background: "radial-gradient(ellipse at center, #1a140c, #0a0806)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 20 }}>
              <span style={{ width: 88, height: 88, borderRadius: "50%", border: `1px solid ${C.gold}`, display: "flex", alignItems: "center", justifyContent: "center", color: C.gold, fontSize: 30, background: "rgba(0,0,0,0.3)", boxShadow: `0 0 60px ${C.goldGlow}` }}>▶</span>
              <span style={{ fontFamily: FONT.display, fontSize: 13, letterSpacing: "0.24em", textTransform: "uppercase", color: C.ivory }}>{tt.play} · {lang}</span>
            </button>
          )}
          {playing && (
            <button onClick={goFs} aria-label={tt.fullscreen} style={{ position: "absolute", top: 12, right: 12, padding: "8px 12px", background: "rgba(0,0,0,0.6)", color: C.ivory, border: `1px solid ${C.gold}55`, cursor: "pointer", fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.16em", textTransform: "uppercase", backdropFilter: "blur(8px)" }}>⛶ {tt.fullscreen}</button>
          )}
        </div>

        <div style={{ display: "flex", gap: 12, justifyContent: "center", flexWrap: "wrap", marginTop: 22 }}>
          {[["web", tt.downloadWeb, "~560 MB"], ["hd", tt.downloadHd, "~2.4 GB"]].map(([kind, label, size]) => {
            const active = dl && dl.kind === kind;
            return (
              <button key={kind} onClick={() => download(kind)} disabled={!!dl} style={{ position: "relative", overflow: "hidden", display: "inline-flex", alignItems: "center", gap: 10, padding: "12px 20px", background: "transparent", border: `1px solid ${C.gold}44`, color: C.ivory, cursor: dl ? "default" : "pointer", opacity: dl && !active ? 0.5 : 1, fontFamily: FONT.display, fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase" }}>
                {active && <span aria-hidden style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: dl.pct + "%", background: C.goldGlow, transition: "width 0.2s" }} />}
                <span style={{ position: "relative", color: C.gold }}>↓</span>
                <span style={{ position: "relative" }}>{active ? `${tt.preparing}… ${dl.pct}%` : label}</span>
                <span style={{ position: "relative", color: C.ivoryFaint, fontSize: 10 }}>{!active && size}</span>
              </button>
            );
          })}
        </div>
      </div>
    </section>
  );
}

// ─── Clips section (grid → opens feed) ───────────────────────────────────────
function ClipsSection({ tt, lang, onOpen }) {
  const clips = buildClips(lang);
  return (
    <section style={{ padding: "clamp(70px, 11vw, 130px) clamp(20px, 6vw, 80px)", background: C.ink }}>
      <div style={{ maxWidth: 1300, margin: "0 auto" }}>
        <div style={{ textAlign: "center", marginBottom: 48 }}>
          <Eyebrow>{tt.clipsEyebrow}</Eyebrow>
          <h2 style={{ fontFamily: FONT.display, fontWeight: 400, fontSize: "clamp(28px, 5vw, 46px)", margin: "18px 0 0", color: C.ivory, letterSpacing: "0.01em" }}>{tt.clipsTitle}</h2>
          <p style={{ fontFamily: FONT.serif, fontSize: "clamp(15px, 1.9vw, 18px)", color: C.ivoryDim, margin: "14px 0 0" }}>{tt.clipsNote}</p>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: 14 }}>
          {clips.map((c, i) => (
            <div key={c.id} onClick={() => onOpen(i)} style={{ position: "relative", aspectRatio: "9/16", overflow: "hidden", border: `1px solid ${C.gold}22`, cursor: "pointer", background: "#000" }}
              onMouseEnter={(e) => { e.currentTarget.style.borderColor = C.gold; const v = e.currentTarget.querySelector("video"); if (v) v.play().catch(() => {}); }}
              onMouseLeave={(e) => { e.currentTarget.style.borderColor = C.gold + "22"; const v = e.currentTarget.querySelector("video"); if (v) { v.pause(); } }}>
              <video src={c.shorts + "#t=2"} muted loop playsInline preload="metadata" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
              <div style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(10,8,6,0.05) 45%, rgba(10,8,6,0.95) 100%)" }} />
              <div style={{ position: "absolute", top: 9, left: 9, fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.1em", color: C.gold }}>{String(c.n).padStart(2, "0")}</div>
              <div style={{ position: "absolute", left: 11, right: 11, bottom: 11, fontFamily: FONT.display, fontSize: 13, color: C.ivory, lineHeight: 1.25, letterSpacing: "0.01em" }}>{c.title}</div>
            </div>
          ))}
        </div>
        <div style={{ textAlign: "center", marginTop: 40 }}>
          <GoldBtn solid onClick={() => onOpen(0)}>▶ {tt.enterFeed}</GoldBtn>
        </div>
      </div>
    </section>
  );
}

// ─── Footer ──────────────────────────────────────────────────────────────────
function Footer({ tt, lang, setLang }) {
  return (
    <footer style={{ padding: "clamp(54px, 8vw, 90px) clamp(20px, 6vw, 80px) 50px", background: C.inkSoft, borderTop: `1px solid ${C.line}`, textAlign: "center" }}>
      <Rule />
      <p style={{ fontFamily: FONT.accent, fontStyle: "italic", fontSize: "clamp(19px, 3vw, 26px)", color: C.gold, margin: "32px 0 28px" }}>{tt.footerLine}</p>
      <div style={{ display: "flex", gap: 16, justifyContent: "center", flexWrap: "wrap", alignItems: "center" }}>
        <GoldBtn href={YOUTUBE_URL} target="_blank">▶ {tt.youtube}</GoldBtn>
        <button onClick={() => setLang(lang === "EN" ? "ES" : "EN")} style={{ background: "none", border: "none", color: C.ivoryDim, cursor: "pointer", fontFamily: FONT.display, fontSize: 12, letterSpacing: "0.2em", textTransform: "uppercase" }}>{tt.lang}</button>
      </div>
      <div style={{ marginTop: 40, fontFamily: FONT.display, fontSize: 11, letterSpacing: "0.22em", textTransform: "uppercase", color: C.ivoryFaint }}>
        Nick Connelly · connolleygospel.com
      </div>
    </footer>
  );
}

// ─── App ─────────────────────────────────────────────────────────────────────
function App() {
  const [lang, setLangState] = useState(detectLang());
  const [feed, setFeed] = useState(null); // null | startIdx
  const tt = T[lang] || T.EN;

  useEffect(() => { document.documentElement.lang = lang.toLowerCase(); }, [lang]);
  function setLang(l) {
    setLangState(l);
    try {
      localStorage.setItem("cgLang", l);
      const u = new URL(location.href);
      u.searchParams.set("lang", l.toLowerCase());
      history.replaceState(null, "", u);
    } catch {}
  }

  // Lock scroll when feed open
  useEffect(() => { document.body.style.overflow = feed != null ? "hidden" : ""; return () => { document.body.style.overflow = ""; }; }, [feed]);

  // Only one audible video plays at a time: when any unmuted video starts,
  // pause every other unmuted one. Muted hero/hover clips are unaffected.
  useEffect(() => {
    const onPlay = (e) => {
      const t = e.target;
      if (!(t instanceof HTMLVideoElement) || t.muted) return;
      document.querySelectorAll("video").forEach((v) => {
        if (v !== t && !v.muted && !v.paused) { try { v.pause(); } catch {} }
      });
    };
    document.addEventListener("play", onPlay, true);
    return () => document.removeEventListener("play", onPlay, true);
  }, []);

  // When the clips feed opens, silence any audible video on the page behind it
  // (e.g. the Full Message player) so it doesn't bleed into the feed.
  useEffect(() => {
    if (feed == null) return;
    requestAnimationFrame(() => {
      document.querySelectorAll("video").forEach((v) => {
        if (!v.closest("[data-feed-root]") && !v.muted) { try { v.pause(); } catch {} }
      });
    });
  }, [feed]);

  return (
    <div>
      <Nav tt={tt} lang={lang} setLang={setLang} onClips={() => setFeed(0)} />
      <Hero tt={tt} onFull={() => { const el = document.getElementById("full"); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 50, behavior: "smooth" }); }} onClips={() => setFeed(0)} />
      <MessageSection tt={tt} />
      <FullMessage tt={tt} lang={lang} />
      <ClipsSection tt={tt} lang={lang} onOpen={(i) => setFeed(i)} />
      <Footer tt={tt} lang={lang} setLang={setLang} />
      {feed != null && <ClipsFeed lang={lang} setLang={setLang} startIdx={feed} onClose={() => setFeed(null)} />}
    </div>
  );
}

const boot = document.getElementById("boot");
if (boot) setTimeout(() => boot.classList.add("hide"), 400);
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
