/* 11 wrapped — Slide components (class recap) */

// ─── Data ─────────────────────────────────────────────────────────────
const DATA = {
  year: "2025 / 26",
  grade: "11",
  petya: { timesLate: 1_337_420 },
  chairs: { broken: 112 },
  teeth: { given: 254 },
  reza: {
    items: [
      { name: "The Clock", src: "images/reza-1.jpg" },
      { name: "The TV", src: "images/reza-2.jpg" },
      { name: "Arseniy's phone", src: "images/reza-3.jpg" },
    ],
  },
  board: { photoCount: 1456 },
  videoUrl:
    "https://drive.google.com/file/d/18pa9RGi04DCzM4mWNnaaAbRpG948fbC7/view?usp=sharing",
};

// Avatar palette for animations
const AVATAR_PALETTE = [
  {
    face: "linear-gradient(135deg, #ff2e93, #ff6a1f)",
    trail: "rgba(255, 46, 147, 0.6)",
  },
  {
    face: "linear-gradient(135deg, #ffd23f, #e8113a)",
    trail: "rgba(255, 210, 63, 0.55)",
  },
  {
    face: "linear-gradient(135deg, #ffb1c8, #ff2e93)",
    trail: "rgba(255, 177, 200, 0.6)",
  },
  {
    face: "linear-gradient(135deg, #ff6a1f, #ffd23f)",
    trail: "rgba(255, 106, 31, 0.55)",
  },
  {
    face: "linear-gradient(135deg, #e8113a, #14080e)",
    trail: "rgba(232, 17, 58, 0.55)",
  },
];

const CHASE_AVATARS = [
  { name: "Petya" },
  { name: "Reza" },
  { name: "11k" },
  { name: "Class" },
  { name: "Board" },
];

// ─── Animated number counter ──────────────────────────────────────────
function useCounter(target, active, duration = 1600) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    if (!active) {
      setVal(0);
      return;
    }
    let raf;
    const start = performance.now();
    const tick = (now) => {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setVal(Math.round(target * eased));
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, active, duration]);
  return val;
}

const fmt = (n) => n.toLocaleString("en-US");

const Bg = ({ a, b }) => (
  <div className="bg" style={{ "--bg-a": a, "--bg-b": b }} />
);

const A = ({ delay = 0, children, style = {}, className = "", ...rest }) => (
  <div
    className={`anim ${className}`}
    style={{ transitionDelay: `${delay}ms`, ...style }}
    {...rest}
  >
    {children}
  </div>
);

// ─── ChasingAvatars: racing-circles animation ────────────────────────
function ChasingAvatars({
  avatars = CHASE_AVATARS,
  scale = 1,
  top = "50%",
  opacity = 1,
}) {
  return (
    <div className="chase" style={{ top, opacity }}>
      {avatars.slice(0, 5).map((a, i) => {
        const palette = AVATAR_PALETTE[i % AVATAR_PALETTE.length];
        const dur = (6 + i * 0.9) / scale;
        const delay = -i * 1.4;
        const initials = computeInitials(a.name);
        const vOffset = (i % 2 === 0 ? -1 : 1) * (8 + i * 3);
        return (
          <div
            key={a.name + i}
            className="runner"
            style={{
              "--dur": `${dur}s`,
              "--delay": `${delay}s`,
              "--face": palette.face,
              "--trail": palette.trail,
              marginTop: `${vOffset}px`,
              zIndex: 5 - i,
            }}
          >
            <div className="face">{initials}</div>
          </div>
        );
      })}
    </div>
  );
}

function computeInitials(name) {
  const words = String(name || "")
    .split(/\s+/)
    .filter((w) => w && w !== "//" && w !== "·" && w !== "—" && w !== "-");
  if (words.length === 0) return "";
  if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
  return words
    .slice(0, 2)
    .map((w) => w[0])
    .join("")
    .toUpperCase();
}

const RING_PALETTE = ["#ff2e93", "#ffd23f", "#ff6a1f", "#e8113a", "#ffb1c8"];

function shuffleByIdx(arr, seed) {
  const a = [...arr];
  let s = seed;
  for (let i = a.length - 1; i > 0; i--) {
    s = (s * 9301 + 49297) % 233280;
    const j = Math.floor((s / 233280) * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

// ─── FallingChase: ring-trail race animation ──────────────────────────
function FallingChase({
  items,
  totalMs = 15500,
  seed = 11,
  showCards = true,
  shuffle = true,
}) {
  if (!items || !items.length) return null;
  const n = items.length;
  const visual = React.useMemo(() => {
    const ranked = items.map((it, i) => ({ ...it, rank: i + 1 }));
    return shuffle ? shuffleByIdx(ranked, seed + n) : ranked;
  }, [items, seed, n, shuffle]);
  const cols =
    n === 1
      ? [50]
      : Array.from({ length: n }, (_, i) => 10 + i * (80 / (n - 1)));
  const raceMs = Math.max(3000, totalMs - 1800);
  const raceSec = raceMs / 1000;
  const revealStartSec = (raceMs - 200) / 1000;
  const variants = ["v1", "v2", "v3", "v4", "v5"];

  return (
    <div className="falling-tracks">
      {visual.map((item, laneIdx) => {
        const ring = RING_PALETTE[laneIdx % RING_PALETTE.length];
        const face = AVATAR_PALETTE[laneIdx % AVATAR_PALETTE.length].face;
        const variant = variants[laneIdx % variants.length];
        const initials = computeInitials(item.name || item.label || "");
        const isWinner = item.rank === 1;
        // Winner reveals last with extra delay for dramatic effect
        const revealDelay =
          revealStartSec + (n - item.rank) * 0.3 + (isWinner ? 0.3 : 0);
        return (
          <div
            key={laneIdx}
            className={`lane ${variant}`}
            style={{
              "--col": `${cols[laneIdx]}%`,
              "--face": face,
              "--ring": ring,
              "--dur": `${raceSec}s`,
              "--reveal-delay": `${revealDelay}s`,
            }}
          >
            <div className="race-area">
              <div className="trail">
                <div className="head">
                  {item.src ? (
                    <img
                      src={item.src}
                      alt=""
                      style={{
                        width: "100%",
                        height: "100%",
                        objectFit: "cover",
                        borderRadius: "50%",
                        display: "block",
                        pointerEvents: "none",
                      }}
                    />
                  ) : (
                    initials || String(item.rank).padStart(2, "0")
                  )}
                </div>
              </div>
            </div>
            {showCards && (
              <div className={`card${isWinner ? " winner" : ""}`}>
                <div className="card-rank">
                  #{String(item.rank).padStart(2, "0")}
                </div>
                <div className="card-name">{item.name || item.label}</div>
                {item.sub && <div className="card-sub">{item.sub}</div>}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ─── Transitions ──────────────────────────────────────────────────────
function getTransitionItems(slideIdx) {
  return null;
}

function getTransitionMs(slideIdx) {
  return 420;
}

// ─── Slides ───────────────────────────────────────────────────────────

// Update names here:
const CREDITS = [
  { role: "MADE BY", name: "Grade 11K" },
  { role: "DIRECTED BY", name: "Boris (somehow)" },
  { role: "PROGRAMMING", name: "Andrey" },
  { role: "ART DIRECTION", name: "Arseniy" },
  { role: "FURNITURE", name: "dead" },
  { role: "SPECIAL THANKS", name: "Reza, Olga, Grigoriy" },
];

function StarWarsSlide({ active }) {
  const stars = React.useMemo(
    () =>
      Array.from({ length: 130 }, (_, i) => ({
        x: Math.random() * 100,
        y: Math.random() * 100,
        s: Math.random() * 1.8 + 0.4,
        o: 0.3 + Math.random() * 0.7,
      })),
    [],
  );
  return (
    <div className={`slide starwars ${active ? "active" : ""}`}>
      <div className="sw-stars" aria-hidden="true">
        {stars.map((s, i) => (
          <div
            key={i}
            className="sw-star"
            style={{
              left: `${s.x}%`,
              top: `${s.y}%`,
              width: `${s.s}px`,
              height: `${s.s}px`,
              opacity: s.o,
            }}
          />
        ))}
      </div>
      <div className={`sw-crawl-wrap ${active ? "playing" : ""}`}>
        <div className="sw-crawl">
          <div className="sw-crawl-inner">
            <p className="sw-galaxy">In a galaxy, far far away...</p>
            <p className="sw-ep">EPISODE XI</p>
            <p className="sw-title">
              THE GRADE
              <br />
              THAT SURVIVED
            </p>
            <p>
              It is a period of great academic turmoil. The forces of homework,
              mandatory attendance, and teachers who actually check notebooks
              have stretched a generation to its absolute limit.
            </p>
            <p>
              Yet from the chaos emerged something unexpected — a class that
              refused to be broken. Not because they were prepared. Not because
              they studied. But because somehow, against every reasonable
              prediction, they kept showing up.
            </p>
            <p>
              They showed up late. They showed up confused. They showed up
              having clearly not slept. But they showed up.
            </p>
            <p>
              They argued in hallways. They laughed in the wrong moments. They
              made promises with the gravity of treaties and the reliability of
              weather forecasts.
            </p>
            <p>
              There were setbacks. There was furniture. There were diagrams on
              surfaces that had never consented to be diagrams. There were many,
              many moments where the smart move would have been to simply stop.
            </p>
            <p>They did not stop.</p>
            <p>
              Grade 11 threw everything it had at them — the deadlines, the
              exams, the early mornings, the group projects with people who do
              not respond to messages.
            </p>
            <p>And in the end, the grade blinked first.</p>
            <p className="sw-end">They survived. All of them. Somehow.</p>
          </div>
        </div>
      </div>
    </div>
  );
}

function CreditsSlide({ active }) {
  return (
    <div className={`slide credits-slide ${active ? "active" : ""}`}>
      <div className="credits-stars" aria-hidden="true" />
      <div className={`credits-scroll-wrap ${active ? "playing" : ""}`}>
        <div className="credits-scroll">
          <div className="credits-title-block">
            <div className="credits-main-title display">11</div>
            <div className="credits-main-sub italic">wrapped</div>
            <div className="credits-year mono">{DATA.year}</div>
          </div>
          {CREDITS.map((c, i) => (
            <div key={i} className="credit-item">
              <div className="credit-role">{c.role}</div>
              <div className="credit-name">{c.name}</div>
            </div>
          ))}
          <div className="credits-fin">happy graduation.</div>
        </div>
      </div>
    </div>
  );
}

function IntroSlide({ active }) {
  return (
    <div className={`slide intro ${active ? "active" : ""}`}>
      <Bg a="#ff2e93" b="#ff6a1f" />
      <ChasingAvatars top="70%" opacity={0.55} />
      <div className="col stack">
        <A delay={80}>
          <div className="year mono">— {DATA.year} —</div>
        </A>
        <A delay={220}>
          <h1 className="display">
            11
            <span className="wrapped italic">wrapped</span>
          </h1>
        </A>
        <A delay={360}>
          <div
            className="tagline"
            style={{ marginTop: "clamp(8px, 1vh, 14px)" }}
          >
            grade {DATA.grade}, recapped.
          </div>
        </A>
      </div>
    </div>
  );
}

function PetyaLateSlide({ active }) {
  const n = useCounter(DATA.petya.timesLate, active, 2000);
  return (
    <div className={`slide stat-slide petya-late ${active ? "active" : ""}`}>
      <Bg a="#e8113a" b="#ff6a1f" />
      <div className="col">
        <A delay={60}>
          <div className="label">chronic tardiness</div>
        </A>
        <A delay={180}>
          <div className="big display">{fmt(n)}</div>
        </A>
        <A delay={320}>
          <div className="unit display">times petya was late</div>
        </A>
        <A delay={500}>
          <div className="sub">
            still hasn't apologized
            <br />
            for <em>a single one.</em>
          </div>
        </A>
      </div>
    </div>
  );
}

function ChairsBrokenSlide({ active }) {
  const n = useCounter(DATA.chairs.broken, active, 1200);
  return (
    <div className={`slide stat-slide ${active ? "active" : ""}`}>
      <Bg a="#ff6a1f" b="#ffd23f" />
      <div className="col">
        <A delay={60}>
          <div className="label">structural damage</div>
        </A>
        <A delay={180}>
          <div className="big display">{fmt(n)}</div>
        </A>
        <A delay={320}>
          <div className="unit display">chairs broken</div>
        </A>
        <A delay={500}>
          <div className="sub">
            the school owes us
            <br />
            <em>a furniture budget.</em>
          </div>
        </A>
      </div>
    </div>
  );
}

function TeethGivenSlide({ active }) {
  const n = useCounter(DATA.teeth.given, active, 1200);
  return (
    <div className={`slide stat-slide ${active ? "active" : ""}`}>
      <Bg a="#ff2e93" b="#e8113a" />
      <div className="col">
        <A delay={60}>
          <div className="label">sworn promises</div>
        </A>
        <A delay={180}>
          <div className="big display">{fmt(n)}</div>
        </A>
        <A delay={320}>
          <div className="unit display">teeth given</div>
        </A>
        <A delay={500}>
          <div className="sub">
            most of them
            <br />
            <em>still pending.</em>
          </div>
        </A>
      </div>
    </div>
  );
}

const REZA_MS = 15000;

function RezaDrawingsSlide({ active }) {
  return (
    <div className={`slide reza-drawings ${active ? "active" : ""}`}>
      <Bg a="#14080e" b="#ff2e93" />
      {/* Remount on activate to reset animation from the start */}
      {active && (
        <FallingChase
          items={DATA.reza.items}
          totalMs={REZA_MS}
          seed={42}
          showCards={true}
          shuffle={false}
        />
      )}
      <div className="reza-header">
        <A delay={80}>
          <div className="label">reza's art gallery</div>
        </A>
        <A delay={200}>
          <div className="heading display">
            top 3<br />
            <em>surfaces</em>
          </div>
        </A>
      </div>
    </div>
  );
}

function BoardCountSlide({ active }) {
  const n = useCounter(DATA.board.photoCount, active, 1400);
  return (
    <div className={`slide stat-slide ${active ? "active" : ""}`}>
      <Bg a="#14080e" b="#e8113a" />
      <div className="col">
        <A delay={60}>
          <div className="label">archival evidence</div>
        </A>
        <A delay={180}>
          <div className="big display">{fmt(n)}</div>
        </A>
        <A delay={320}>
          <div className="unit display">board photos</div>
        </A>
        <A delay={500}>
          <div className="sub">
            we never missed
            <br />
            <em>a single diagram.</em>
          </div>
        </A>
      </div>
    </div>
  );
}

const CAROUSEL_TOTAL = 8;
const CAROUSEL_MS = 500;

function BoardCarouselSlide({ active }) {
  const [cur, setCur] = React.useState(0);
  React.useEffect(() => {
    if (!active) {
      setCur(0);
      return;
    }
    const t = setInterval(
      () => setCur((i) => (i + 1) % CAROUSEL_TOTAL),
      CAROUSEL_MS,
    );
    return () => clearInterval(t);
  }, [active]);

  return (
    <div className={`slide board-carousel ${active ? "active" : ""}`}>
      <Bg a="#ff2e93" b="#14080e" />
      <div className="col">
        <A delay={60}>
          <div className="label">the board chronicles</div>
        </A>
        <A delay={180}>
          <div className="carousel-stage">
            {Array.from({ length: CAROUSEL_TOTAL }, (_, i) => (
              <div
                key={i}
                className={`carousel-item ${i === cur ? "visible" : ""}`}
              >
                <image-slot
                  id={`board-photo-${i + 1}`}
                  src={`images/board-${i + 1}.jpg`}
                  shape="rounded"
                  radius="12"
                  placeholder={`board photo ${i + 1}`}
                  readonly=""
                  style={{ width: "100%", height: "100%", display: "block" }}
                />
              </div>
            ))}
          </div>
        </A>
        <A delay={280}>
          <div className="carousel-dots">
            {Array.from({ length: CAROUSEL_TOTAL }, (_, i) => (
              <div
                key={i}
                className={`carousel-dot ${i === cur ? "on" : ""}`}
              />
            ))}
          </div>
        </A>
      </div>
    </div>
  );
}

function OutroSlide({ active, onDownload, downloading }) {
  return (
    <div className={`slide outro ${active ? "active" : ""}`}>
      <Bg a="#14080e" b="#e8113a" />
      <div className="col">
        <A delay={60}>
          <div className="label">year in numbers</div>
        </A>
        <A delay={180}>
          <div className="share-card" id="share-card">
            <div className="badge">
              11 wrapped · grade {DATA.grade} · {DATA.year}
            </div>
            <div className="you">
              that was
              <br />
              <em>one year.</em>
            </div>
            <div className="stats">
              <div>
                <div className="stat-key">petya late</div>
                <div className="stat-val">{fmt(DATA.petya.timesLate)}</div>
              </div>
              <div>
                <div className="stat-key">chairs broken</div>
                <div className="stat-val">{DATA.chairs.broken}</div>
              </div>
              <div>
                <div className="stat-key">teeth given</div>
                <div className="stat-val">{DATA.teeth.given}</div>
              </div>
              <div>
                <div className="stat-key">board photos</div>
                <div className="stat-val">{DATA.board.photoCount}</div>
              </div>
            </div>
            <div className="footer">
              <span>grade {DATA.grade}</span>
              <span>·</span>
              <span>{DATA.year}</span>
            </div>
          </div>
        </A>
        <A delay={400}>
          <div className="actions">
            <button
              className="btn btn-primary"
              onClick={onDownload}
              disabled={downloading}
            >
              {downloading ? "embedding fonts…" : "download card"}
            </button>
            <a
              className="btn btn-video"
              href={DATA.videoUrl}
              target="_blank"
              rel="noopener noreferrer"
            >
              watch the video ↗
            </a>
            <button
              className="btn btn-secondary"
              onClick={() => location.reload()}
            >
              replay
            </button>
          </div>
        </A>
      </div>
    </div>
  );
}

// Slide registry
const SLIDES = [
  { id: "starwars", Comp: StarWarsSlide, duration: 90000 },
  { id: "intro", Comp: IntroSlide, duration: 3500 },
  { id: "petya-late", Comp: PetyaLateSlide, duration: 5500 },
  { id: "chairs", Comp: ChairsBrokenSlide, duration: 5000 },
  { id: "teeth", Comp: TeethGivenSlide, duration: 5000 },
  { id: "reza", Comp: RezaDrawingsSlide, duration: 18000 },
  { id: "board-count", Comp: BoardCountSlide, duration: 5000 },
  { id: "board-carousel", Comp: BoardCarouselSlide, duration: 25000 },
  { id: "credits", Comp: CreditsSlide, duration: 28000 },
  { id: "outro", Comp: OutroSlide, duration: 60000 },
];

Object.assign(window, {
  SLIDES,
  DATA,
  CREDITS,
  ChasingAvatars,
  FallingChase,
  getTransitionItems,
  getTransitionMs,
  AVATAR_PALETTE,
  StarWarsSlide,
  IntroSlide,
  PetyaLateSlide,
  ChairsBrokenSlide,
  TeethGivenSlide,
  RezaDrawingsSlide,
  BoardCountSlide,
  BoardCarouselSlide,
  CreditsSlide,
  OutroSlide,
});
