// components.jsx — all RNZAF Avionics Reunion site components

const Header = () => (
  <header className="rar-header">
    <div className="rar-header__inner">
      <a className="rar-header__brand" href="#top">
        <img src="assets/AV-Reunion-2018-Logo.png" alt="RNZAF Avionics Reunion crest" />
        <div className="rar-header__brand-text">
          <span className="rar-eyebrow">Wigram - 1938 - 2026</span>
          <strong>RNZAF Avionics Reunion</strong>
        </div>
      </a>
      <nav className="rar-header__nav">
        <a href="#reunion">2026 Update</a>
        <a href="#history">History</a>
        <a href="#gallery">Photos</a>
        <a href="#past">Past Events</a>
        <a href="#links">Links</a>
        <a href="#contact" className="rar-header__cta">
          Contact Us
        </a>
      </nav>
    </div>
    <div className="rar-rule-roundel" />
  </header>
);

const slugify = (s = "") =>
  s
    .toString()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");

const Sidebar = () => {
  const chapters = typeof CHAPTERS !== "undefined" ? CHAPTERS : [];
  return (
    <aside className="rar-sidebar" aria-label="Primary navigation">
      <nav>
        <a href="#reunion" data-target="reunion" className="dial-item">
          <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path
              fill="currentColor"
              d="M12 2a1 1 0 0 1 1 1v3a1 1 0 0 1-2 0V3a1 1 0 0 1 1-1zm4.22 2.03a1 1 0 0 1 1.41 0l2.12 2.12a1 1 0 0 1-1.41 1.41L16.22 5.44a1 1 0 0 1 0-1.41zM21 11a1 1 0 0 1 1 1v0a1 1 0 0 1-1 1h-3a1 1 0 0 1 0-2h3zM6.34 4.12a1 1 0 0 1 0 1.41L4.22 9.65A1 1 0 0 1 2.81 8.24L4.93 6.12a1 1 0 0 1 1.41 0zM3 11a1 1 0 0 1 1-1h3a1 1 0 1 1 0 2H4a1 1 0 0 1-1-1z"
            />
          </svg>
          <span className="label">2026 Update</span>
        </a>

        <div className="rar-sidebar__group">
          <a href="#history" data-target="history" className="rar-sidebar__parent dial-item">
            <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
              <path fill="currentColor" d="M3 5a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v12l-4-2-4 2-4-2V5z" />
            </svg>
            <span className="label">History</span>
          </a>
          <div className="rar-sidebar__submenu">
            {chapters.map((c, i) => (
              <a
                key={i}
                href={`#chapter-${i}`}
                data-target={`chapter-${i}`}
                className="rar-sidebar__subitem"
              >
                <svg className="icon" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
                  <circle cx="12" cy="12" r="2" fill="currentColor" />
                </svg>
                <span className="label">{c.title}</span>
              </a>
            ))}
          </div>
        </div>

        <a href="#gallery" data-target="gallery" className="dial-item">
          <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path
              fill="currentColor"
              d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14h18zM8 11l2.5 3 3.5-4.5L18 17H6l2-6z"
            />
          </svg>
          <span className="label">Photos</span>
        </a>

        <a href="#past" data-target="past" className="dial-item">
          <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path fill="currentColor" d="M12 8V4l6 6-6 6v-4H6V8h6z" />
          </svg>
          <span className="label">Past Events</span>
        </a>

        <a href="#contact" data-target="contact" className="dial-item">
          <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path fill="currentColor" d="M2 4v16h20V4H2zm2 2h16v2l-8 5-8-5V6z" />
          </svg>
          <span className="label">Contact Us</span>
        </a>

        <a href="#links" data-target="links" className="dial-item">
          <svg className="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path
              fill="currentColor"
              d="M3.9 12a5 5 0 0 1 0-7.07l1.41-1.41A5 5 0 0 1 12 3.9L10.59 5.3A3 3 0 0 0 6.7 5.3L3.9 8.12A3 3 0 0 0 3.9 12zM20.1 12a5 5 0 0 1 0 7.07l-1.41 1.41A5 5 0 0 1 12 20.1l1.41-1.41a3 3 0 0 0 4.89 0l2.8-2.82A3 3 0 0 0 20.1 12zM8.59 15.41L15.41 8.59"
            />
          </svg>
          <span className="label">Links</span>
        </a>
      </nav>
    </aside>
  );
};

const Hero = ({ onContact }) => (
  <section className="rar-hero" id="top" data-screen-label="01 Hero">
    <div className="rar-hero__photo" />
    <div className="rar-hero__veil" />
    <div className="rar-hero__inner">
      <div className="rar-hero__left">
        <div className="rar-hero__lockup">
          <span className="rar-hero__lockup-stripe" />
          <span className="rar-eyebrow rar-eyebrow--light">
            Royal New Zealand Air Force &middot; Avionics Trades
          </span>
        </div>
        <h1>
          The Avionics
          <br />
          Trades <span className="accent">Reunion</span>.
        </h1>
        <p className="rar-hero__caption">
          Fifty years on from the 1976 amalgamation, former and serving members of the Electrical,
          Instrument, Radio, Radar and Avionics trades.
        </p>
        <div className="rar-hero__meta">
          <span style={{ color: "var(--airforce-sky)" }}>The 2026 reunion has been cancelled.</span>
        </div>
        <div className="rar-hero__cta-row">
          <a
            href="#contact"
            className="rar-btn rar-btn--alert"
            onClick={(e) => {
              e.preventDefault();
              onContact();
            }}
          >
            Contact Us <span className="arrow">&rarr;</span>
          </a>
          <a href="#history" className="rar-btn rar-btn--outline">
            Read the History
          </a>
        </div>
      </div>
      <div className="rar-hero__right">
        <img className="rar-hero__mark" src="assets/AV-Reunion-2018-Logo.png" alt="" />
        <div className="rar-hero__plaque">
          <div className="rar-hero__plaque-years">1938 &mdash; 2026</div>
          <div className="rar-hero__plaque-sub">Eighty-eight years of service</div>
        </div>
      </div>
    </div>
    <figcaption className="rar-hero__credit">
      RNZAF Harvard line-up &middot; Wigram tarmac, archival
    </figcaption>
  </section>
);

const AnnouncementPanel = ({ onContact }) => (
  <section className="rar-announce" id="reunion" data-screen-label="02 Reunion 2026">
    <div className="rar-announce__year">2026</div>
    <div>
      <p className="rar-eyebrow rar-eyebrow--alert">Cancelled</p>
      <h3 className="rar-announce__title">Reunion Cancelled</h3>
      <p className="rar-announce__body">
        The 2026 RNZAF Avionics Trades Reunion has been cancelled. We thank everyone who expressed
        interest. Please get in touch with the committee if you have any questions.
      </p>
    </div>
    <div className="rar-announce__cta">
      <span className="rar-announce__date">Christchurch &middot; 2026</span>
      <button className="rar-btn rar-btn--alert" onClick={onContact}>
        Contact Us <span className="arrow">&rarr;</span>
      </button>
    </div>
  </section>
);

const StatsStrip = () => {
  const STATS = [
    {
      num: "5,290",
      label: "Airmen Trained",
      desc: "Across 288 wireless and radar courses run through WW2.",
    },
    {
      num: "88",
      unit: "yrs",
      label: "Of Avionics Training",
      desc: "From the Electrical & Wireless School, 4 January 1938.",
    },
    {
      num: "5",
      unit: "→ 1",
      label: "Trades Amalgamated",
      desc: "Electrical, Instrument, Ground Radio, Air Radio and Radar Fitters.",
    },
    {
      num: "50",
      unit: "yrs",
      label: "Since Amalgamation",
      desc: "The September 1976 restructure that defined today's trade.",
    },
  ];
  return (
    <div className="rar-stats-wrap">
      <div className="rar-stats">
        {STATS.map((s, i) => (
          <div className="rar-stat" key={i}>
            <div className="rar-stat__num">
              {s.num}
              {s.unit && <span className="unit">{s.unit}</span>}
            </div>
            <div className="rar-stat__label">{s.label}</div>
            <p className="rar-stat__desc">{s.desc}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

const Chapter = ({ eyebrow, title, year, place, lead, body, figure, id }) => (
  <article className="rar-chapter" id={id}>
    <header className="rar-chapter__head">
      <p className="rar-eyebrow">{eyebrow}</p>
      <h3>{title}</h3>
      <div className="rar-chapter__meta">
        {year && <span>{year}</span>}
        {year && place && <span className="rar-sep" />}
        {place && <span>{place}</span>}
      </div>
    </header>
    {lead && <p className="rar-chapter__lead">{lead}</p>}
    {body && body.map((para, i) => <p key={i}>{para}</p>)}
    {figure && (
      <figure className="rar-chapter__figure">
        <img src={figure.src} alt={figure.alt} />
        <figcaption className="rar-chapter__caption">{figure.caption}</figcaption>
      </figure>
    )}
    <a href="history.html" className="rar-btn rar-btn--ghost rar-btn--small">
      Read more <span className="arrow">&rarr;</span>
    </a>
  </article>
);

const PullQuote = ({ text, attr }) => (
  <blockquote className="rar-pullquote">
    <p className="rar-pullquote__text">{text}</p>
    <div className="rar-pullquote__attr">
      <span className="rar-pullquote__attr-stripe" />
      <span>{attr}</span>
    </div>
  </blockquote>
);

const Gallery = () => {
  const ITEMS = [
    {
      src: "assets/photos/wigram-01.jpg",
      year: "c.1960s",
      label: "Harvard line-up, Wigram tarmac",
      span: "span-c-6 span-r-2",
    },
    {
      src: "assets/photos/CombinedFitters76.jpg",
      year: "Dec 1976",
      label: "Combined Fitters Course — last of the Fitters",
      span: "span-c-6",
    },
    {
      src: "assets/photos/2ttsStaff78.jpg",
      year: "1978",
      label: "2TTS staff, Wigram",
      span: "span-c-3",
    },
    {
      src: "assets/photos/1960-bristol-NZ5907.jpg",
      year: "1960",
      label: "Bristol Freighter NZ5907 in flight",
      span: "span-c-3",
    },
    {
      src: "assets/photos/wigram-03.jpg",
      year: "1950s",
      label: "Tiger Moth servicing, Wigram",
      span: "span-c-4",
    },
    {
      src: "assets/photos/wigram-07.jpg",
      year: "1980s",
      label: "Skyhawk on display, open day",
      span: "span-c-4",
    },
    {
      src: "assets/photos/wigram-05.jpg",
      year: "1950s",
      label: "P2 Neptune on the line",
      span: "span-c-4",
    },
  ];
  return (
    <div className="rar-gallery-wrap" id="gallery" data-screen-label="05 Gallery">
      <div className="rar-gallery">
        <div className="rar-section__heading">
          <span className="rar-eyebrow">Photo Archive</span>
          <h2>From the Reunion Albums</h2>
          <p>
            A small selection from the 2002 and 2018 reunion archives and the Air Force Museum
            collection. Hover an image for caption details.
          </p>
        </div>
        {ITEMS.map((it, i) => (
          <div className={`rar-gallery__item ${it.span}`} key={i}>
            <img src={it.src} alt={it.label} loading="lazy" />
            <div className="rar-gallery__caption">
              <span className="yr">{it.year}</span>
              <span>{it.label}</span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

const PastReunions = () => {
  const PAST = [
    {
      year: "2002",
      title: "Auckland Reunion",
      where: "Auckland &middot; 15-17 March 2002",
      tag: "First combined Avionics reunion",
      body: "The first large gathering of the amalgamated Avionics trade — held in Auckland over three days. Friday night venue was the old 3 Sqn hangar at Hobsonville, and the Saturday night function was held at the Alexandra racecourse. Over 500 attended; more than four hundred training course photographs were collected.",
      img: "assets/photos/wigram-10.jpg",
    },
    {
      year: "2018",
      title: "80th Anniversary",
      where: "Air Force Museum &middot; Wigram",
      tag: "1938 &mdash; 2018",
      body: "Held on Friday 23rd and Saturday 24th March 2018 to mark eighty years since the founding of the Electrical and Wireless School. The 80th-anniversary mark, designed for that reunion, is still in use today.",
      img: "assets/photos/wigram-12.png",
    },
  ];
  return (
    <section className="rar-section rar-section--wide" id="past" data-screen-label="06 Past">
      <div className="rar-section__heading">
        <span className="rar-eyebrow">Service Record &middot; Past Reunions</span>
        <h2>Previous Gatherings</h2>
        <p>
          Earlier reunions have been the seed of the collection now preserved in the photo archive.
        </p>
      </div>
      <div className="rar-past-list">
        {PAST.map((p) => (
          <article className="rar-past" key={p.year}>
            <div className="rar-past__photo">
              <img src={p.img} alt={`${p.year} reunion — ${p.title}`} />
              <div className="rar-past__year-stamp">{p.year}</div>
            </div>
            <div className="rar-past__body">
              <div className="rar-past__meta">
                <span dangerouslySetInnerHTML={{ __html: p.where }} />
              </div>
              <h3>{p.title}</h3>
              <p>{p.body}</p>
              <span className="rar-past__tag" dangerouslySetInnerHTML={{ __html: p.tag }} />
            </div>
          </article>
        ))}
      </div>
      <div className="rar-past-timeline">
        <span className="yr-past">2002 &middot; Auckland</span>
        <span className="line" />
        <span className="yr-past">2018 &middot; 80 Years</span>
        <span className="line" />
        <span className="yr-now">2026 &middot; Cancelled</span>
      </div>
    </section>
  );
};

const ContactForm = () => {
  const [submitted, setSubmitted] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const [serverError, setServerError] = React.useState("");
  const [name, setName] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [message, setMessage] = React.useState("");
  const [errors, setErrors] = React.useState({});

  const validate = () => {
    const e = {};
    if (!name.trim()) e.name = "Name is required";
    if (!email.trim()) {
      e.email = "Email is required";
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
      e.email = "Please enter a valid email address";
    }
    if (!message.trim()) e.message = "Message is required";
    return e;
  };

  const handle = async (e) => {
    e.preventDefault();
    setServerError("");
    const errs = validate();
    if (Object.keys(errs).length) {
      setErrors(errs);
      return;
    }
    setErrors({});
    setLoading(true);
    try {
      const res = await fetch("https://formsubmit.co/ajax/contact@rnzafavionicsreunion.co.nz", {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify({
          name,
          email,
          message,
          _subject: "RNZAF Avionics Reunion — Contact from " + name,
        }),
      });
      const data = await res.json();
      if (data.success === "true" || data.success === true) {
        setSubmitted(true);
      } else {
        setServerError("Something went wrong. Please try again or email us directly.");
      }
    } catch {
      setServerError("Could not send message. Please email us directly.");
    } finally {
      setLoading(false);
    }
  };

  if (submitted) {
    return (
      <section
        className="rar-register rar-register--done"
        id="contact"
        data-screen-label="07 Contact"
      >
        <p>
          <div className="rar-check">&#10003;</div>
        </p>
        <p className="rar-eyebrow">Message received</p>
        <h3>Thank you, {name || "there"}.</h3>
        <p>Your message has been sent to the committee.</p>
        <button
          className="rar-btn rar-btn--ghost"
          onClick={() => {
            setSubmitted(false);
            setName("");
            setEmail("");
            setMessage("");
          }}
        >
          &larr; Send another
        </button>
      </section>
    );
  }

  return (
    <section className="rar-register" id="contact" data-screen-label="07 Contact">
      <header className="rar-register__head">
        <p className="rar-eyebrow">Get in touch</p>
        <h3>Contact the Committee</h3>
        <p className="rar-register__sub">
          For any questions about the reunion or the association, send a message using the form
          below
          {/* or email us directly at{" "}
          <a href="mailto:contact@rnzafavionicsreunion.co.nz">contact@rnzafavionicsreunion.co.nz</a> */}
          .
        </p>
      </header>
      <form className="rar-form" onSubmit={handle} noValidate>
        <label className={`rar-field${errors.name ? " rar-field--error" : ""}`}>
          <span>Full name</span>
          <input
            value={name}
            onChange={(e) => {
              setName(e.target.value);
              setErrors((prev) => ({ ...prev, name: "" }));
            }}
            placeholder="Your name"
          />
          {errors.name && <span className="rar-field__error">{errors.name}</span>}
        </label>
        <label className={`rar-field${errors.email ? " rar-field--error" : ""}`}>
          <span>Email</span>
          <input
            type="email"
            value={email}
            onChange={(e) => {
              setEmail(e.target.value);
              setErrors((prev) => ({ ...prev, email: "" }));
            }}
            placeholder="you@example.com"
          />
          {errors.email && <span className="rar-field__error">{errors.email}</span>}
        </label>
        <label className={`rar-field rar-field--full${errors.message ? " rar-field--error" : ""}`}>
          <span>Message</span>
          <textarea
            value={message}
            onChange={(e) => {
              setMessage(e.target.value);
              setErrors((prev) => ({ ...prev, message: "" }));
            }}
            placeholder="Your message to the committee"
            rows={5}
          />
          {errors.message && <span className="rar-field__error">{errors.message}</span>}
        </label>
        {serverError && <p className="rar-form__server-error">{serverError}</p>}
        <div className="rar-form__actions">
          <button type="submit" className="rar-btn rar-btn--primary" disabled={loading}>
            {loading ? (
              "Sending…"
            ) : (
              <>
                Send Message <span className="arrow">&rarr;</span>
              </>
            )}
          </button>
        </div>
      </form>
    </section>
  );
};

const LINKS = [
  { label: "Air Force Museum of New Zealand", href: "https://www.airforcemuseum.co.nz/" },
  { label: "RNZAF Website", href: "https://www.nzdf.mil.nz/air-force/" },
  {
    label: "Air Force News (PDF)",
    href: "https://www.airforce.mil.nz/about-us/news/airforce-news/pdfs.htm",
  },
];

const LinksFooter = () => (
  <footer className="rar-footer" id="links" data-screen-label="08 Footer">
    <div className="rar-footer__rule" />
    <div className="rar-footer__inner">
      <div className="rar-footer__col">
        <p className="rar-eyebrow rar-eyebrow--light">About</p>
        <p>
          An unofficial reunion of serving and former Royal New Zealand Air Force avionics
          tradespeople &mdash; the Electrical, Instrument, Radio, Radar and Avionics trades from
          1938 to the present day.
        </p>
      </div>
      <div className="rar-footer__col">
        <p className="rar-eyebrow rar-eyebrow--light">Related</p>
        <ul>
          {LINKS.map((l) => (
            <li key={l.href}>
              <a href={l.href} target="_blank" rel="noreferrer">
                {l.label}
                <span className="ext"></span>
              </a>
            </li>
          ))}
        </ul>
      </div>
      <div className="rar-footer__col">
        <p className="rar-eyebrow rar-eyebrow--light">Committee</p>
        <p>
          The 2026 reunion has been cancelled. For enquiries, email{" "}
          <a href="mailto:contact@rnzafavionicsreunion.co.nz">contact@rnzafavionicsreunion.co.nz</a>
        </p>
      </div>
      <div className="rar-footer__col rar-footer__col--brand">
        <img src="assets/AV-Reunion-2018-Logo.png" alt="" />
        <p className="rar-footer__heritage">Per Ardua Ad Astra</p>
        <p className="rar-footer__copy">
          &copy; 2026 RNZAF Avionics Reunion. An unofficial reunion. Not affiliated with the NZDF.
        </p>
      </div>
    </div>
    <div className="rar-footer__bar">
      <span>RNZAF Avionics Reunion &middot; Est. 2002</span>
      <span>Wigram &middot; Woodbourne &middot; Christchurch</span>
    </div>
  </footer>
);

function setupSidebar() {
  const sidebar = document.querySelector(".rar-sidebar");
  if (!sidebar) return;
  const nav = sidebar.querySelector("nav");
  const allItems = Array.from(nav.querySelectorAll('a[href^="#"]')).filter((a) =>
    a.classList.contains("dial-item"),
  );

  if (allItems.length === 0) return;

  // Smooth scroll for clicks
  allItems.forEach((a) => {
    a.addEventListener("click", function (e) {
      e.preventDefault();
      const id = this.getAttribute("href").slice(1);
      const el = document.getElementById(id);
      if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
    });
  });

  // Build map of section IDs to their items
  const buildMap = () => {
    const map = new Map();
    allItems.forEach((a, idx) => {
      const id = a.getAttribute("href").slice(1);
      const el = document.getElementById(id);
      if (el) map.set(idx, { anchor: a, el, id });
    });
    return map;
  };

  let sectionMap = buildMap();
  let retries = 0;
  const maxRetries = 12;

  const startDial = (sectionMap) => {
    if (sectionMap.size === 0) return;
    const sections = Array.from(sectionMap.values()).sort((a, b) => {
      const aIdx = Array.from(sectionMap.entries()).find((e) => e[1] === a)[0];
      const bIdx = Array.from(sectionMap.entries()).find((e) => e[1] === b)[0];
      return aIdx - bIdx;
    });

    let ticking = false;
    const viewportCenter = () => window.innerHeight / 2;

    function updateDial() {
      const vc = viewportCenter();
      let bestIdx = 0;
      let bestDist = Infinity;

      // Find section closest to viewport center
      sections.forEach((s, idx) => {
        const r = s.el.getBoundingClientRect();
        const center = r.top + r.height / 2;
        const dist = Math.abs(center - vc);
        if (dist < bestDist) {
          bestDist = dist;
          bestIdx = idx;
        }
      });

      // Update all items with dial classes
      sections.forEach((s, idx) => {
        const offset = idx - bestIdx;
        s.anchor.classList.remove(
          "dial-center",
          "dial-offset-1",
          "dial-offset-neg-1",
          "dial-offset-2",
          "dial-offset-neg-2",
          "hidden",
        );

        // Only show items within ±2 range
        if (Math.abs(offset) > 2) {
          s.anchor.classList.add("hidden");
        } else if (offset === 0) {
          s.anchor.classList.add("dial-center");
        } else if (offset === 1) {
          s.anchor.classList.add("dial-offset-1");
        } else if (offset === -1) {
          s.anchor.classList.add("dial-offset-neg-1");
        } else if (offset === 2) {
          s.anchor.classList.add("dial-offset-2");
        } else if (offset === -2) {
          s.anchor.classList.add("dial-offset-neg-2");
        }
      });
    }

    function onScroll() {
      if (ticking) return;
      ticking = true;
      requestAnimationFrame(() => {
        updateDial();
        ticking = false;
      });
    }

    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    updateDial();
  };

  if (sectionMap.size === 0) {
    const id = setInterval(() => {
      retries += 1;
      sectionMap = buildMap();
      if (sectionMap.size > 0 || retries >= maxRetries) {
        clearInterval(id);
        if (sectionMap.size > 0) startDial(sectionMap);
      }
    }, 100);
  } else {
    startDial(sectionMap);
  }
}

Object.assign(window, {
  Header,
  Hero,
  AnnouncementPanel,
  StatsStrip,
  Chapter,
  PullQuote,
  Gallery,
  PastReunions,
  ContactForm,
  LinksFooter,
  setupSidebar,
});
