/* ring.jsx — cinematic 3D project carousel + grid view + filter overlay
   Redesigned: section header sits ABOVE the ring (no text over cards); a live
   caption bar tracks the front-most card; category quick-filters replace the
   scattered labels; arrows + drag + hover + keyboard all drive it. */
const { useState: uS, useEffect: uE, useRef: uR, useMemo: uM, useCallback: uC } = React;

const CAT_ICON = { villa: "building", hospital: "hospital", commercial: "layers", infrastructure: "ruler", interior: "sofa", farmhouse: "trees", landscape: "leaf", residential: "building" };
function statusTone(s) { return s === "delivered" ? "success" : s === "ongoing" ? "warning" : "gold"; }

/* ============================ the 3D carousel =========================== */
/* Robust index-based 3D coverflow — deterministic front card, momentum drag,
   snap, keyboard, trackpad, subtle mouse-parallax tilt, gentle auto-advance. */
function Ring({ items, lang, activeId, setActive, onFront, onCardOpen }) {
  const stageRef = uR(null), innerRef = uR(null), cardRefs = uR([]);
  const S = uR({ pos: 0, target: 0, dragging: false, hover: false, lastX: 0, moved: 0, tpx: 0, tpy: 0, px: 0, py: 0, front: -1, reduce: false, lastStep: 0 });
  const onFrontRef = uR(onFront); onFrontRef.current = onFront;
  const openRef = uR(onCardOpen); openRef.current = onCardOpen;
  const [dims, setDims] = uS(null);
  cardRefs.current = [];
  const N = items.length;

  const nearestDelta = (i) => { let d = ((i - Math.round(S.current.pos)) % N + N) % N; if (d > N / 2) d -= N; return d; };
  const goTo = (i) => { S.current.target = Math.round(S.current.pos) + nearestDelta(i); };
  const step = (dir) => { S.current.target = Math.round(S.current.pos) + dir; S.current.lastStep = performance.now(); };

  /* dimensions */
  uE(() => {
    S.current.reduce = window.matchMedia("(prefers-reduced-motion:reduce)").matches;
    const stage = stageRef.current; if (!stage) return;
    const measure = () => {
      const w = stage.clientWidth;
      const cardW = Math.max(300, Math.min(w * 0.38, 520));
      setDims({ w, cardW, cardH: cardW * 0.66, spacing: cardW * (w < 720 ? 0.46 : 0.52), depth: Math.min(w * 0.24, 280), angle: w < 720 ? 40 : 46, persp: 1700 });
    };
    measure();
    const ro = new ResizeObserver(measure); ro.observe(stage);
    return () => ro.disconnect();
  }, []);

  /* external activeId (audience picks) -> center that card */
  uE(() => { if (activeId == null) return; const idx = items.findIndex((p) => p.id === activeId); if (idx >= 0) goTo(idx); }, [activeId, items]);

  /* animation loop */
  uE(() => {
    if (!dims || !N) return;
    let raf; const s = S.current;
    const frame = (t) => {
      if (!s.dragging) { s.pos += (s.target - s.pos) * 0.14; if (Math.abs(s.target - s.pos) < 0.0008) s.pos = s.target; }
      s.px += (s.tpx - s.px) * 0.05; s.py += (s.tpy - s.py) * 0.05;
      const inner = innerRef.current;
      if (inner) inner.style.transform = `rotateX(${(-s.py * 5).toFixed(2)}deg) rotateY(${(s.px * 6).toFixed(2)}deg)`;
      for (let i = 0; i < N; i++) {
        const el = cardRefs.current[i]; if (!el) continue;
        let off = ((i - s.pos) % N + N) % N; if (off > N / 2) off -= N;
        const a = Math.abs(off);
        const x = off * dims.spacing;
        const z = -a * dims.depth;
        const ry = Math.max(-60, Math.min(60, -off * dims.angle));
        const scale = Math.max(0.6, 1 - a * 0.14);
        const op = a > 3.1 ? 0 : Math.max(0, 1 - a * 0.30);
        const blur = Math.min(5, a * 1.5);
        el.style.transform = `translate(-50%,-50%) translate3d(${x.toFixed(1)}px,0,${z.toFixed(1)}px) rotateY(${ry.toFixed(1)}deg) scale(${scale.toFixed(3)})`;
        el.style.opacity = op.toFixed(3);
        el.style.filter = blur > 0.2 ? `blur(${blur.toFixed(1)}px)` : "none";
        el.style.zIndex = String(1000 - Math.round(a * 100));
        el.style.pointerEvents = op > 0.35 ? "auto" : "none";
      }
      const front = ((Math.round(s.pos) % N) + N) % N;
      if (front !== s.front) {
        const p = cardRefs.current[s.front]; if (p) p.classList.remove("front");
        const c = cardRefs.current[front]; if (c) c.classList.add("front");
        s.front = front;
        if (items[front] && onFrontRef.current) onFrontRef.current(items[front].id);
      }
      const idle = s.pos === s.target && !s.hover && !s.dragging;
      if (!s.reduce && idle && t - s.lastStep > 4600) { s.target += 1; s.lastStep = t; }
      else if (!idle) { s.lastStep = t; }
      raf = requestAnimationFrame(frame);
    };
    raf = requestAnimationFrame(frame);
    return () => cancelAnimationFrame(raf);
  }, [dims, items]);

  /* drag (pointer events, direction-locked) + trackpad + mouse-parallax */
  uE(() => {
    if (!dims) return;
    const stage = stageRef.current, s = S.current;
    let startX = 0, startY = 0, decided = null, pid = null;
    const down = (e) => {
      if (e.pointerType === "mouse" && e.button !== 0) return;
      pid = e.pointerId; startX = e.clientX; startY = e.clientY; decided = null;
      s.lastX = e.clientX; s.moved = 0; s.dragging = false;
      s.target = s.pos; s.lastStep = performance.now(); // freeze auto-advance/settle at current spot
    };
    const move = (e) => {
      if (pid !== null && e.pointerId !== pid) return;
      if (decided === null) {
        const adx = Math.abs(e.clientX - startX), ady = Math.abs(e.clientY - startY);
        if (adx < 6 && ady < 6) return;
        decided = adx > ady ? "h" : "v";
        if (decided === "h") { s.dragging = true; stage.classList.add("grabbing"); try { stage.setPointerCapture(pid); } catch (_) {} }
      }
      if (decided !== "h") return;              // vertical gesture -> let the page scroll
      const dx = e.clientX - s.lastX; s.lastX = e.clientX; s.moved += Math.abs(dx);
      s.pos -= dx / dims.spacing;
      if (e.cancelable) e.preventDefault();
    };
    const up = (e) => {
      if (pid !== null && e.pointerId !== pid) return;
      pid = null;
      if (s.dragging) { s.dragging = false; stage.classList.remove("grabbing"); s.target = Math.round(s.pos); }
      decided = null;
    };
    const enter = () => { s.hover = true; };
    const leave = () => { s.hover = false; s.tpx = 0; s.tpy = 0; };
    const par = (e) => { if (e.pointerType && e.pointerType !== "mouse") return; const r = stage.getBoundingClientRect(); s.tpx = ((e.clientX - r.left) / r.width - 0.5) * 2; s.tpy = ((e.clientY - r.top) / r.height - 0.5) * 2; };
    let wt = 0;
    const wheel = (e) => { if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return; e.preventDefault(); const now = Date.now(); if (now - wt < 240) return; wt = now; step(e.deltaX > 0 ? 1 : -1); };
    stage.addEventListener("pointerdown", down);
    stage.addEventListener("pointermove", move);
    stage.addEventListener("pointermove", par);
    stage.addEventListener("pointerup", up);
    stage.addEventListener("pointercancel", up);
    stage.addEventListener("pointerenter", enter);
    stage.addEventListener("pointerleave", leave);
    stage.addEventListener("wheel", wheel, { passive: false });
    return () => { stage.removeEventListener("pointerdown", down); stage.removeEventListener("pointermove", move); stage.removeEventListener("pointermove", par); stage.removeEventListener("pointerup", up); stage.removeEventListener("pointercancel", up); stage.removeEventListener("pointerenter", enter); stage.removeEventListener("pointerleave", leave); stage.removeEventListener("wheel", wheel); };
  }, [dims]);

  const onKey = (e) => {
    if (e.key === "ArrowRight") { e.preventDefault(); step(1); }
    else if (e.key === "ArrowLeft") { e.preventDefault(); step(-1); }
    else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); const f = items[S.current.front]; if (f) openRef.current(f.id); }
  };

  return (
    <div className="ring-stage" ref={stageRef} data-cursor="grab" tabIndex={0} role="application"
      aria-label={window.t({ en: "Project carousel — arrow keys to browse, Enter to open gallery", hi: "प्रोजेक्ट कैरोसेल — ब्राउज़ हेतु तीर-कुंजियाँ, गैलरी हेतु एंटर" }, lang)} onKeyDown={onKey}
      style={{ perspective: dims ? dims.persp + "px" : "1600px" }}>
      <div className="ring-inner" ref={innerRef}>
        {items.map((p, i) => (
          <button key={p.id} ref={(el) => (cardRefs.current[i] = el)} className="ring-card"
            style={{ width: dims ? dims.cardW : 240, height: dims ? dims.cardH : 300 }}
            onClick={() => { const s = S.current; if (s.moved > 6) return; if (s.front === i) openRef.current(p.id); else goTo(i); }}
            aria-label={window.t(p.title, lang)}>
            <img src={p.img} alt="" loading="lazy" draggable="false" />
            <span className="ring-card-glow" />
            <span className="ring-card-open"><Icon name="images" size={15} />{window.t({ en: "View gallery", hi: "गैलरी देखें" }, lang)}</span>
          </button>
        ))}
      </div>
      <button className="ring-arrow left" aria-label="Previous" onClick={() => step(-1)}><Icon name="chevron-left" size={22} /></button>
      <button className="ring-arrow right" aria-label="Next" onClick={() => step(1)}><Icon name="chevron-right" size={22} /></button>
    </div>
  );
}

/* ====================== live caption bar ================================ */
function Caption({ project, lang, index, total, onOpen }) {
  const T = (v) => window.t(v, lang);
  if (!project) return null;
  const cat = window.OLV.categories.find((c) => c.id === project.cat);
  const status = window.OLV.statuses.find((s) => s.id === project.status);
  return (
    <div className="ring-caption" aria-live="polite">
      <div className="rcap" key={project.id}>
        <h3>{T(project.title)}</h3>
        <p className="rcap-desc">{T(project.summary)}</p>
        {project.gallery && project.gallery.length > 0 && (
          <button className="rcap-cta" onClick={() => onOpen(project.id)}>
            <Icon name="images" size={15} />{T({ en: "View gallery", hi: "गैलरी देखें" })}<span className="rcap-count">{project.gallery.length}</span>
          </button>
        )}
      </div>
    </div>
  );
}

/* ====================== project gallery lightbox ======================= */
function Lightbox({ project, lang, onClose }) {
  const T = (v) => window.t(v, lang);
  const gallery = (project && project.gallery) || [];
  const [idx, setIdx] = uS(0);
  const stripRef = uR(null);
  const go = uC((d) => setIdx((i) => (i + d + gallery.length) % gallery.length), [gallery.length]);

  uE(() => { setIdx(0); }, [project && project.id]);
  uE(() => {
    if (!project) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); else if (e.key === "ArrowRight") go(1); else if (e.key === "ArrowLeft") go(-1); };
    window.addEventListener("keydown", onKey);
    const prevOv = document.body.style.overflow; document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = prevOv; };
  }, [project, go, onClose]);

  uE(() => {
    const strip = stripRef.current; if (!strip) return;
    const el = strip.children[idx]; if (el) strip.scrollTo({ left: el.offsetLeft - strip.clientWidth / 2 + el.clientWidth / 2, behavior: "smooth" });
  }, [idx]);

  if (!project) return null;
  const cat = window.OLV.categories.find((c) => c.id === project.cat);
  return (
    <div className="lb" role="dialog" aria-modal="true" aria-label={T(project.title)}>
      <div className="lb-scrim" onClick={onClose} />
      <div className="lb-panel">
        <button className="lb-x" onClick={onClose} aria-label="Close"><Icon name="x" size={20} /></button>
        <div className="lb-stage">
          <button className="lb-nav prev" onClick={() => go(-1)} aria-label="Previous"><Icon name="chevron-left" size={24} /></button>
          <div className="lb-frame">
            {gallery.map((src, i) => (
              <img key={i} src={src} alt="" className={i === idx ? "on" : ""} loading={i === 0 ? "eager" : "lazy"} draggable="false" />
            ))}
            <div className="lb-count">{String(idx + 1).padStart(2, "0")} / {String(gallery.length).padStart(2, "0")}</div>
          </div>
          <button className="lb-nav next" onClick={() => go(1)} aria-label="Next"><Icon name="chevron-right" size={24} /></button>
        </div>
        <div className="lb-info">
          <div className="lb-cat"><Icon name={CAT_ICON[project.cat]} size={13} />{cat && T(cat)}</div>
          <h3>{T(project.title)}</h3>
          <div className="lb-meta"><span><Icon name="map-pin" size={13} />{T(project.loc)}</span><span className="lb-area">{project.area}</span></div>
          <p>{T(project.desc || project.summary)}</p>
          <div className="lb-strip" ref={stripRef}>
            {gallery.map((src, i) => (
              <button key={i} className={"lb-thumb" + (i === idx ? " on" : "")} onClick={() => setIdx(i)} aria-label={"Photo " + (i + 1)}><img src={src} alt="" loading="lazy" draggable="false" /></button>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ====================== portfolio section ============================== */
function Portfolio({ lang }) {
  const T = (v) => window.t(v, lang);
  const P = window.OLV.portfolio;
  const [activeId, setActive] = uS(null);
  const [frontId, setFrontId] = uS(null);
  const [lightboxId, setLightbox] = uS(null);

  const items = window.OLV.projects;

  const captionProj = uM(() => items.find((p) => p.id === frontId) || items[0] || null, [frontId, items]);
  const frontIndex = captionProj ? items.findIndex((p) => p.id === captionProj.id) : -1;
  const lightboxProj = uM(() => items.find((p) => p.id === lightboxId) || null, [lightboxId, items]);

  /* audience cards dispatch a category -> rotate to first matching project */
  uE(() => {
    const onFilter = (e) => { const cat = e.detail; const m = items.find((p) => p.cat === cat); if (m) setActive(m.id); };
    window.addEventListener("olv-filter-cat", onFilter);
    return () => window.removeEventListener("olv-filter-cat", onFilter);
  }, []);

  return (
    <section className="section" id="portfolio">
      <div className="container">
        <div className="port-head">
          <div style={{ maxWidth: 640 }}>
            <Reveal><Overline>{T(P.overline)}</Overline></Reveal>
            <Headline as="h2" text={T(P.title)} className="display" onScroll style={{ fontSize: "var(--fs-display)", marginTop: 20 }} />
            <Reveal delay="2"><p style={{ fontFamily: "var(--font-body)", fontSize: "var(--fs-body)", color: "var(--text-muted)", lineHeight: "var(--leading-normal)", marginTop: 18, maxWidth: "52ch" }}>{T(P.sub)}</p></Reveal>
          </div>
        </div>
      </div>

      <div className="ring-wrap">
        <div className="ring-spotlight" /><div className="ring-floor" />
        <div className="ring-hint"><Icon name="chevrons-right" size={15} />{T({ en: "Drag · hover · click a project to view its gallery", hi: "खींचें · होवर · गैलरी हेतु प्रोजेक्ट पर क्लिक करें" })}</div>
        {items.length > 0 && <div className="ring-counter"><b>{String(frontIndex + 1).padStart(2, "0")}</b> / {String(items.length).padStart(2, "0")}</div>}
        <Ring items={items} lang={lang} activeId={activeId} setActive={setActive} onFront={setFrontId} onCardOpen={setLightbox} />
        <Caption project={captionProj} lang={lang} index={frontIndex} total={items.length} onOpen={setLightbox} />
        {!items.length && <div className="ring-empty">{T(P.empty)}</div>}
      </div>

      <Lightbox project={lightboxProj} lang={lang} onClose={() => setLightbox(null)} />
    </section>
  );
}

Object.assign(window, { Portfolio });
