// Annotation Fragments — responsive, with full-width ribbon variant
// -------------------------------------------------------------------
// Torn paper & broken ceramic cards. Each fragment has an irregular clip-path
// (generated from a seed) so no two are identical. Variants:
//   • 'card'   — original square-ish card (default)
//   • 'ribbon' — full-width horizontal strip; edges torn on top/bottom only

const mulberry32 = (a) => () => {
  a |= 0; a = (a + 0x6D2B79F5) | 0;
  let t = Math.imul(a ^ (a >>> 15), 1 | a);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};

// Card-style clip (all four edges torn)
const cardClip = (seed, feel) => {
  const rand = mulberry32(seed);
  const actualFeel = feel === 'mixed' ? (rand() < 0.5 ? 'torn' : 'ceramic') : feel;
  const sides = actualFeel === 'torn' ? 28 : 14;
  const jitter = actualFeel === 'torn' ? 2.8 : 4.5;
  const inset = 2;
  const pts = [];
  for (let i = 0; i <= sides; i++) pts.push([(i/sides)*100, Math.max(0, inset + (rand()-0.5)*jitter)]);
  for (let i = 1; i <= sides/2; i++) pts.push([Math.min(100, 100-inset+(rand()-0.5)*jitter), (i/(sides/2))*100]);
  for (let i = sides; i >= 0; i--) pts.push([(i/sides)*100, Math.min(100, 100-inset+(rand()-0.5)*jitter)]);
  for (let i = sides/2; i >= 1; i--) pts.push([Math.max(0, inset+(rand()-0.5)*jitter), (i/(sides/2))*100]);
  return `polygon(${pts.map(([x,y])=>`${x.toFixed(2)}% ${y.toFixed(2)}%`).join(', ')})`;
};

// Ribbon clip (only top+bottom edges torn; sides run clean to ±2%)
const ribbonClip = (seed, feel) => {
  const rand = mulberry32(seed);
  const actualFeel = feel === 'mixed' ? (rand() < 0.5 ? 'torn' : 'ceramic') : feel;
  const sides = actualFeel === 'torn' ? 60 : 22;
  const jitter = actualFeel === 'torn' ? 2.2 : 3.6;
  const pts = [];
  for (let i = 0; i <= sides; i++) pts.push([(i/sides)*100, Math.max(0, (rand()-0.5)*jitter + 1.5)]);
  pts.push([100, 100]);
  for (let i = sides; i >= 0; i--) pts.push([(i/sides)*100, Math.min(100, 100 - (rand()-0.5)*jitter - 1.5)]);
  pts.push([0, 0]);
  return `polygon(${pts.map(([x,y])=>`${x.toFixed(2)}% ${y.toFixed(2)}%`).join(', ')})`;
};

const fragmentClip = (seed, feel = 'mixed', variant = 'card') =>
  variant === 'ribbon' ? ribbonClip(seed, feel) : cardClip(seed, feel);

// Noise texture — resolved ONCE, cached by the browser. Previously inlined
// per-fragment, which meant feTurbulence ran per paint on every card. Now
// it's a single data URL shared across all fragments.
const NOISE_URL =
  "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")";

/**
 * Fragment — a single torn/ceramic piece.
 * Props:
 *   seed, feel ('torn'|'ceramic'|'mixed'), rotate,
 *   width (number|string e.g. '100%'),
 *   variant ('card'|'ribbon'),
 *   children, style
 */
const Fragment = ({
  seed = 1,
  feel = 'mixed',
  rotate = 0,
  width = 'min(480px, 100%)',
  variant = 'card',
  children,
  style = {},
}) => {
  const clip = React.useMemo(() => fragmentClip(seed, feel, variant), [seed, feel, variant]);
  // Perf notes:
  //  • `drop-shadow` filters stack poorly under the `mix-blend-mode: difference`
  //    canvas overlay — every scroll tick forces the browser to recomposite the
  //    whole stacking context. Dropped in favor of a sibling shadow div with
  //    the same clip-path (cheaper: own layer, not a filter).
  //  • The noise overlay previously used inline SVG `feTurbulence` PER fragment.
  //    feTurbulence is re-evaluated per paint. Now it's a single module-level
  //    data-URI (resolved once, cached by the browser), and the overlay uses
  //    a normal `background-image` with no blend mode — the darker paper
  //    already reads as textured without needing `mix-blend-mode: multiply`.
  return (
    <div
      className={`fragment fragment-${variant}`}
      style={{
        position: 'relative',
        width,
        maxWidth: '100%',
        transform: `rotate(${rotate}deg)`,
        ...style,
      }}
    >
      {/* Shadow layer — replaces drop-shadow filter. Slightly offset + blurred
          via a plain box-shadow-on-clipped-shape. Its own compositing layer,
          no filter pipeline. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          inset: 0,
          clipPath: clip,
          WebkitClipPath: clip,
          background: 'rgba(0,0,0,0.22)',
          transform: 'translate(0, 8px)',
          filter: 'blur(12px)',
          zIndex: 0,
        }}
      />
      <div
        style={{
          position: 'relative',
          clipPath: clip,
          WebkitClipPath: clip,
          background: `#fafaf7 ${NOISE_URL}`,
          backgroundBlendMode: 'multiply',
          backgroundSize: 'auto, 160px 160px',
          padding: variant === 'ribbon'
            ? 'clamp(22px, 3vw, 36px) clamp(28px, 5vw, 72px)'
            : 'clamp(22px, 2.4vw, 30px) clamp(22px, 2.6vw, 34px)',
          color: '#0a0a0a',
          fontFamily: 'var(--font-mono)',
          lineHeight: 1.35,
          zIndex: 1,
        }}
      >
        {children}
      </div>
    </div>
  );
};

/* Slot components */

const QuoteFragment = ({ seed, rotate, width, variant, quote, cite }) => (
  <Fragment seed={seed} rotate={rotate} width={width} variant={variant} feel="torn">
    <div style={{ fontSize: 12, letterSpacing: '0.14em', textTransform: 'uppercase', opacity: 0.5, marginBottom: 14 }}>
      Note
    </div>
    <div style={{ fontSize: 'clamp(18px, 2vw, 22px)', fontWeight: 600, textWrap: 'pretty' }}>
      <span style={{ fontSize: 40, lineHeight: 0, position: 'relative', top: 8, marginRight: 4 }}>“</span>
      {quote}
      <span style={{ fontSize: 40, lineHeight: 0, position: 'relative', top: 8, marginLeft: 2 }}>”</span>
    </div>
    {cite && (
      <div style={{ marginTop: 16, fontSize: 12, letterSpacing: '0.1em', opacity: 0.55 }}>
        — {cite}
      </div>
    )}
  </Fragment>
);

const PostFragment = ({ seed, rotate, width, variant, tag, title, excerpt, date }) => (
  <Fragment seed={seed} rotate={rotate} width={width} variant={variant} feel="ceramic">
    <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12, fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', gap: 8 }}>
      <span style={{ fontWeight: 700 }}>{tag}</span>
      <span style={{ opacity: 0.5 }}>{date}</span>
    </div>
    <h3 style={{ margin: 0, fontSize: 'clamp(18px, 2.2vw, 24px)', fontWeight: 700, lineHeight: 1.2, textWrap: 'balance' }}>
      {title}
    </h3>
    <p style={{ marginTop: 12, marginBottom: 16, fontSize: 'clamp(13px, 1.4vw, 14px)', opacity: 0.72, lineHeight: 1.55, textWrap: 'pretty' }}>
      {excerpt}
    </p>
    <div style={{ fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', display: 'inline-flex', alignItems: 'center', gap: 8, borderBottom: '1px solid currentColor', paddingBottom: 2 }}>
      Read<span>→</span>
    </div>
  </Fragment>
);

const ManifestoFragment = ({ seed, rotate, width, variant, text, index }) => (
  <Fragment seed={seed} rotate={rotate} width={width} variant={variant} feel="mixed">
    <div style={{ fontSize: 11, letterSpacing: '0.18em', opacity: 0.4, marginBottom: 10 }}>
      {String(index).padStart(2, '0')} / STANCE
    </div>
    <div style={{ fontSize: 'clamp(22px, 2.6vw, 28px)', fontWeight: 700, lineHeight: 1.15, textWrap: 'balance' }}>
      {text}
    </div>
  </Fragment>
);

// Ribbon-style manifesto: full-width banner across the page.
const ManifestoRibbon = ({ seed, rotate = 0, text, index }) => (
  <Fragment seed={seed} rotate={rotate} width="100%" variant="ribbon" feel="torn">
    <div style={{ display: 'flex', alignItems: 'center', gap: 'clamp(16px, 3vw, 40px)', flexWrap: 'wrap' }}>
      <div style={{ fontSize: 11, letterSpacing: '0.22em', opacity: 0.4, flexShrink: 0 }}>
        {String(index).padStart(2, '0')} / STANCE
      </div>
      <div style={{ fontSize: 'clamp(22px, 3.4vw, 42px)', fontWeight: 700, lineHeight: 1.1, textWrap: 'balance', flex: 1, minWidth: 0 }}>
        {text}
      </div>
    </div>
  </Fragment>
);

// Ribbon-style quote: full-width torn paper banner with a pull quote.
const QuoteRibbon = ({ seed, rotate = 0, quote, cite }) => (
  <Fragment seed={seed} rotate={rotate} width="100%" variant="ribbon" feel="torn">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 'clamp(16px, 3vw, 40px)', flexWrap: 'wrap' }}>
      <div style={{ fontSize: 11, letterSpacing: '0.22em', opacity: 0.4, flexShrink: 0, paddingTop: 8 }}>
        NOTE
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 'clamp(20px, 2.6vw, 32px)', fontWeight: 600, lineHeight: 1.25, textWrap: 'pretty' }}>
          <span style={{ fontSize: 50, lineHeight: 0, position: 'relative', top: 10, marginRight: 4 }}>“</span>
          {quote}
          <span style={{ fontSize: 50, lineHeight: 0, position: 'relative', top: 10, marginLeft: 2 }}>”</span>
        </div>
        {cite && (
          <div style={{ marginTop: 14, fontSize: 12, letterSpacing: '0.12em', opacity: 0.55 }}>
            — {cite}
          </div>
        )}
      </div>
    </div>
  </Fragment>
);

// Ribbon-style post: full-width torn paper banner with article meta + body.
const PostRibbon = ({ seed, rotate = 0, tag, title, excerpt, date }) => (
  <Fragment seed={seed} rotate={rotate} width="100%" variant="ribbon" feel="ceramic">
    <div style={{ display: 'grid', gridTemplateColumns: 'minmax(120px, 200px) 1fr minmax(140px, auto)', gap: 'clamp(20px, 3vw, 48px)', alignItems: 'center' }}>
      <div>
        <div style={{ fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 700 }}>{tag}</div>
        <div style={{ fontSize: 11, letterSpacing: '0.14em', opacity: 0.5, marginTop: 6 }}>{date}</div>
      </div>
      <div style={{ minWidth: 0 }}>
        <h3 style={{ margin: 0, fontSize: 'clamp(20px, 2.6vw, 30px)', fontWeight: 700, lineHeight: 1.18, textWrap: 'balance' }}>{title}</h3>
        {excerpt && (
          <p style={{ marginTop: 10, marginBottom: 0, fontSize: 'clamp(13px, 1.4vw, 15px)', opacity: 0.7, lineHeight: 1.55, textWrap: 'pretty' }}>{excerpt}</p>
        )}
      </div>
      <div style={{ fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', display: 'inline-flex', alignItems: 'center', gap: 8, borderBottom: '1px solid currentColor', paddingBottom: 2, justifySelf: 'end' }}>
        Read<span>→</span>
      </div>
    </div>
  </Fragment>
);

Object.assign(window, {
  Fragment, QuoteFragment, PostFragment, ManifestoFragment,
  QuoteRibbon, PostRibbon, ManifestoRibbon,
  fragmentClip,
});
