/* global React */
// Shared bits: image URLs, sample word data, demo hooks.

const IMG = {
  // Library / dark academia stacks — using local assets
  libraryStacks: "assets/library-grand.jpg",   // grand baroque library — hero
  spiralStairs:  "assets/spiral-stairs.jpg",   // wrought-iron spiral stairs in stacks
  libraryArches: "https://images.unsplash.com/photo-1572969057101-2837cb1f0bbb?w=1800&q=85&auto=format&fit=crop",
  libraryAisle:  "https://images.unsplash.com/photo-1507842217343-583bb7270b66?w=1400&q=80&auto=format&fit=crop",
  libraryGrand:  "assets/library-grand.jpg",
  oldBooks:      "https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=1400&q=80&auto=format&fit=crop",
  bookSpines:    "https://images.unsplash.com/photo-1457369804613-52c61a468e7d?w=1200&q=80&auto=format&fit=crop",
  candle:        "https://images.unsplash.com/photo-1602528054991-79edcb674ed3?w=900&q=80&auto=format&fit=crop",
  // Busts & sculpture
  bustHead:      "https://images.unsplash.com/photo-1589998059171-988d887df646?w=900&q=80&auto=format&fit=crop",
  bustProfile:   "https://images.unsplash.com/photo-1562924538-bbc63b3a3a30?w=900&q=80&auto=format&fit=crop",
  marbleHand:    "https://images.unsplash.com/photo-1605721911519-3dfeb3be25e7?w=900&q=80&auto=format&fit=crop",
  // Quill / writing
  quillInk:      "https://images.unsplash.com/photo-1455390582262-044cdead277a?w=1200&q=80&auto=format&fit=crop",
  oldPaper:      "https://images.unsplash.com/photo-1519682337058-a94d519337bc?w=1400&q=80&auto=format&fit=crop",
  manuscript:    "https://images.unsplash.com/photo-1532153259564-a5f24f261f51?w=1200&q=80&auto=format&fit=crop",
  // Texture / atmosphere
  velvet:        "https://images.unsplash.com/photo-1582123509004-de2afa6c0747?w=1200&q=80&auto=format&fit=crop",
  ceiling:       "https://images.unsplash.com/photo-1565060169187-e284c2f2bcfc?w=1600&q=80&auto=format&fit=crop",
};

// Synonym cycler — the headline word morphs through synonyms.
const SYNONYM_CYCLE = [
  { word: "lexicon",     gloss: "n. — the words of a language, a person, a craft" },
  { word: "vernacular",  gloss: "n. — the language of a place, ordinary speech" },
  { word: "argot",       gloss: "n. — the private idiom of a closed group" },
  { word: "idiolect",    gloss: "n. — the language of one mind, peculiar to a single speaker" },
  { word: "diction",     gloss: "n. — the choice of words; the cut of one's voice" },
  { word: "parlance",    gloss: "n. — a particular manner of speaking" },
];

// Sample word + Claude rewrite (used in the demo block)
const SAMPLE_WORD = {
  word: "lambent",
  pos: "adj.",
  definition: "softly glowing or flickering; lit from within, never harsh.",
  synonyms: ["luminous", "gleaming", "incandescent", "radiant", "gilded"],
};

const SAMPLE_DRAFT = "The candles in the library were bright and warm and made the room feel old.";
const SAMPLE_REWRITE = "A lambent hush of candlelight aged the room.";
const CRAFT_MOVE = {
  name: "Compression + nominalisation",
  note: "Three coordinated clauses collapsed into one image. The verb 'aged' carries the sentence's weight; 'lambent' supplies the warmth that 'bright and warm' bled across two adjectives.",
};

// Synonym cycler hook — index advances on a timer, returns current entry + idx.
function useCycler(items, ms = 2400) {
  const [i, setI] = React.useState(0);
  React.useEffect(() => {
    const t = setInterval(() => setI((x) => (x + 1) % items.length), ms);
    return () => clearInterval(t);
  }, [items, ms]);
  return [items[i], i, setI];
}

// Live-typing hook — types `text` char-by-char, then pauses, then optionally
// erases and types the next entry from `texts` (array). Used for the Claude
// rewrite demo.
function useTyper(texts, { typeMs = 28, holdMs = 1800, eraseMs = 14, loop = true } = {}) {
  const [str, setStr] = React.useState("");
  const [idx, setIdx] = React.useState(0);
  const [phase, setPhase] = React.useState("typing"); // typing | holding | erasing

  React.useEffect(() => {
    const target = texts[idx] || "";
    if (phase === "typing") {
      if (str.length < target.length) {
        const t = setTimeout(() => setStr(target.slice(0, str.length + 1)), typeMs);
        return () => clearTimeout(t);
      }
      const t = setTimeout(() => setPhase("holding"), holdMs);
      return () => clearTimeout(t);
    }
    if (phase === "holding") {
      if (!loop && idx === texts.length - 1) return;
      const t = setTimeout(() => setPhase("erasing"), holdMs);
      return () => clearTimeout(t);
    }
    if (phase === "erasing") {
      if (str.length > 0) {
        const t = setTimeout(() => setStr(str.slice(0, -1)), eraseMs);
        return () => clearTimeout(t);
      }
      setIdx((x) => (x + 1) % texts.length);
      setPhase("typing");
    }
  }, [str, idx, phase, texts, typeMs, holdMs, eraseMs, loop]);

  return str;
}

// Aged, torn-paper edge. Layered: a deep irregular tear path + a fibrous fringe
// of tiny stray fibers + a soft brown shadow under the tear. Side = "top" or "bottom".
function RippedEdge({ side = "bottom", color = "#E8DCC4", height = 36, shadow = "rgba(20,8,12,0.35)" }) {
  const w = 1600;
  const h = height;

  // Stable pseudo-random
  const rnd = (i, k = 1) => {
    const v = Math.sin(i * 12.9898 + k * 78.233) * 43758.5453;
    return v - Math.floor(v);
  };

  // Build a richly irregular tear: many short segments with two scales of jitter
  // (large undulation + tight micro-tears). At each vertex add tiny inward
  // fibers occasionally.
  const segs = 240;
  const verts = [];
  for (let i = 0; i <= segs; i++) {
    const x = (w / segs) * i;
    // Combine sines + noise so the curve breathes irregularly, not periodically
    const macro = Math.sin(i * 0.18) * 0.55 + Math.sin(i * 0.07 + 1.3) * 0.35;
    const micro = (rnd(i, 1) - 0.5) * 0.6 + (rnd(i, 2) - 0.5) * 0.35;
    const yPct = 0.45 + macro * 0.32 + micro * 0.28; // 0..1 range, weighted toward middle
    const y = side === "bottom" ? h - yPct * h : yPct * h;
    verts.push({ x, y });
  }

  // Build path: occasionally jab a small inward fiber notch
  let d = side === "bottom" ? `M0 0 ` : `M0 ${h} `;
  for (let i = 0; i < verts.length; i++) {
    const v = verts[i];
    d += `L${v.x.toFixed(1)} ${v.y.toFixed(1)} `;
    // Occasional fiber notch — small triangular spike inward
    if (rnd(i, 7) > 0.86 && i < verts.length - 1) {
      const next = verts[i + 1];
      const mx = (v.x + next.x) / 2;
      const dir = side === "bottom" ? -1 : 1;
      const spike = (3 + rnd(i, 8) * 6) * dir;
      d += `L${mx.toFixed(1)} ${(v.y + spike).toFixed(1)} `;
    }
  }
  d += side === "bottom" ? `L${w} 0 Z` : `L${w} ${h} Z`;

  // Stray fibers — short ticks dangling beyond the main edge
  const fibers = [];
  for (let i = 0; i < 80; i++) {
    const x = rnd(i, 11) * w;
    const len = 2 + rnd(i, 12) * 7;
    const dir = side === "bottom" ? 1 : -1;
    // anchor near the tear line approximation
    const idx = Math.round((x / w) * segs);
    const yA = verts[Math.min(verts.length - 1, idx)].y;
    const yB = yA + len * dir;
    const xJ = x + (rnd(i, 13) - 0.5) * 1.5;
    fibers.push({ x1: x, y1: yA, x2: xJ, y2: yB, op: 0.3 + rnd(i, 14) * 0.5 });
  }

  return (
    <svg
      viewBox={`0 0 ${w} ${h}`}
      preserveAspectRatio="none"
      style={{
        position: "absolute",
        left: 0, right: 0,
        [side]: -1,
        width: "100%",
        height: h,
        display: "block",
        pointerEvents: "none",
        filter: `drop-shadow(0 ${side === "bottom" ? 4 : -4}px 6px ${shadow})`,
      }}
    >
      <defs>
        <linearGradient id={`tear-grad-${side}-${color.replace(/[^a-z0-9]/gi, "")}`} x1="0" x2="0" y1={side === "bottom" ? "0" : "1"} y2={side === "bottom" ? "1" : "0"}>
          <stop offset="0%" stopColor={color} stopOpacity="1" />
          <stop offset="65%" stopColor={color} stopOpacity="1" />
          <stop offset="100%" stopColor={color} stopOpacity="0.92" />
        </linearGradient>
      </defs>
      <path d={d} fill={color} />
      {/* darker undertone along tear edge — like exposed inner pulp */}
      <path d={d} fill="none" stroke="rgba(80,40,20,0.18)" strokeWidth="1.2" />
      {/* loose fibers */}
      {fibers.map((f, i) => (
        <line key={i} x1={f.x1} y1={f.y1} x2={f.x2} y2={f.y2}
          stroke={color} strokeOpacity={f.op} strokeWidth="0.7" strokeLinecap="round" />
      ))}
    </svg>
  );
}

// Shared placeholder image with a subtle vignette + label fallback
function Img({ src, alt, style, vignette = false }) {
  return (
    <div style={{ position: "relative", overflow: "hidden", ...style }}>
      <img
        src={src}
        alt={alt}
        loading="lazy"
        style={{ width: "100%", height: "100%", objectFit: "cover", display: "block", filter: "saturate(0.9) contrast(1.05)" }}
      />
      {vignette && (
        <div style={{
          position: "absolute", inset: 0,
          background: "radial-gradient(ellipse at center, transparent 30%, rgba(0,0,0,0.55) 100%)",
          pointerEvents: "none",
        }} />
      )}
    </div>
  );
}

Object.assign(window, {
  IMG, SYNONYM_CYCLE, SAMPLE_WORD, SAMPLE_DRAFT, SAMPLE_REWRITE, CRAFT_MOVE,
  useCycler, useTyper, RippedEdge, Img,
});
