/* global React */
const { useState, useEffect, useRef, useMemo } = React;

// ============= coordinate strip header =============
function CpCoord({ frame, id, status = "PRE-INTAKE" }) {
  return (
    <div className="cp-coord">
      <span className="cc-frame">DOGPATCH · DUBLIN</span>
      <span>//</span>
      <span className="cc-id">FN26.COMPETE.{id}</span>
      <span className="cc-bar"></span>
      <span>{frame}</span>
      <span>·</span>
      <span className="cc-status">▸ {status}</span>
    </div>
  );
}

// ============= 01 · HERO + REGISTER (combined) ===========
function CpHookCAD() {
  return (
    <svg className="cp-hook-cad" viewBox="0 0 1600 700" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
      <defs>
        <pattern id="cad-grid" width="40" height="40" patternUnits="userSpaceOnUse">
          <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#FF6A1A" strokeWidth="0.4" opacity="0.18"/>
        </pattern>
        <pattern id="cad-grid-fine" width="8" height="8" patternUnits="userSpaceOnUse">
          <path d="M 8 0 L 0 0 0 8" fill="none" stroke="#FF6A1A" strokeWidth="0.2" opacity="0.06"/>
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#cad-grid-fine)"/>
      <rect width="100%" height="100%" fill="url(#cad-grid)"/>
      <g stroke="#FF6A1A" fill="none" strokeWidth="0.8" opacity="0.55">
        <g transform="translate(220 480)">
          <polygon points="-60,-25 -25,-60 25,-60 60,-25 60,25 25,60 -25,60 -60,25"/>
          <circle cx="0" cy="0" r="38"/>
          <circle cx="0" cy="0" r="6"/>
          <line x1="-60" y1="0" x2="60" y2="0" strokeDasharray="3 3"/>
          <line x1="0" y1="-60" x2="0" y2="60" strokeDasharray="3 3"/>
          <line x1="-60" y1="80" x2="60" y2="80"/>
          <line x1="-60" y1="76" x2="-60" y2="84"/>
          <line x1="60" y1="76" x2="60" y2="84"/>
        </g>
        <g transform="translate(820 200)">
          <rect x="-100" y="-60" width="200" height="120"/>
          <rect x="-80" y="-40" width="160" height="80" strokeDasharray="2 4"/>
          <line x1="-100" y1="-60" x2="-160" y2="-100"/>
          <line x1="100" y1="-60" x2="160" y2="-100"/>
          <line x1="-100" y1="60" x2="-160" y2="100"/>
          <line x1="100" y1="60" x2="160" y2="100"/>
          <circle cx="-100" cy="-60" r="3"/>
          <circle cx="100" cy="-60" r="3"/>
          <circle cx="-100" cy="60" r="3"/>
          <circle cx="100" cy="60" r="3"/>
        </g>
        <g transform="translate(1340 540)" opacity="0.7">
          <line x1="-160" y1="-40" x2="160" y2="-40"/>
          <line x1="-160" y1="40" x2="160" y2="40"/>
          <line x1="-160" y1="-40" x2="-160" y2="40"/>
          <line x1="160" y1="-40" x2="160" y2="40"/>
          {[-120, -60, 0, 60, 120].map((x, i) => (
            <g key={i}>
              <circle cx={x} cy="-40" r="4"/>
              <circle cx={x} cy="40" r="4"/>
              <line x1={x} y1="-40" x2={x} y2="40" strokeDasharray="2 4" opacity="0.5"/>
            </g>
          ))}
        </g>
      </g>
    </svg>
  );
}

// Cycling hero gallery — combat/build-focused selection. Crossfade handled by
// `.hero-img-bg-img--cycle` (opacity 1.2s ease, honors prefers-reduced-motion).
const CP_HOOK_SLIDES = [
  "assets/photo-chainsaw.png",
  "assets/photo-bot-eyes.png",
  "assets/photo-smoke.png",
  "assets/photo-arena-overview.png",
  "assets/photo-controller-2.png",
];
const CP_HOOK_SLIDE_MS = 4500;

function CpHook() {
  const [active, setActive] = useState(0);
  useEffect(() => {
    const id = setInterval(() => {
      setActive((a) => (a + 1) % CP_HOOK_SLIDES.length);
    }, CP_HOOK_SLIDE_MS);
    return () => clearInterval(id);
  }, []);

  return (
    <section className="cp-hook" data-cp-id="01" data-screen-label="01 Compete · Hero">
      <div className="hero-img-bg" aria-hidden="true">
        {CP_HOOK_SLIDES.map((src, i) => (
          <div
            key={src}
            className="hero-img-bg-img hero-img-bg-img--cycle"
            style={{ backgroundImage: `url('${src}')`, opacity: i === active ? 1 : 0 }}
          ></div>
        ))}
        <div className="hero-img-bg-vignette"></div>
        <div className="hero-img-bg-scan"></div>
        <div className="hero-img-bg-grid"></div>
      </div>
      <CpCoord frame="FRAME 0001" id="0001" />
      <CpHookCAD />
      <div className="cp-hook-content cp-hook-stack">
        <h1>
          <span className="line">Get ready</span>
          <span className="accent">to rumble.</span>
        </h1>
        <p className="cp-hook-sub">
          <span className="lb-lede-em">Five-hundred euro, eight weeks, <span className="lb-lede-mark">one night.</span></span> Sign up, form a team, and spend your summer building a robot, we'll cover all your costs, and provide mentorship along the way. <span className="lb-lede-em">The only thing it costs is your time.</span> We'll meet Every Saturday, at Dogpatch Labs to build, test, and enforce deadlines. If you think you have what it takes, then<span className="lb-lede-em"> come put your skills to the test.</span>
        </p>
        <div className="cp-hook-cta">
          <window.HeroNotifyField />
        </div>
      </div>
    </section>
  );
}

// ============= 01b · WHAT YOU'RE SIGNING UP FOR =============================
// Plain-language overview for cold-start readers: three concrete commitments
// (money, time, mentorship) presented as headline-impact cards, followed by a
// standalone "competition starts day 1" image-block that reframes the offer
// as a dual-championship contest (Fight Night = race, weekly build = constructors).

// Scramble-in helper: matches the count-up reveal feel for non-numeric headline
// values. Cycles random A-Z chars, locks them left-to-right with the same
// ease-out cubic the CountUp uses, fires once on first viewport entry.
const SCRAMBLE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
function ScrambleText({ to, ms = 1100 }) {
  const [text, setText] = useState(() =>
    Array.from({ length: to.length }, () =>
      SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)]
    ).join("")
  );
  const seenRef = useRef(false);
  const ref = useRef(null);

  useEffect(() => {
    if (!ref.current) return;
    const reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduced) {
      setText(to);
      return;
    }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !seenRef.current) {
          seenRef.current = true;
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - start) / ms);
            const eased = 1 - Math.pow(1 - p, 3);
            const lockUpTo = Math.floor(eased * to.length);
            let next = "";
            for (let i = 0; i < to.length; i++) {
              next += i < lockUpTo
                ? to[i]
                : SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)];
            }
            setText(next);
            if (p < 1) requestAnimationFrame(tick);
            else setText(to);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [to, ms]);

  return <span ref={ref}>{text}</span>;
}

const MIGHT_CARDS = [
  {
    num: "01",
    tag: "PER TEAM",
    prefix: "€",
    count: 500,
    after: ".",
    body: "We'll full reimburse any parts, tools, & gear by the end of the competion,",
    img: "assets/photo-bot-blue.png",
  },
  {
    num: "02",
    tag: "BUILD WINDOW",
    count: 8,
    after: " WEEKS.",
    body: "Building & testing at Dogpatch Labs from July 5th to September 5th.",
    img: "assets/bring-space.jpg",
  },
  {
    num: "03",
    tag: "ON-SITE",
    scramble: "MENTORS",
    after: ".",
    body: "Engineers, Patch Allumni, & Fellow nerds. Available in person, or online at 1am.",
    img: "assets/bring-mentorship.jpg",
  },
];

function CpDayOne() {
  return (
    <div className="cp-day-one">
      <div className="cp-day-one-bg" aria-hidden="true"></div>
      <div className="cp-day-one-veil" aria-hidden="true"></div>
      <span className="cp-day-one-corner tl" aria-hidden="true"></span>
      <span className="cp-day-one-corner br" aria-hidden="true"></span>

      <div className="cp-day-one-content">
        <span className="cp-day-one-eyebrow">▸ CONSTRUCTORS' CHAMPIONSHIP</span>
        <h3 className="cp-day-one-title">
          COMPETITION STARTS <span className="accent">DAY 1.</span>
        </h3>
        <p className="cp-day-one-body">
          Building robots takes time. Building good robots takes longer.
          We will be pitting you against eachother and lighting a fire 
          under you to get things over the line.
        </p>
        <p className="cp-day-one-body">
          Hit weekly goals on time, on budget, with a repairable design 
          and you'll enter the arena with points on the board and bonuses
          you can use during your fights.
        </p>
        <div className="cp-day-one-register">
          <div className="cp-day-one-tl">
            <span className="cp-day-one-tl-date"><span className="k">KICKOFF</span> 05 JUL 2026</span>
            <span className="cp-day-one-tl-arrow" aria-hidden="true">→</span>
            <span className="cp-day-one-tl-date"><span className="k">FIGHT NIGHT</span> 05 SEP 2026</span>
          </div>
          <window.HeroNotifyField />
        </div>
      </div>
    </div>
  );
}

function CpMight() {
  return (
    <section className="cp-section cp-might-section" data-cp-id="01b" data-screen-label="01b Compete · What You're Signing Up For">
      <div className="cp-might-head">
        <span className="cp-might-eyebrow">▸ §01 · WHAT YOU'RE SIGNING UP FOR</span>
        <h2 className="cp-sec-title">PROVE YOUR <span className="accent">MIGHT.</span></h2>
        <p className="cp-might-lede">
          Three things from us. Eight Saturdays from you. By <strong>05 Sep 2026</strong>,
          your bot's in an arena at Dogpatch Labs in front of a packed crowd.
        </p>
      </div>

      <div className="cp-might-grid">
        {MIGHT_CARDS.map((c) => (
          <div key={c.num} className="cp-might-card">
            <div className="hero-img-bg" aria-hidden="true">
              <div
                className="hero-img-bg-img cp-might-card-bg"
                style={{ backgroundImage: `url('${c.img}')` }}
              ></div>
              <div className="hero-img-bg-vignette"></div>
              <div className="hero-img-bg-scan"></div>
            </div>
            <div className="cp-might-card-content">
              <div className="cp-might-card-stamps">
                <span className="cp-might-card-num">▸ {c.num}</span>
                <span className="cp-might-card-tag">{c.tag}</span>
              </div>
              <h3 className="cp-might-card-title">
                {c.prefix}
                {c.count != null && (
                  <span className="accent"><window.CountUp to={c.count} /></span>
                )}
                {c.scramble && (
                  <span className="accent"><ScrambleText to={c.scramble} /></span>
                )}
                {c.after}
              </h3>
              <p className="cp-might-card-body">{c.body}</p>
            </div>
          </div>
        ))}
      </div>

      <CpDayOne />
    </section>
  );
}

// ============= 03 · EXPECTATIONS (replaces old WE PROVIDE / YOU BRING) ====
// What we expect from contestants — five non-negotiables, each with a
// custom mechanical/techy SVG icon.  Section is its own thing, with an
// in-section CTA that scrolls to the bottom register form.
const EXPECTATIONS = [
  {
    n: "01",
    title: "SKILLS",
    icon: "chip",
    body: "at least one of: CAD, Electronics, Programming, RC/RF Projects.",
    note: "you don't need to be an engineer, but every team needs a baseline of hands-on competence in each of these areas.",
  },
  {
    n: "02",
    title: "TIME",
    icon: "hourglass",
    body: "8 hrs / week, every week, for 8 weeks.",
    note: "Saturdays in dogpatch should be treated mandatory, we're expecting you to be working on your bot regularly throughout the week.",
  },
  {
    n: "03",
    title: "TOOLS",
    icon: "multimeter",
    body: "Be prepared to use your own tools & offer them to others.",
    note: "3D Printers, soldering irons, multimeters, we will try to cover what we can, but the budget is for bots, not tools.",
  },
  {
    n: "04",
    title: "CONSISTENCY",
    icon: "pulse",
    body: "Hit weekly checkpoints, with safe & repairable designs.",
    note: "If you start missing deadlines or falling behind, at best your team will earn a handicap on fight night, at worst your won't compete. No extensions.",
  },
  {
    n: "05",
    title: "TEAMWORK",
    icon: "gears",
    body: "4–6 people, balanced across mech, elec, ops.",
    note: "Share tools. Share notes. Share blame. Share the load. Not just with your team but with other teams aswell. We have zero tolerence on this.",
  },
];

function ExpectIcon({ name }) {
  const TEETH = [0, 45, 90, 135, 180, 225, 270, 315];
  const gearTeeth = (cx, cy, r1, r2, sw, prefix) =>
    TEETH.map((deg) => {
      const a = (deg * Math.PI) / 180;
      return (
        <line
          key={`${prefix}-${deg}`}
          x1={cx + Math.cos(a) * r1}
          y1={cy + Math.sin(a) * r1}
          x2={cx + Math.cos(a) * r2}
          y2={cy + Math.sin(a) * r2}
          strokeWidth={sw}
        />
      );
    });

  const paths = {
    chip: (
      <g fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <rect x="20" y="20" width="40" height="40" rx="1" />
        <circle cx="26" cy="26" r="2" fill="currentColor" stroke="none" />
        <line x1="28" y1="14" x2="28" y2="20" />
        <line x1="36" y1="14" x2="36" y2="20" />
        <line x1="44" y1="14" x2="44" y2="20" />
        <line x1="52" y1="14" x2="52" y2="20" />
        <line x1="28" y1="60" x2="28" y2="66" />
        <line x1="36" y1="60" x2="36" y2="66" />
        <line x1="44" y1="60" x2="44" y2="66" />
        <line x1="52" y1="60" x2="52" y2="66" />
        <line x1="14" y1="28" x2="20" y2="28" />
        <line x1="14" y1="36" x2="20" y2="36" />
        <line x1="14" y1="44" x2="20" y2="44" />
        <line x1="14" y1="52" x2="20" y2="52" />
        <line x1="60" y1="28" x2="66" y2="28" />
        <line x1="60" y1="36" x2="66" y2="36" />
        <line x1="60" y1="44" x2="66" y2="44" />
        <line x1="60" y1="52" x2="66" y2="52" />
        <line x1="32" y1="32" x2="48" y2="32" opacity="0.55" />
        <line x1="32" y1="48" x2="48" y2="48" opacity="0.55" />
        <circle cx="40" cy="40" r="3.5" />
      </g>
    ),
    multimeter: (
      <g fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <rect x="18" y="14" width="44" height="44" rx="2" />
        <rect x="24" y="20" width="32" height="14" />
        <line x1="28" y1="27" x2="32" y2="27" strokeWidth="2.5" />
        <line x1="35" y1="25" x2="35" y2="29" strokeWidth="3" />
        <line x1="38" y1="27" x2="42" y2="27" strokeWidth="2.5" />
        <line x1="46" y1="27" x2="50" y2="27" strokeWidth="2.5" />
        <circle cx="40" cy="46" r="8" />
        <line x1="40" y1="46" x2="40" y2="40" strokeWidth="2.5" />
        <circle cx="28" cy="56" r="2" fill="currentColor" stroke="none" />
        <circle cx="40" cy="56" r="2" fill="currentColor" stroke="none" />
        <circle cx="52" cy="56" r="2" fill="currentColor" stroke="none" />
        <path d="M 28 60 Q 22 64 18 70" strokeWidth="1.5" />
        <path d="M 52 60 Q 58 64 62 70" strokeWidth="1.5" />
      </g>
    ),
    hourglass: (
      <g fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <line x1="20" y1="14" x2="60" y2="14" />
        <line x1="20" y1="66" x2="60" y2="66" />
        <path d="M 26 14 L 54 14 L 40 40 Z" />
        <path d="M 26 66 L 54 66 L 40 40 Z" />
        <path d="M 32 22 L 48 22 L 40 35 Z" fill="currentColor" stroke="none" opacity="0.7" />
        <line x1="40" y1="36" x2="40" y2="44" strokeWidth="1.6" />
        <path d="M 32 60 L 48 60 L 44 50 L 36 50 Z" fill="currentColor" stroke="none" opacity="0.55" />
      </g>
    ),
    pulse: (
      <g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round">
        <line x1="14" y1="40" x2="66" y2="40" strokeWidth="0.6" opacity="0.3" strokeDasharray="2 4" />
        <path d="M 14 40 L 22 40 L 26 30 L 32 50 L 36 22 L 42 56 L 48 32 L 54 40 L 66 40" strokeWidth="2.4" />
        <circle cx="48" cy="32" r="2.2" fill="currentColor" stroke="none" />
        <line x1="14" y1="14" x2="14" y2="18" strokeWidth="1" />
        <line x1="34" y1="14" x2="34" y2="17" strokeWidth="1" opacity="0.6" />
        <line x1="54" y1="14" x2="54" y2="18" strokeWidth="1" />
        <line x1="14" y1="62" x2="14" y2="66" strokeWidth="1" />
        <line x1="34" y1="63" x2="34" y2="66" strokeWidth="1" opacity="0.6" />
        <line x1="54" y1="62" x2="54" y2="66" strokeWidth="1" />
      </g>
    ),
    gears: (
      <g fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <circle cx="40" cy="22" r="9" />
        <circle cx="40" cy="22" r="3" />
        {gearTeeth(40, 22, 9, 13, 3, "g1")}
        <circle cx="22" cy="50" r="8" />
        <circle cx="22" cy="50" r="2.5" />
        {gearTeeth(22, 50, 8, 12, 2.5, "g2")}
        <circle cx="58" cy="50" r="8" />
        <circle cx="58" cy="50" r="2.5" />
        {gearTeeth(58, 50, 8, 12, 2.5, "g3")}
      </g>
    ),
  };

  return (
    <svg className="cp-expect-icon" viewBox="0 0 80 80" aria-hidden="true">
      {paths[name]}
    </svg>
  );
}

function CpExpectations() {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setInView(true);
          obs.disconnect();
        }
      });
    }, { threshold: 0.18 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);

  return (
    <section className="cp-section cp-expect-section" data-cp-id="03" data-screen-label="03 Compete · Expectations">
      <div className="cp-expect-head">
        <div className="cp-expect-head-l">
          <span className="cp-expect-eyebrow">▸ FIG. 03 · CONTESTANT CHECKLIST</span>
          <h2 className="cp-sec-title">
            WHAT WE<br />
            <span className="accent">EXPECT.</span>
          </h2>
        </div>
        <p className="cp-expect-lede">
          We can only help to amplify the efforts that you put in. Last year, hundreds of people applied to be a part of Robowars. It was a really tough choice but ultimately it came down to the following.
        </p>
      </div>

      <div ref={ref} className={`cp-expect-grid${inView ? " is-in" : ""}`}>
        {EXPECTATIONS.map((e) => (
          <article key={e.n} className="cp-expect-card">
            <span className="cp-expect-card-num">▸ {e.n} <span className="of">/ 05</span></span>
            <ExpectIcon name={e.icon} />
            <h3 className="cp-expect-card-title">{e.title}</h3>
            <p className="cp-expect-card-body">{e.body}</p>
            <p className="cp-expect-card-note">{e.note}</p>
          </article>
        ))}
      </div>
    </section>
  );
}

// ===== EXPORT =====
Object.assign(window, {
  CpCoord, CpHook, CpMight, CpExpectations,
});
