/* global React */
// Shared cosmetic helpers for the Jullia website UI kit.
// Not design-system primitives — kit-local scaffolding only.

// A low-key photo frame — src given, it shows real photography treated in the
// atelier's mono hand (desaturated, deep shadow, a single-lamp vignette, a slow
// one-time reveal scale). No src, it falls back to the original art-direction
// placeholder, stating the intended shot instead.
function Media({ label, caption, src, alt, ratio = '16 / 9', tone = 'inset', showCaption = true, style = {} }) {
  const bg = tone === 'raised' ? 'var(--surface-raised)' : tone === 'surface' ? 'var(--surface)' : 'var(--surface-inset)';
  return (
    <figure className="jx-media" style={{ margin: 0, position: 'relative', aspectRatio: ratio, background: bg, border: '1px solid var(--hairline)', overflow: 'hidden', display: 'flex', alignItems: 'flex-end', ...style }}>
      {src && (
        <img
          className="jx-media-img"
          src={src}
          alt={alt || caption || label || ''}
          style={{
            position: 'absolute', inset: 0, width: '100%', height: '100%',
            objectFit: 'cover', filter: 'grayscale(0.55) contrast(1.08) brightness(0.82)',
          }}
        />
      )}
      {/* single-lamp vignette, drawn with value only */}
      <div style={{ position: 'absolute', inset: 0, background: src ? 'linear-gradient(180deg, rgba(0,0,0,0.05), rgba(0,0,0,0.45) 88%), radial-gradient(120% 90% at 30% 15%, rgba(255,255,255,0.07), transparent 55%)' : 'radial-gradient(120% 90% at 30% 20%, rgba(255,255,255,0.05), transparent 60%)', pointerEvents: 'none' }} />
      {showCaption && (
        <figcaption style={{ position: 'relative', padding: 'var(--space-5)', display: 'flex', flexDirection: 'column', gap: 6 }}>
          {!src && <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--text-2xs)', letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: 'var(--text-tertiary)' }}>Image</span>}
          <span style={{ fontFamily: 'var(--font-sans)', fontWeight: 300, fontSize: 'var(--text-base)', color: src ? 'var(--text-primary)' : 'var(--text-secondary)', maxWidth: 380, lineHeight: 1.4 }}>{caption || label}</span>
        </figcaption>
      )}
    </figure>
  );
}

// Reveal-on-scroll. The base state ([data-reveal]) is hidden; this reveals nodes by
// setting the final values INLINE (so paint is guaranteed even if the composited CSS
// transition never plays). IntersectionObserver drives the on-scroll fade as an
// enhancement, and a double-rAF guarantees every tracked node ends visible on mount —
// the transition still animates 0→1 for anything currently in view.
function useReveal() {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const nodes = [...(el.hasAttribute('data-reveal') ? [el] : []), ...el.querySelectorAll('[data-reveal]')];
    const reveal = (n) => { n.setAttribute('data-revealed', ''); n.style.opacity = '1'; n.style.transform = 'none'; };

    let io;
    if ('IntersectionObserver' in window) {
      io = new IntersectionObserver((entries) => {
        entries.forEach((e) => { if (e.isIntersecting) { reveal(e.target); io.unobserve(e.target); } });
      }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' });
      nodes.forEach((n) => io.observe(n));
    }

    // Guarantee visibility: reveal in-view nodes on the next frame (they fade in),
    // then reveal everything shortly after so nothing can stay hidden.
    const raf = requestAnimationFrame(() => {
      const vh = window.innerHeight || document.documentElement.clientHeight;
      nodes.forEach((n) => { if (n.getBoundingClientRect().top < vh * 0.95) reveal(n); });
    });
    const t = setTimeout(() => nodes.forEach(reveal), 900);

    return () => { if (io) io.disconnect(); cancelAnimationFrame(raf); clearTimeout(t); };
  }, []);
  return ref;
}

// A rework-film placeholder. Reads as a video still with a play affordance; no
// real footage is bundled. Click toggles a quiet "playing" caption. Swap the
// inner surface for a real <video> (low-key, single source) in production.
function VideoPlate({ caption, ratio = '16 / 9', style = {} }) {
  const [playing, setPlaying] = React.useState(false);
  return (
    <figure
      onClick={() => setPlaying((p) => !p)}
      style={{ margin: 0, position: 'relative', aspectRatio: ratio, background: 'var(--gray-990)', border: '1px solid var(--hairline)', overflow: 'hidden', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', ...style }}
    >
      <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(90% 90% at 50% 45%, rgba(255,255,255,0.05), transparent 62%)', pointerEvents: 'none' }} />
      {/* play / pause affordance — a hairline ring, monochrome */}
      <div style={{ position: 'relative', width: 74, height: 74, borderRadius: '50%', border: '1px solid var(--hairline-strong)', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'border-color var(--dur-med) var(--ease-quiet)' }}>
        {playing ? (
          <span style={{ display: 'flex', gap: 6 }}>
            <span style={{ width: 4, height: 20, background: 'var(--text-primary)' }} />
            <span style={{ width: 4, height: 20, background: 'var(--text-primary)' }} />
          </span>
        ) : (
          <span style={{ width: 0, height: 0, borderTop: '11px solid transparent', borderBottom: '11px solid transparent', borderLeft: '18px solid var(--text-primary)', marginLeft: 4 }} />
        )}
      </div>
      <figcaption style={{ position: 'absolute', left: 0, right: 0, bottom: 0, padding: 'var(--space-5)', display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 'var(--space-5)' }}>
        <span style={{ fontFamily: 'var(--font-sans)', fontWeight: 300, fontSize: 'var(--text-base)', color: 'var(--text-secondary)', maxWidth: 460, lineHeight: 1.4 }}>{caption}</span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--text-2xs)', letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: 'var(--text-tertiary)', whiteSpace: 'nowrap' }}>{playing ? '— Playing' : 'Film ▸'}</span>
      </figcaption>
    </figure>
  );
}

Object.assign(window, { Media, VideoPlate, useReveal });
