/* ============================================================
   3point Digital — shared lib
   Brand mark, scroll-reveal, animated counters, layout helpers.
   ============================================================ */

const { useState, useEffect, useRef, createContext, useContext } = React;

/* Motion can be switched off via Tweaks. When off, everything is
   rendered in its final visible state (good for reduced-motion too). */
const MotionCtx = createContext(true);

/* ---------- Brand mark --------------------------------------
   Glyph: three points — triangulation = precision; the apex
   point is the accent = momentum. Sentence-case wordmark. */
function BrandMark({ height = 24, inverse = false, glyphOnly = false }) {
  const ink = inverse ? 'var(--inverse-ink)' : 'var(--ink)';
  const muted = inverse ? 'var(--inverse-ink-muted)' : 'var(--ink-muted)';
  const s = height;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: Math.round(s * 0.42) }}>
      <svg width={s} height={s} viewBox="0 0 28 28" fill="none" aria-hidden="true" style={{ flex: '0 0 auto' }}>
        <line x1="14" y1="5.2" x2="6" y2="22.4" stroke={ink} strokeWidth="1.1" strokeOpacity="0.32" />
        <line x1="14" y1="5.2" x2="22" y2="22.4" stroke={ink} strokeWidth="1.1" strokeOpacity="0.32" />
        <line x1="6" y1="22.4" x2="22" y2="22.4" stroke={ink} strokeWidth="1.1" strokeOpacity="0.32" />
        <circle cx="6" cy="22.4" r="3.1" fill={ink} />
        <circle cx="22" cy="22.4" r="3.1" fill={ink} />
        <circle cx="14" cy="5.2" r="3.4" fill="var(--accent)" />
      </svg>
      {!glyphOnly && (
        <span style={{
          fontFamily: 'var(--font-display)', fontSize: Math.round(s * 0.74),
          letterSpacing: '-0.4px', lineHeight: 1, whiteSpace: 'nowrap',
        }}>
          <span style={{ color: ink, fontWeight: 600 }}>3point</span>
          <span style={{ color: muted, fontWeight: 400 }}> digital</span>
        </span>
      )}
    </span>
  );
}

/* ---------- Scroll reveal -----------------------------------
   Fades + lifts children into place once, on first intersection.
   `delay` staggers siblings. No-ops (renders final state) when
   motion is off. */
function Reveal({ children, delay = 0, y = 18, as = 'div', style = {}, className = '', ...rest }) {
  const motion = useContext(MotionCtx);
  const ref = useRef(null);
  const [shown, setShown] = useState(false);

  useEffect(() => {
    if (!motion) { setShown(true); return; }
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reveal = () => { if (!done) { done = true; setShown(true); cleanup(); } };
    const check = () => {
      const vh = window.innerHeight || document.documentElement.clientHeight || 800;
      const r = el.getBoundingClientRect();
      if (r.top < vh * 0.92 && r.bottom > 0) reveal();
    };
    const onScroll = () => check();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    // Re-check across a few frames so above-the-fold content reveals once the
    // iframe has a real height (innerHeight can be 0 at first paint).
    const timers = [50, 250, 600].map((ms) => setTimeout(check, ms));
    function cleanup() {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
      timers.forEach(clearTimeout);
    }
    return cleanup;
  }, [motion]);

  const Tag = as;
  const motionStyle = motion ? {
    opacity: shown ? 1 : 0,
    transform: shown ? 'none' : `translateY(${y}px)`,
    transition: `opacity 620ms cubic-bezier(0.22,1,0.36,1) ${delay}ms, transform 620ms cubic-bezier(0.22,1,0.36,1) ${delay}ms`,
    willChange: 'opacity, transform',
  } : {};

  return (
    <Tag ref={ref} className={className} style={{ ...motionStyle, ...style }} {...rest}>
      {children}
    </Tag>
  );
}

/* ---------- Animated counter --------------------------------
   Counts from 0 → value when scrolled into view. */
function Counter({ value, decimals = 0, prefix = '', suffix = '', duration = 1400 }) {
  const motion = useContext(MotionCtx);
  const ref = useRef(null);
  const [display, setDisplay] = useState(motion ? 0 : value);

  useEffect(() => {
    if (!motion) { setDisplay(value); return; }
    const el = ref.current;
    if (!el) return;
    let raf, started = false;
    const run = () => {
      if (started) return;
      started = true;
      cleanup();
      const t0 = performance.now();
      const tick = (now) => {
        const p = Math.min(1, (now - t0) / duration);
        const eased = 1 - Math.pow(1 - p, 3);
        setDisplay(value * eased);
        if (p < 1) raf = requestAnimationFrame(tick);
      };
      raf = requestAnimationFrame(tick);
    };
    const check = () => {
      const vh = window.innerHeight || document.documentElement.clientHeight || 800;
      const r = el.getBoundingClientRect();
      if (r.top < vh * 0.85 && r.bottom > 0) run();
    };
    const onScroll = () => check();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    const timers = [50, 250, 600].map((ms) => setTimeout(check, ms));
    function cleanup() {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
      timers.forEach(clearTimeout);
    }
    return () => { cleanup(); cancelAnimationFrame(raf); };
  }, [motion, value]);

  const formatted = display.toLocaleString('en-US', {
    minimumFractionDigits: decimals, maximumFractionDigits: decimals,
  });

  return <span ref={ref}>{prefix}{formatted}{suffix}</span>;
}

/* ---------- Layout primitives -------------------------------- */
function Container({ children, style = {}, ...rest }) {
  return (
    <div style={{
      maxWidth: 'var(--container-max)', margin: '0 auto',
      padding: '0 clamp(20px, 5vw, 40px)', boxSizing: 'border-box', ...style,
    }} {...rest}>{children}</div>
  );
}

function Section({ id, children, label, style = {}, pad = 'var(--space-section)' }) {
  return (
    <section id={id} data-screen-label={label} style={{ padding: `${pad} 0`, ...style }}>
      <Container>{children}</Container>
    </section>
  );
}

/* Section header: eyebrow + headline + optional lede, left or center. */
function SectionHead({ eyebrow, title, lede, align = 'left', max = 620, children }) {
  const { Eyebrow } = window.EditorialCSDesignSystem_8c71a4;
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 'var(--space-md)',
      alignItems: align === 'center' ? 'center' : 'flex-start',
      textAlign: align === 'center' ? 'center' : 'left',
      maxWidth: align === 'center' ? max : 'none',
      margin: align === 'center' ? '0 auto' : 0,
    }}>
      {eyebrow && <Reveal><Eyebrow dot tone="muted">{eyebrow}</Eyebrow></Reveal>}
      {title && (
        <Reveal delay={60} className="t-display-md" style={{ maxWidth: max, color: 'var(--ink)', textWrap: 'balance', margin: 0 }} as="h2">
          {title}
        </Reveal>
      )}
      {lede && (
        <Reveal delay={120} className="t-subhead" style={{ maxWidth: max, color: 'var(--ink-muted)', textWrap: 'pretty' }} as="p">
          {lede}
        </Reveal>
      )}
      {children}
    </div>
  );
}

/* ---------- Phone mockup — Instagram Reel embed -------------
   Paste any instagram.com/reel/… or /p/… URL via the in-frame
   input. Embeds autoplay (muted). Click overlay → redirect modal. */
function PhoneShot({ id, src = '', maxWidth = 300 }) {
  const [showRedirect, setShowRedirect] = useState(false);

  const embedUrl = (() => {
    const m = src.match(/instagram\.com\/(reel|p)\/([A-Za-z0-9_-]+)/);
    return m ? `https://www.instagram.com/${m[1]}/${m[2]}/embed/?cr=1&v=14` : null;
  })();

  return (
    <div style={{
      width: '100%', maxWidth, background: 'var(--ink)',
      borderRadius: 36, padding: 10, boxSizing: 'border-box',
    }}>
      {/* notch */}
      <div style={{ display: 'flex', justifyContent: 'center', paddingBottom: 8 }}>
        <span style={{ width: 64, height: 5, borderRadius: 999, background: 'rgba(255,255,255,0.28)' }} />
      </div>

      <div style={{ borderRadius: 26, overflow: 'hidden', position: 'relative', aspectRatio: '9/16', background: '#111' }}>

        {embedUrl ? (
          <>
            <iframe
              src={embedUrl}
              style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', border: 'none', display: 'block' }}
              allow="autoplay; encrypted-media; fullscreen"
              scrolling="no"
            />
            {/* transparent click capture */}
            <div onClick={() => setShowRedirect(true)}
              style={{ position: 'absolute', inset: 0, cursor: 'pointer', zIndex: 2 }} />
            {/* redirect modal */}
            {showRedirect && (
              <div style={{
                position: 'absolute', inset: 0, zIndex: 10,
                background: 'rgba(0,0,0,0.82)', backdropFilter: 'blur(8px)',
                display: 'flex', flexDirection: 'column',
                alignItems: 'center', justifyContent: 'center', gap: 16, padding: 24,
              }}>
                <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="1.8" strokeLinecap="round">
                  <rect x="2" y="2" width="20" height="20" rx="5" ry="5"/>
                  <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/>
                  <line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/>
                </svg>
                <p style={{ color: '#fff', fontSize: 14, fontWeight: 600, margin: 0, textAlign: 'center', lineHeight: 1.4 }}>
                  Watch this Reel<br/>on Instagram?
                </p>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', justifyContent: 'center' }}>
                  <a href={src} target="_blank" rel="noopener noreferrer"
                    onClick={() => setShowRedirect(false)}
                    style={{
                      padding: '10px 20px',
                      background: 'linear-gradient(135deg,#f09433 0%,#e6683c 25%,#dc2743 50%,#cc2366 75%,#bc1888 100%)',
                      color: '#fff', borderRadius: 10, textDecoration: 'none',
                      fontWeight: 700, fontSize: 14, whiteSpace: 'nowrap',
                    }}>Open Instagram</a>
                  <button onClick={() => setShowRedirect(false)} style={{
                    padding: '10px 16px', background: 'rgba(255,255,255,0.12)',
                    border: '1px solid rgba(255,255,255,0.22)', color: '#fff',
                    borderRadius: 10, cursor: 'pointer', fontSize: 14,
                  }}>Dismiss</button>
                </div>
              </div>
            )}
          </>
        ) : (
          <div style={{
            position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center', gap: 10,
            background: 'var(--surface-2)',
          }}>
            <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" strokeWidth="1.5" strokeLinecap="round">
              <rect x="2" y="2" width="20" height="20" rx="5" ry="5"/>
              <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/>
              <line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/>
            </svg>
            <span style={{ color: 'var(--ink-muted)', fontSize: 12, textAlign: 'center', padding: '0 24px', lineHeight: 1.5 }}>
              No Reel linked
            </span>
          </div>
        )}

      </div>
    </div>
  );
}

/* Tiny inline arrow used in text links / buttons. */
function ArrowIcon({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
      strokeWidth="1.85" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <line x1="5" y1="12" x2="19" y2="12" />
      <polyline points="13 6 19 12 13 18" />
    </svg>
  );
}

/* Text link with a nudging arrow on hover. */
function TextLink({ children, onClick, href = '#', style = {} }) {
  const [hover, setHover] = useState(false);
  return (
    <a href={href} onClick={(e) => { if (onClick) { e.preventDefault(); onClick(e); } }}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 8, textDecoration: 'none',
        fontFamily: 'var(--font-body)', fontSize: 'var(--type-body-size)', fontWeight: 500,
        color: 'var(--ink)', ...style,
      }}>
      {children}
      <span style={{ display: 'inline-flex', transform: hover ? 'translateX(4px)' : 'none', transition: 'transform 180ms ease', color: 'var(--accent)' }}>
        <ArrowIcon />
      </span>
    </a>
  );
}

Object.assign(window, {
  MotionCtx, BrandMark, Reveal, Counter, Container, Section, SectionHead, ArrowIcon, TextLink, PhoneShot,
});
