/* ============================================================
   BRAND GRAPHICS - the "break the line" device, made visual.
   Motion is ENHANCEMENT ONLY: every element is visible by default
   and self-heals (setTimeout fallback) so a throttled/background
   tab, disabled JS, or reduced-motion never leaves content hidden.
   ============================================================ */

const { useRef, useState, useEffect } = React;

const motionOff = () =>
  (typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches)
  || document.documentElement.classList.contains('motion-off');

// Arm (hide) then guarantee a later reveal via IO + setTimeout safety.
// Returns a boolean `armed` and a ref to attach.
function useEntrance(delay = 0) {
  const ref = useRef(null);
  const [armed, setArmed] = useState(false); // default: visible
  useEffect(() => {
    const el = ref.current;
    if (!el || motionOff()) return;
    setArmed(true); // hide, about to animate in
    let io;
    const show = () => { setArmed(false); if (io) io.disconnect(); };
    const r = el.getBoundingClientRect();
    const inView = r.top < (window.innerHeight || 800) * 0.95 && r.bottom > 0;
    let timer;
    if (inView) {
      timer = setTimeout(show, 60 + delay);
    } else {
      io = new IntersectionObserver(
        (es) => { if (es.some((e) => e.isIntersecting)) show(); },
        { threshold: 0.1, rootMargin: '0px 0px -6% 0px' }
      );
      io.observe(el);
      timer = setTimeout(show, 2600); // self-heal if IO never fires
    }
    return () => { if (io) io.disconnect(); clearTimeout(timer); };
  }, []);
  return [ref, armed];
}

// ── BrokenRing ───────────────────────────────────────────────
// The signature mark, oversized. Single open arc, gap at ~1 o'clock.
// Static (always drawn) so it can never go missing. Never closes.
const BrokenRing = ({ size = 420, color = '#1a6b5a', sw = 2, style }) => {
  const r = 42, cx = 50, cy = 50;
  const startDeg = 55, endDeg = 350;
  const toXY = (deg) => {
    const rad = (deg - 90) * Math.PI / 180;
    return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
  };
  const [x1, y1] = toXY(startDeg);
  const [x2, y2] = toXY(endDeg);
  const sweep = ((endDeg - startDeg + 360) % 360);
  const largeArc = sweep > 180 ? 1 : 0;
  const d = `M ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2}`;
  const strokeVB = (sw / size) * 100;
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" aria-hidden="true"
         style={{ display: 'block', overflow: 'visible', ...style }}>
      <path d={d} fill="none" stroke={color} strokeWidth={strokeVB} strokeLinecap="round" />
    </svg>
  );
};

// ── BrokenLine ───────────────────────────────────────────────
// A full-bleed rule that literally breaks; orange dot at the break.
const BrokenLine = ({ color = '#1c1c1c', gap = 64, dot = '#d4883a' }) => {
  const [ref, armed] = useEntrance();
  return (
    <div ref={ref} className={armed ? 'etp-bl armed' : 'etp-bl'}
         style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
      <span className="etp-bl-seg" style={{ background: color }} />
      <span style={{ flex: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', width: gap }}>
        <span className="etp-bl-dot" style={{ background: dot }} />
      </span>
      <span className="etp-bl-seg" style={{ background: color }} />
    </div>
  );
};

// ── Marquee ──────────────────────────────────────────────────
// Slow mantra ticker. Holds static when motion is off (content visible).
const Marquee = ({ items = ['See it', 'Name it', 'Stop it'], bg = '#1c1c1c', color = '#f4f1eb', dot = '#d4883a', speed = 32 }) => {
  const Group = () => (
    <span className="etp-mq-group">
      {[...items, ...items, ...items].map((t, i) => (
        <span key={i} className="etp-mq-item">
          <span className="etp-mq-dot" style={{ background: dot }} />
          <span>{t}</span>
        </span>
      ))}
    </span>
  );
  return (
    <div className="etp-mq" style={{ background: bg, color }}>
      <div className="etp-mq-track" style={{ animationDuration: `${speed}s` }}>
        <Group /><Group />
      </div>
    </div>
  );
};

// ── Generations ──────────────────────────────────────────────
// Editorial illustration: four figures pass the line down; it
// breaks before the fifth, who stands on their own ground.
const Generations = ({ color = '#1c1c1c', teal = '#1a6b5a', dot = '#d4883a', style }) => (
  <svg viewBox="0 0 560 132" aria-hidden="true"
       style={{ display: 'block', width: '100%', maxWidth: 560, height: 'auto', overflow: 'visible', ...style }}>
    {/* the inherited line, running under four generations */}
    <line x1="14" y1="108" x2="416" y2="108" stroke={color} strokeWidth="2" strokeLinecap="round" />
    {[64, 168, 272, 376].map((x, i) => (
      <g key={x}>
        <circle cx={x} cy="44" r="13" fill="none" stroke={color} strokeWidth="2" />
        <line x1={x} y1="57" x2={x} y2="108" stroke={color} strokeWidth="2" strokeLinecap="round" />
      </g>
    ))}
    {/* the break */}
    <circle cx="446" cy="108" r="5" fill={dot} />
    {/* the one who stands still - own ground, not the old line */}
    <circle cx="506" cy="40" r="14" fill="none" stroke={teal} strokeWidth="2.5" />
    <line x1="506" y1="54" x2="506" y2="108" stroke={teal} strokeWidth="2.5" strokeLinecap="round" />
    <line x1="480" y1="112" x2="532" y2="112" stroke={teal} strokeWidth="2.5" strokeLinecap="round" />
  </svg>
);

// ── CircleRoom ───────────────────────────────────────────────
// The room: seats around an open circle. The gap is the door -
// the circle never closes, and one seat is yours.
const CircleRoom = ({ size = 320, color = '#1c1c1c', dot = '#d4883a', style }) => {
  const cx = 100, cy = 100, r = 66;
  const toXY = (deg, rad = r) => {
    const a = (deg - 90) * Math.PI / 180;
    return [cx + rad * Math.cos(a), cy + rad * Math.sin(a)];
  };
  const [ax1, ay1] = toXY(58);
  const [ax2, ay2] = toXY(354);
  const arc = `M ${ax1} ${ay1} A ${r} ${r} 0 1 1 ${ax2} ${ay2}`;
  const seats = [80, 112, 144, 176, 208, 240, 272, 304, 336];
  return (
    <svg width={size} height={size} viewBox="0 0 200 200" aria-hidden="true"
         style={{ display: 'block', overflow: 'visible', ...style }}>
      <path d={arc} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" opacity="0.55" />
      {seats.map((deg, i) => {
        const [x, y] = toXY(deg);
        return <circle key={deg} cx={x} cy={y} r="6.5" fill={i === 4 ? dot : 'none'} stroke={i === 4 ? dot : color} strokeWidth="2" />;
      })}
    </svg>
  );
};

// ── PathSteps ────────────────────────────────────────────────
// Six chapters as ascending steps; the orange dot is where you
// end up - standing on work you built yourself.
const PathSteps = ({ color = '#1c1c1c', dot = '#d4883a', style }) => (
  <svg viewBox="0 0 372 216" aria-hidden="true"
       style={{ display: 'block', width: '100%', maxWidth: 372, height: 'auto', overflow: 'visible', ...style }}>
    {[0, 1, 2, 3, 4, 5].map((i) => {
      const h = 26 + i * 28;
      return (
        <rect key={i} x={10 + i * 58} y={204 - h} width="46" height={h}
              fill="none" stroke={color} strokeWidth="2" />
      );
    })}
    <circle cx="323" cy="24" r="8" fill={dot} />
  </svg>
);

// ── StoryPhoto ───────────────────────────────────────────────
// Editorial photograph treatment: hairline border, slight
// desaturation + teal wash so photography sits inside the
// palette. Hides itself entirely if the image fails to load,
// so a dead URL can never break the layout.
const StoryPhoto = ({ src, alt, caption, ratio = '4 / 3', style }) => (
  <figure style={{ margin: 0, ...style }}>
    <div style={{ position: 'relative', border: '1px solid #1c1c1c', overflow: 'hidden', aspectRatio: ratio, background: '#e6e0d2' }}>
      <img
        src={src}
        alt={alt}
        loading="lazy"
        onError={(e) => { const f = e.currentTarget.closest('figure'); if (f) f.style.display = 'none'; }}
        style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', filter: 'saturate(0.8) contrast(1.03)' }}
      />
      <div style={{ position: 'absolute', inset: 0, background: 'rgba(26,107,90,0.09)', mixBlendMode: 'multiply', pointerEvents: 'none' }} />
    </div>
    {caption && <figcaption className="label" style={{ color: '#666', marginTop: 10 }}>{caption}</figcaption>}
  </figure>
);

// ── Reveal ───────────────────────────────────────────────────
const Reveal = ({ children, delay = 0, y = 18, style, className = '', ...rest }) => {
  const [ref, armed] = useEntrance(delay);
  return (
    <div ref={ref}
         className={`etp-reveal ${armed ? 'armed' : ''} ${className}`}
         style={{ transitionDelay: `${delay}ms`, '--reveal-y': `${y}px`, ...style }}
         {...rest}>
      {children}
    </div>
  );
};

Object.assign(window, { BrokenRing, BrokenLine, Marquee, Reveal, Generations, CircleRoom, PathSteps, StoryPhoto });
