// Connelly Gospel — clips feed overlay (TikTok-style vertical feed).
// Self-contained; uses window C / FONT / T / buildClips.

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

function SmallCaps({ children, color, size = 11, ls = "0.28em", style }) {
  return <span style={{ fontFamily: FONT.display, fontSize: size, letterSpacing: ls, textTransform: "uppercase", color: color || C.gold, ...style }}>{children}</span>;
}

function MuteIcon({ muted }) {
  return muted
    ? <svg width="15" height="15" viewBox="0 0 16 16" fill="currentColor"><path d="M3 6h2l3-3v10l-3-3H3V6z" /><path d="M11 6l3 3M14 6l-3 3" stroke="currentColor" strokeWidth="1.4" fill="none" /></svg>
    : <svg width="15" height="15" viewBox="0 0 16 16" fill="currentColor"><path d="M3 6h2l3-3v10l-3-3H3V6z" /><path d="M11 5a3 3 0 010 6" stroke="currentColor" strokeWidth="1.4" fill="none" /></svg>;
}

function ClipsFeed({ lang, setLang, startIdx = 0, onClose }) {
  const tt = T[lang] || T.EN;
  const list = useMemo(() => buildClips(lang), [lang]);
  const containerRef = useRef(null);
  const [activeIdx, setActiveIdx] = useState(startIdx);
  const [muted, setMuted] = useState(true);
  const isDesktop = !((navigator.maxTouchPoints > 0) || ("ontouchstart" in window));
  const [forceWide, setForceWide] = useState(false);
  const [landscape, setLandscape] = useState(false);
  const [autoplay, setAutoplay] = useState(() => {
    try { return localStorage.getItem("cgAutoplay") !== "off"; } catch { return true; }
  });
  useEffect(() => { try { localStorage.setItem("cgAutoplay", autoplay ? "on" : "off"); } catch {} }, [autoplay]);

  // Touch-device landscape → fullscreen 16:9 takeover.
  useEffect(() => {
    const forced = new URLSearchParams(location.search).get("land") === "1";
    const isTouch = (navigator.maxTouchPoints > 0) || ("ontouchstart" in window);
    const mq = window.matchMedia("(orientation: landscape)");
    const on = () => setLandscape(forced || (mq.matches && isTouch));
    on();
    if (mq.addEventListener) mq.addEventListener("change", on); else mq.addListener(on);
    window.addEventListener("orientationchange", on);
    window.addEventListener("resize", on);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", on); else mq.removeListener(on);
      window.removeEventListener("orientationchange", on);
      window.removeEventListener("resize", on);
    };
  }, []);

  // Active slide detection
  useEffect(() => {
    const c = containerRef.current;
    if (!c) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting && e.intersectionRatio > 0.6) setActiveIdx(Number(e.target.dataset.idx)); });
    }, { root: c, threshold: [0.6] });
    Array.from(c.children).forEach((ch) => io.observe(ch));
    return () => io.disconnect();
  }, [list.length]);

  // Scroll to start index on mount
  useEffect(() => {
    const c = containerRef.current;
    if (c && startIdx) c.scrollTo({ top: startIdx * c.clientHeight });
  }, []);

  // Keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      else if (e.key === "ArrowDown") jump(1);
      else if (e.key === "ArrowUp") jump(-1);
      else if (e.key.toLowerCase() === "m") setMuted((m) => !m);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [activeIdx, list.length]);

  function jump(delta) {
    const c = containerRef.current;
    if (!c) return;
    const ni = Math.max(0, Math.min(list.length - 1, activeIdx + delta));
    if (ni === activeIdx) return;
    setActiveIdx(ni);
    c.scrollTo({ top: ni * c.clientHeight, behavior: "smooth" });
  }
  function advanceAuto() {
    const c = containerRef.current;
    const ni = activeIdx + 1 >= list.length ? 0 : activeIdx + 1;
    setActiveIdx(ni);
    if (c) c.scrollTo({ top: ni * c.clientHeight, behavior: "smooth" });
  }

  const iconBtn = { width: 38, height: 38, background: "rgba(0,0,0,0.4)", border: `1px solid ${C.gold}44`, color: C.ivory, cursor: "pointer", backdropFilter: "blur(8px)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 };

  return (
    <div data-feed-root style={{ position: "fixed", inset: 0, zIndex: 200, background: "#000", overflow: "hidden" }}>
      <div ref={containerRef} className="no-bar" style={{ height: "100dvh", overflowY: "scroll", scrollSnapType: "y mandatory", WebkitOverflowScrolling: "touch" }}>
        {list.map((v, i) => (
          <ClipSlide key={v.id} video={v} idx={i} active={i === activeIdx} near={Math.abs(i - activeIdx) <= 1}
            muted={muted} autoplay={autoplay} onAdvance={advanceAuto} forceWide={forceWide} landscape={landscape}
            onFlip={jump} lang={lang} tt={tt} />
        ))}
      </div>

      {/* Top bar */}
      <div style={{ position: landscape ? "fixed" : "absolute", top: 0, left: 0, right: 0, zIndex: 70, padding: landscape ? "8px 14px" : "calc(20px + env(safe-area-inset-top)) 14px 14px", display: "flex", justifyContent: "space-between", alignItems: "center", background: "linear-gradient(180deg, rgba(0,0,0,0.65), transparent)", pointerEvents: "none" }}>
        <button onClick={onClose} aria-label="Close" style={{ ...iconBtn, pointerEvents: "auto" }}>
          <svg width="14" height="14" viewBox="0 0 14 14" stroke="currentColor" strokeWidth="2" fill="none"><line x1="3" y1="3" x2="11" y2="11" /><line x1="11" y1="3" x2="3" y2="11" /></svg>
        </button>
        <div style={{ display: "flex", gap: 8, alignItems: "center", pointerEvents: "auto" }}>
          {isDesktop && (
            <div style={{ display: "flex", border: `1px solid ${C.gold}55`, background: "rgba(0,0,0,0.5)", backdropFilter: "blur(8px)", height: 38 }}>
              {[["9:16", false], ["16:9", true]].map(([label, w]) => (
                <button key={label} onClick={() => setForceWide(w)} style={{ padding: "0 11px", background: forceWide === w ? C.gold : "transparent", color: forceWide === w ? C.ink : C.ivory, border: "none", cursor: "pointer", fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.12em", fontWeight: forceWide === w ? 700 : 400 }}>{label}</button>
              ))}
            </div>
          )}
          <button onClick={() => setAutoplay((a) => !a)} title={tt.auto} style={{ display: "flex", alignItems: "center", gap: 5, padding: "0 11px", height: 38, background: autoplay ? C.gold : "rgba(0,0,0,0.4)", color: autoplay ? C.ink : C.gold, border: `1px solid ${C.gold}55`, cursor: "pointer", backdropFilter: "blur(8px)", fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.14em", fontWeight: autoplay ? 700 : 400 }}>
            <svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M3 2l11 6-11 6V2z" /></svg>{tt.auto.toUpperCase()}
          </button>
          <button onClick={() => setMuted((m) => !m)} aria-label={muted ? tt.unmute : tt.mute} style={{ display: "flex", alignItems: "center", gap: 6, padding: "0 12px", height: 38, background: "rgba(0,0,0,0.4)", border: `1px solid ${C.gold}44`, color: C.gold, cursor: "pointer", backdropFilter: "blur(8px)", fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.14em", fontWeight: 600 }}>
            <MuteIcon muted={muted} />{(muted ? tt.unmute : tt.mute).toUpperCase()}
          </button>
          <div style={{ display: "flex", border: `1px solid ${C.gold}55`, background: "rgba(0,0,0,0.5)", backdropFilter: "blur(8px)", height: 38 }}>
            {["EN", "ES"].map((l) => (
              <button key={l} onClick={() => setLang(l)} style={{ padding: "0 11px", background: lang === l ? C.gold : "transparent", color: lang === l ? C.ink : C.ivory, border: "none", cursor: "pointer", fontFamily: FONT.display, fontSize: 10, letterSpacing: "0.12em", fontWeight: lang === l ? 700 : 400 }}>{l}</button>
            ))}
          </div>
        </div>
      </div>

      {/* Landscape prev/next */}
      {landscape && (
        <>
          <button onClick={() => jump(-1)} disabled={activeIdx === 0} aria-label="Previous" style={{ position: "fixed", left: 8, top: "50%", transform: "translateY(-50%)", width: 44, height: 44, zIndex: 71, background: "rgba(0,0,0,0.45)", border: `1px solid ${C.gold}55`, color: activeIdx === 0 ? `${C.ivory}44` : C.ivory, cursor: "pointer", backdropFilter: "blur(8px)", fontSize: 20 }}>‹</button>
          <button onClick={() => jump(1)} disabled={activeIdx === list.length - 1} aria-label="Next" style={{ position: "fixed", right: 8, top: "50%", transform: "translateY(-50%)", width: 44, height: 44, zIndex: 71, background: "rgba(0,0,0,0.45)", border: `1px solid ${C.gold}55`, color: activeIdx === list.length - 1 ? `${C.ivory}44` : C.ivory, cursor: "pointer", backdropFilter: "blur(8px)", fontSize: 20 }}>›</button>
        </>
      )}

      {/* Flip-for-more hint */}
      {!landscape && (
        <div style={{ position: "absolute", bottom: "calc(14px + env(safe-area-inset-bottom))", left: 0, right: 0, textAlign: "center", pointerEvents: "none", zIndex: 5 }}>
          <SmallCaps color={C.gold} ls="0.3em" size={10} style={{ background: "rgba(0,0,0,0.5)", padding: "6px 14px", display: "inline-flex", alignItems: "center", gap: 8 }}>
            {tt.flipForMore}
            <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" style={{ animation: "cgBob 1.6s ease-in-out infinite" }}><path d="M8 2v11M3 8l5 5 5-5" /></svg>
          </SmallCaps>
        </div>
      )}
      <style>{`@keyframes cgBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(3px); } }`}</style>
    </div>
  );
}

function ClipSlide({ video, idx, active, near, muted, autoplay, onAdvance, forceWide, landscape, onFlip, tt }) {
  const videoRef = useRef(null);
  const seekRef = useRef(0);
  const [wide, setWide] = useState(false);

  useEffect(() => {
    const forced = new URLSearchParams(location.search).get("land") === "1";
    const isTouch = (navigator.maxTouchPoints > 0) || ("ontouchstart" in window);
    const mq = window.matchMedia("(orientation: landscape)");
    const onChange = () => {
      const v = videoRef.current;
      seekRef.current = v ? v.currentTime : 0;
      setWide(forceWide || forced || (mq.matches && isTouch));
    };
    onChange();
    if (mq.addEventListener) mq.addEventListener("change", onChange); else mq.addListener(onChange);
    window.addEventListener("orientationchange", onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", onChange); else mq.removeListener(onChange);
      window.removeEventListener("orientationchange", onChange);
    };
  }, [active]);

  useEffect(() => {
    const v = videoRef.current;
    if (v) seekRef.current = v.currentTime || 0;
    const isTouch = (navigator.maxTouchPoints > 0) || ("ontouchstart" in window);
    setWide(forceWide || (window.matchMedia("(orientation: landscape)").matches && isTouch));
  }, [forceWide]);

  const src = wide ? video.wide : video.shorts;
  const onMeta = () => {
    const v = videoRef.current;
    if (!v) return;
    const t = seekRef.current;
    if (t > 0 && t < (v.duration || Infinity)) { try { v.currentTime = t; } catch {} }
    if (active) v.play().catch(() => {});
  };
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    v.muted = muted;
    if (active) v.play().catch(() => {}); else v.pause();
  }, [active, muted, near, src]);

  const onTap = () => {
    const v = videoRef.current;
    if (!v) return;
    if (v.paused) v.play().catch(() => {}); else v.pause();
  };

  const touch = useRef(null);
  const onTouchStart = (e) => { const t = e.touches[0]; touch.current = { x: t.clientX, y: t.clientY }; };
  const onTouchEnd = (e) => {
    if (!landscape || !touch.current) { touch.current = null; return; }
    const t = e.changedTouches[0];
    const dx = t.clientX - touch.current.x, dy = t.clientY - touch.current.y;
    touch.current = null;
    if (Math.max(Math.abs(dx), Math.abs(dy)) < 45) return;
    const dir = Math.abs(dx) >= Math.abs(dy) ? -Math.sign(dx) : -Math.sign(dy);
    if (onFlip) onFlip(dir);
  };

  return (
    <div data-idx={idx} style={{ height: "100dvh", scrollSnapAlign: "start", scrollSnapStop: "always", position: "relative", background: "#000", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }}>
      {near && (
        <>
          {active && <div aria-hidden style={{ position: "absolute", inset: 0, background: `url(${src}) center/cover`, filter: "blur(40px) brightness(0.35)", opacity: 0.6 }} />}
          <video ref={videoRef} src={src} loop={!autoplay} playsInline autoPlay muted={muted} preload={active ? "auto" : "metadata"}
            onClick={onTap} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} onLoadedMetadata={onMeta}
            onEnded={() => { if (autoplay && active && onAdvance) onAdvance(); }}
            style={(landscape && active)
              ? { position: "fixed", inset: 0, width: "100%", height: "100%", objectFit: "contain", background: "#000", zIndex: 2 }
              : wide
              ? { position: "relative", width: "min(100%, calc(100dvh * 16 / 9))", height: "auto", maxHeight: "100%", objectFit: "contain", background: "#000", zIndex: 1 }
              : { position: "relative", height: "100%", maxWidth: "min(100%, calc(100dvh * 9 / 16))", width: "auto", objectFit: "contain", background: "#000", zIndex: 1 }} />
        </>
      )}

      {/* Caption */}
      {(active || !landscape) && (
        <div style={landscape
          ? { position: "fixed", left: 16, right: "auto", top: 52, maxWidth: "55%", zIndex: 60, textAlign: "left", pointerEvents: "none" }
          : { position: "absolute", left: 0, right: 0, bottom: "calc(54px + env(safe-area-inset-bottom))", padding: "0 24px", zIndex: 4, textAlign: "center", pointerEvents: "none" }}>
          <SmallCaps color={C.gold} size={9} style={{ textShadow: "0 1px 8px rgba(0,0,0,0.95)" }}>{String(video.n).padStart(2, "0")} · {tt.shortClip}</SmallCaps>
          <h2 style={{ fontFamily: FONT.display, fontSize: landscape ? 17 : 22, fontWeight: 400, margin: "8px 0 0", color: C.ivory, letterSpacing: "0.01em", lineHeight: 1.2, textShadow: "0 1px 10px rgba(0,0,0,0.95)" }}>{video.title}</h2>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { ClipsFeed });
