// Project detail page — appears after the thumbnail finishes its expand animation.
// Hero layout: a rotating carousel of feature images scrolls behind a
// dominant centre render (the product). Below: title + project number, then a
// 2-column meta/body block. Close returns home.

const { useState, useEffect, useRef } = React;

const VISIBLE_TILES = 5;

// The feature band is a continuously rotating carousel: the pool is shuffled into
// a random order and scrolls horizontally behind the centre render, looping
// seamlessly. Five tiles show at a time so each image gets more room.
function MediaGallery({ gallery, mobile }) {
  const { hero, pool } = gallery;
  const tiles = mobile ? 2 : VISIBLE_TILES;
  const bandH = mobile ? 280 : 460;
  const heroW = mobile ? '58%' : '40%';

  const bandRef = useRef(null);
  const [tileW, setTileW] = useState(null);
  useEffect(() => {
    if (bandRef.current) setTileW(bandRef.current.clientWidth / tiles);
  }, [tiles]);

  // Randomised order, fixed for the life of this mount.
  // On touch devices (iPhone/iPad) the full pool blows Safari's GPU limits —
  // the animating track becomes a >10k-physical-px texture with up to 6 video
  // decoders, and iOS evicts already-loaded images (they appear, then vanish).
  // Cap it: a few images + at most one video keeps the layer inside budget.
  const [shuffled] = useState(() => {
    const a = pool.slice();
    for (let i = a.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [a[i], a[j]] = [a[j], a[i]];
    }
    if (navigator.maxTouchPoints > 1) {
      const vid = a.find(m => m.type === 'video');
      const imgs = a.filter(m => m.type !== 'video').slice(0, 5);
      if (vid) imgs.splice(Math.min(2, imgs.length), 0, vid);
      return imgs;
    }
    return a;
  });

  // One full pass must span at least the band width, else the -50% loop shows gaps.
  let base = shuffled;
  while (base.length && base.length < tiles) base = base.concat(shuffled);
  const sequence = base.concat(base);
  const duration = Math.max(base.length * 8, 40);

  return (
    <div style={{ position: 'relative', width: '100%', marginTop: 36 }}>
      {/* Rotating carousel band — fills the width, sits behind the render */}
      <div ref={bandRef} style={{
        position: 'relative', overflow: 'hidden',
        width: '100%', height: bandH, background: 'var(--grey-1)'
      }}>
        <div style={{
          display: 'flex', gap: 4, height: '100%', width: 'max-content',
          animation: (tileW && !window.__rheonReduced) ? `galleryScroll ${duration}s linear infinite` : 'none',
          willChange: 'transform'
        }}>
          {sequence.map((m, i) => (
            <div key={i} style={{ flex: `0 0 ${tileW || 234}px`, height: '100%', overflow: 'hidden' }}>
              {m.type === 'video'
                ? <video src={m.src} autoPlay muted loop playsInline
                    style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: m.position || 'center', display: 'block' }} />
                : <img src={m.src} alt=""
                    style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: m.position || 'center', display: 'block' }} />}
            </div>
          ))}
        </div>
      </div>

      {/* Centre render — dominant, masks the middle of the strip.
          Skipped when a project has no hero: the pool scrolls the full band. */}
      {hero && (
        <div style={{
          position: 'absolute', left: '50%', top: '50%',
          transform: 'translate(-50%, -50%)',
          width: heroW, height: '100%',
          zIndex: 10, pointerEvents: 'none',
        }}>
          <img src={hero} alt="hero render"
            style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
        </div>
      )}

      <style>{`
        @keyframes galleryScroll {
          0%   { transform: translateX(0); }
          100% { transform: translateX(-50%); }
        }
      `}</style>
    </div>
  );
}

// Interactive 16-bit lab stations. You land on the animated pixel-art lab cover
// (room-only iframe) sitting under a "CLICK TO ENTER" bar. Clicking the bar slides
// the cover left and reveals the injection-moulder sim, with the cartridge tabs
// fading in to switch stations (arrow keys too). The enter bar and the tab row
// share one fixed-height slot; the cover room and the sims share one 16:9 viewport.
const TABH = 104;
function LabStations({ stations, cover, mobile }) {
  const tabh = mobile ? 78 : TABH;
  const [entered, setEntered] = useState(false);
  const [i, setI] = useState(0);
  const n = stations.length;
  const active = stations[i];

  // Blue Rheon auxetic foam (open cells: bright rim, lit top-left, dark hole) → pixelated
  // data URL, used as the enter-bar background.
  const [voro, setVoro] = useState(null);
  useEffect(() => {
    const W = 264, H = 22;
    const c = document.createElement('canvas'); c.width = W; c.height = H;
    const g = c.getContext('2d');
    g.fillStyle = '#05123f'; g.fillRect(0, 0, W, H);          // dark gaps between cells
    const Rc = 6.2, sx = 10, sy = 9;
    for (let row = -1; row * sy < H + Rc; row++) {
      for (let col = -1; col * sx < W + Rc; col++) {
        const cxp = col*sx + (row%2 ? sx/2 : 0) + (Math.random()*2.4-1.2);
        const cyp = row*sy + (Math.random()*2.4-1.2);
        const ring = (r, fill) => { g.fillStyle = fill; g.beginPath(); g.arc(cxp, cyp, r, 0, 7); g.fill(); };
        ring(Rc,     '#1736a6');                              // cell body
        ring(Rc-1.4, '#3f74ff');                              // bright rim
        g.fillStyle = '#7aa8ff'; g.beginPath(); g.arc(cxp-1.4, cyp-1.4, Rc-3, 0, 7); g.fill(); // top-left light
        ring(Rc-3.4, '#152e7a');                              // inner wall
        ring(Rc-5,   '#06123c');                              // open hole
      }
    }
    setVoro(c.toDataURL());
  }, []);

  // The cover can also request entry (e.g. a future click target inside it).
  useEffect(() => {
    const onMsg = (e) => { const d = e.data; if (d && d.source === 'rheon-lab-cover' && d.action === 'enter') setEntered(true); };
    window.addEventListener('message', onMsg);
    return () => window.removeEventListener('message', onMsg);
  }, []);

  const onKey = (e) => {
    if (!entered) return;
    if (e.key === 'ArrowRight') { e.preventDefault(); setI(p => Math.min(n - 1, p + 1)); }
    if (e.key === 'ArrowLeft')  { e.preventDefault(); setI(p => Math.max(0, p - 1)); }
  };

  const panelPct = 100 / (n + 1);                       // each panel = one viewport width
  const trackX = entered ? (1 + i) * panelPct : 0;      // 0 = cover, 1..n = sims

  return (
    <div style={{ marginTop: 36 }} onKeyDown={onKey} tabIndex={0}>
      {/* header */}
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
        fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2,
        color: 'var(--mute)', textTransform: 'uppercase', marginBottom: 14
      }}>
        {entered
          ? <button className="hover-fade" onClick={() => { setEntered(false); setI(0); }}
              style={{ background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2, color: 'var(--ink)', textTransform: 'uppercase', padding: 0 }}>◂ Menu</button>
          : <span>Rheon Labs · Interactive Workshop</span>}
        <span>{entered ? `Station ${String(i + 1).padStart(2, '0')} / ${String(n).padStart(2, '0')}` : 'Select a station'}</span>
      </div>

      {/* tab slot — enter bar OR cartridge tabs (same height) */}
      <div style={{ position: 'relative', height: tabh, marginBottom: 16 }}>
        {/* CLICK TO ENTER bar (blue foam background, pulsing + shine to draw the eye) */}
        <button onClick={() => setEntered(true)} aria-label="Click to enter the workshop"
          style={{
            position: 'absolute', inset: 0, cursor: 'pointer', overflow: 'hidden',
            opacity: entered ? 0 : 1, pointerEvents: entered ? 'none' : 'auto',
            transition: 'opacity 300ms ease',
            border: '2px solid var(--ink)', backgroundColor: '#1230a8',
            backgroundImage: voro ? `url(${voro})` : 'none', backgroundSize: 'cover',
            imageRendering: 'pixelated',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 16,
            animation: 'labEnterPulse 1.8s ease-in-out infinite'
          }}>
          {/* sweeping shine */}
          <span aria-hidden style={{
            position: 'absolute', top: 0, bottom: 0, left: 0, width: '45%',
            background: 'linear-gradient(105deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%)',
            animation: 'labShine 2.6s ease-in-out infinite', pointerEvents: 'none'
          }} />
          <span style={{
            fontFamily: "'Press Start 2P', var(--mono)", fontSize: mobile ? 12 : 22, letterSpacing: mobile ? 2 : 4,
            color: '#ffffff', textShadow: '2px 2px 0 #0a1330',
            animation: 'labEnterText 1.8s ease-in-out infinite'
          }}>
            ▸&nbsp;&nbsp;CLICK TO ENTER&nbsp;&nbsp;◂
          </span>
        </button>
        {/* cartridge tabs */}
        <div style={{ position: 'absolute', inset: 0, display: 'flex', gap: mobile ? 6 : 12, opacity: entered ? 1 : 0, pointerEvents: entered ? 'auto' : 'none', transition: 'opacity 300ms ease 140ms' }}>
          {stations.map((s, k) => {
            const on = k === i;
            return (
              <button key={s.id} onClick={() => setI(k)} aria-pressed={on}
                style={{ flex: 1, textAlign: 'left', cursor: 'pointer', padding: mobile ? '8px 9px' : '14px 18px', background: 'var(--paper)', border: on ? '2px solid var(--ink)' : '2px solid var(--rule)', boxShadow: on ? 'none' : '0 3px 0 #dcdcdc' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: mobile ? 5 : 7 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 1, background: on ? '#2f9d57' : '#c4ccce', boxShadow: on ? '0 0 7px #2f9d57' : 'none' }} />
                  <span style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2, color: on ? 'var(--ink)' : 'var(--mute)' }}>{String(k + 1).padStart(2, '0')}</span>
                </div>
                <div style={{ fontFamily: 'var(--mono)', fontSize: mobile ? 10 : 13, letterSpacing: 1, textTransform: 'uppercase', color: on ? 'var(--ink)' : 'var(--mute)' }}>{s.title}</div>
              </button>
            );
          })}
        </div>
      </div>

      {/* viewport — cover room slides left to reveal the sims (cropped a touch shorter than 16:9) */}
      <div style={{ position: 'relative', overflow: 'hidden', aspectRatio: '16 / 8.2', border: '1px solid var(--rule)' }}>
        <div style={{ display: 'flex', width: `${(n + 1) * 100}%`, height: '100%', transform: `translateX(-${trackX}%)`, transition: 'transform 620ms cubic-bezier(.6,.05,.2,1)' }}>
          <div style={{ width: `${panelPct}%`, height: '100%' }}>
            <iframe src={cover} title="Rheon Labs — Workshop & Lab" style={{ width: '100%', height: '100%', border: 'none', display: 'block' }} />
          </div>
          {stations.map(s => (
            <div key={s.id} style={{ width: `${panelPct}%`, height: '100%' }}>
              <iframe src={s.src} title={s.title} style={{ width: '100%', height: '100%', border: 'none', display: 'block' }} />
            </div>
          ))}
        </div>
        {/* whole lab is clickable to enter (before entering) */}
        {!entered && (
          <button onClick={() => setEntered(true)} aria-label="Enter the workshop"
            style={{ position: 'absolute', inset: 0, zIndex: 6, background: 'transparent', border: 'none', cursor: 'pointer' }} />
        )}
      </div>

      {/* HUD (only once entered) */}
      {entered && (
        <div style={{ marginTop: 14, display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2, color: 'var(--mute)' }}>
          <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ width: 9, height: 9, borderRadius: 1, background: '#2f9d57', boxShadow: '0 0 7px #2f9d57' }} />
            LAB STATION — {active.title.toUpperCase()}
          </span>
          <span>INTERACTIVE ▸ PRESS {active.action}</span>
        </div>
      )}
    </div>
  );
}

// Award badges — small seal image + name/year, shown for projects that have won one.
// Sits in the meta sidebar (left column), stacked below KIND/YEAR/ROLE/CLIENT.
function Awards({ awards, mobile }) {
  return (
    <div style={{
      marginTop: mobile ? 28 : 36, paddingTop: mobile ? 24 : 28,
      borderTop: '1px solid var(--rule)'
    }}>
      <div style={{
        fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2,
        color: 'var(--mute)', marginBottom: 18
      }}>AWARDS</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
        {awards.map((a, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <div style={{
              width: 48, height: 48, flexShrink: 0,
              display: 'flex',
              alignItems: 'center', justifyContent: 'center', overflow: 'hidden'
            }}>
              <img src={a.image} alt={a.name}
                style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
            </div>
            <div>
              <div style={{ fontFamily: 'var(--serif)', fontSize: 15, color: 'var(--ink)' }}>{a.name}</div>
              {a.year && <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 1.5, color: 'var(--mute)' }}>{a.year}</div>}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function Detail({ project, onClose, onTerms, mobile }) {
  const headerRef = useRef(null);
  const [headerH, setHeaderH] = useState(88);
  const padX = mobile ? 20 : 56;

  useEffect(() => {
    if (headerRef.current) setHeaderH(headerRef.current.offsetHeight);
  }, []);

  return (
    <div
      className="detail-page"
      style={{
        position: 'fixed', inset: 0,
        background: 'var(--paper)',
        color: 'var(--ink)',
        zIndex: 60,
        overflow: 'auto',
        overscrollBehavior: 'contain',
        animation: 'detailIn 480ms cubic-bezier(.2,.7,.2,1) both'
      }}>

      {/* ── Sticky header ──────────────────────────────── */}
      <div ref={headerRef} style={{
        position: 'sticky', top: 0, zIndex: 30,
        background: 'var(--paper)',
        width: '100%',
      }}>
        <div style={{ maxWidth: 1280, margin: '0 auto', padding: mobile ? '22px 20px 0' : '40px 56px 0' }}>
          <header style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
            paddingBottom: 24,
            borderBottom: '1px solid var(--rule)'
          }}>
            <div style={{ display: 'flex', alignItems: 'baseline', fontFamily: 'var(--mono)', fontSize: 12, letterSpacing: 2 }}>
              <button className="hover-fade" onClick={onClose}
                style={{ background: 'transparent', border: 'none', cursor: 'pointer', padding: 0, margin: 0, font: 'inherit', letterSpacing: 'inherit', color: 'var(--ink)' }}>
                JAMES&nbsp;DOUGALL
              </button>
              &nbsp; / &nbsp;
              <button className="hover-fade" onClick={onClose}
                style={{ background: 'transparent', border: 'none', cursor: 'pointer', padding: 0, margin: 0, font: 'inherit', letterSpacing: 'inherit', color: 'var(--ink)' }}>
                PORTFOLIO
              </button>
              &nbsp; / &nbsp; {project.no}
            </div>
            <button
              className="hover-fade"
              onClick={onClose}
              style={{
                background: 'transparent', border: 'none', cursor: 'pointer',
                fontFamily: 'var(--mono)', fontSize: 12, letterSpacing: 2,
                color: 'var(--ink)', padding: '8px 0'
              }}>
              ← BACK TO INDEX
            </button>
          </header>
        </div>
      </div>

      {/* ── Gallery — sticky below header ──────────────── */}
      {project.gallery && (
        <div style={{
          position: 'sticky', top: headerH, zIndex: 5,
          background: 'var(--paper)', width: '100%',
        }}>
          <div style={{ maxWidth: 1280, margin: '0 auto', padding: `0 ${padX}px` }}>
            <MediaGallery gallery={project.gallery} mobile={mobile} />
          </div>
        </div>
      )}

      {/* ── Lab experience — sticky below header; text scrolls up over it ── */}
      {project.labStations && (
        <div style={{
          position: 'sticky', top: headerH, zIndex: 5,
          background: 'var(--paper)', width: '100%',
        }}>
          <div style={{ maxWidth: 1280, margin: '0 auto', padding: `0 ${padX}px` }}>
            <LabStations stations={project.labStations} cover={project.labCover} mobile={mobile} />
          </div>
        </div>
      )}

      {/* ── Text content — scrolls up over gallery ─────── */}
      <div style={{
        position: 'relative', zIndex: 20,
        background: 'var(--paper)',
        width: '100%',
      }}>
        <div style={{ maxWidth: 1280, margin: '0 auto', padding: mobile ? '0 20px 56px' : '0 56px 80px' }}>

          {/* hero strip — non-gallery, non-lab projects only */}
          {!project.gallery && !project.labStations && (
            <div style={{
              position: 'relative', width: '100%',
              aspectRatio: '16 / 7', marginTop: 36,
              background: 'var(--grey-1)', overflow: 'hidden'
            }}>
              {project.video
                ? <video src={project.video} autoPlay muted loop playsInline
                    style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
                : project.image
                  ? <img src={project.image} alt={project.title} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
                  : <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
                      <ThumbPlaceholder no={project.no} title={project.title} />
                    </div>
              }
            </div>
          )}

          {/* number + title block */}
          <section style={{
            display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 2fr',
            gap: mobile ? 20 : 48, marginTop: mobile ? 36 : 48, alignItems: 'start'
          }}>
            <div>
              <div style={{
                fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2,
                color: 'var(--mute)', marginBottom: 12
              }}>PROJECT&nbsp;{project.no}</div>
              <h1 style={{
                fontFamily: 'var(--display)', fontStyle: 'italic',
                fontWeight: 500, fontSize: mobile ? 40 : 72, lineHeight: 0.95,
                margin: 0, textWrap: 'balance'
              }}>{project.title}</h1>
            </div>
            <div style={{
              fontFamily: 'var(--serif)', fontSize: mobile ? 17 : 22, lineHeight: 1.45,
              color: 'var(--ink)', paddingTop: mobile ? 0 : 12, textWrap: 'pretty'
            }}>
              {project.summary}
            </div>
          </section>

          {/* meta + body */}
          <section style={{
            display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 2fr',
            gap: mobile ? 28 : 48, marginTop: mobile ? 40 : 64, paddingTop: 32,
            borderTop: '1px solid var(--rule)'
          }}>
            <div>
              <dl style={{
                margin: 0, fontFamily: 'var(--mono)', fontSize: 11,
                letterSpacing: 1.5, color: 'var(--mute)',
                display: 'grid', gridTemplateColumns: 'auto 1fr',
                gap: '14px 18px', alignContent: 'start'
              }}>
                <dt>KIND</dt><dd style={{ margin: 0, color: 'var(--ink)' }}>{project.kind}</dd>
                <dt>YEAR</dt><dd style={{ margin: 0, color: 'var(--ink)' }}>{project.year}</dd>
                <dt>ROLE</dt><dd style={{ margin: 0, color: 'var(--ink)' }}>{project.role}</dd>
                <dt>CLIENT</dt><dd style={{ margin: 0, color: 'var(--ink)' }}>{project.client}</dd>
              </dl>
              {project.awards && <Awards awards={project.awards} mobile={mobile} />}
            </div>
            <div style={{
              fontFamily: 'var(--serif)', fontSize: 18, lineHeight: 1.65,
              color: 'var(--ink)', textWrap: 'pretty'
            }}>
              {project.body.map((para, i) =>
                <p key={i} style={{ margin: '0 0 18px' }}>{para}</p>
              )}
            </div>
          </section>

          {/* footer */}
          <footer style={{
            marginTop: 80, paddingTop: 24, borderTop: '1px solid var(--rule)',
            display: 'flex', justifyContent: 'space-between',
            fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2, color: 'var(--mute)'
          }}>
            <span style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
              © {new Date().getFullYear()} James Dougall. All rights reserved.
              <button className="terms-link" onClick={onTerms}>
                Terms of Use
              </button>
            </span>
            <span>{project.year}</span>
          </footer>
        </div>
      </div>

      <style>{`
        @keyframes detailIn {
          0%   { transform: translateY(10px); }
          100% { transform: translateY(0); }
        }
        @keyframes labEnterPulse {
          0%, 100% { box-shadow: inset 0 0 0 0 rgba(122,168,255,0), 0 0 0 0 rgba(63,116,255,0); }
          50%      { box-shadow: inset 0 0 16px 0 rgba(122,168,255,0.4), 0 0 22px 2px rgba(63,116,255,0.55); }
        }
        @keyframes labShine {
          0%       { transform: translateX(-140%) skewX(-18deg); }
          55%, 100% { transform: translateX(430%) skewX(-18deg); }
        }
        @keyframes labEnterText {
          0%, 100% { transform: scale(1); }
          50%      { transform: scale(1.05); }
        }
      `}</style>
    </div>
  );
}

window.Detail = Detail;