/* global React, Nav, Footer, Tag, useApi */
const { useState, useMemo, useRef, useEffect } = React;

const TC = {
  "Artificial Intelligence": "t-ai",
  "Implementation": "t-impl",
  "Research": "t-rsch",
  "Ethics": "t-eth",
  "Equity": "t-eq",
  "Education": "t-edu",
};
const TAG = {
  "Artificial Intelligence": "violet",
  "Implementation": "emerald",
  "Research": "blue",
  "Ethics": "amber",
  "Equity": "magenta",
  "Education": "ink",
};

const TOPICS = ["All", "Artificial Intelligence", "Implementation", "Research", "Ethics", "Equity", "Education"];

/** Format an ISO YYYY-MM-DD into "Mon DD, YYYY". */
function formatDate(iso) {
  if (!iso) return "";
  const d = new Date(iso + "T12:00:00");
  if (isNaN(d.getTime())) return iso;
  return d.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
}

/** Render a webinar's primary speaker line. */
function primarySpeaker(w) {
  if (!w.speakers || !w.speakers.length) return { name: "", aff: "" };
  const first = w.speakers.find(s => s.role === "speaker") || w.speakers[0];
  const name = first.credentials ? `${first.name}, ${first.credentials}` : first.name;
  return { name, aff: first.affiliation || "" };
}

/** Extract an 11-char YouTube video ID from a URL, or null. */
function youtubeId(url) {
  if (!url) return null;
  const m = url.match(/(?:youtu\.be\/|[?&]v=|youtube\.com\/embed\/|youtube\.com\/shorts\/)([A-Za-z0-9_-]{11})/);
  return m ? m[1] : null;
}

/** Resolve a webinar's thumbnail URL.
 *  Precedence: first speaker photo → custom thumbnail → YouTube-derived → null (topic fill).
 *  Speaker photo wins by default because a face is more visually engaging
 *  than a slide deck or generic recording frame. */
function thumbnailFor(w) {
  if (!w) return null;
  if (Array.isArray(w.speakers)) {
    const sp = w.speakers.find(s => s && s.photo && s.role !== "moderator")
            || w.speakers.find(s => s && s.photo);
    if (sp) return sp.photo;
  }
  if (w.thumbnail) return w.thumbnail;
  if (w.autoThumbnail !== false) {
    const id = youtubeId(w.youtube);
    if (id) return `https://i.ytimg.com/vi/${id}/hqdefault.jpg`;
  }
  return null;
}

/** Link target for a webinar card. Uses a query-string URL so it works
 *  without depending on Pages' _redirects rewrite (which has been flaky
 *  for this path). Detail page also accepts /webinar/<slug> via _redirects. */
function webinarHref(w) {
  return `/webinar-detail?id=${encodeURIComponent(w.slug || w.id)}`;
}

/* ────────────────────────────────────────────────────────── */

function Header() {
  return (
    <section style={{ padding: "72px 0 40px", borderBottom: "1px solid var(--rule)" }}>
      <div className="wrap">
        <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 22 }}>
          <span className="rule-thick" />
          <span className="eyebrow">Webinars · Hosted on JMIR YouTube</span>
        </div>
        <h1 className="t-display" style={{ maxWidth: 920 }}>
          Monthly conversations on the science and practice of digital psychiatry.
        </h1>
        <p className="lede" style={{ marginTop: 22, maxWidth: 660 }}>
          Free and open to the public. Recordings posted to JMIR YouTube within 48 hours of each session.
        </p>
      </div>
    </section>
  );
}

/* ────────────────────────────────────────────────────────── */

const PlayIcon = () => (
  <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5v14l11-7z" /></svg>
);
const CalendarIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
    <line x1="16" y1="2" x2="16" y2="6" />
    <line x1="8" y1="2" x2="8" y2="6" />
    <line x1="3" y1="10" x2="21" y2="10" />
  </svg>
);
const ClockIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <circle cx="12" cy="12" r="10" />
    <polyline points="12 6 12 12 16 14" />
  </svg>
);

function VideoCard({ w, index, upcoming }) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (typeof IntersectionObserver === "undefined") { setInView(true); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) { setInView(true); obs.disconnect(); }
      });
    }, { threshold: 0.1, rootMargin: "0px 0px -40px 0px" });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);

  const topicClass = TC[w.topic] || "";
  const thumb = thumbnailFor(w);
  const sp = primarySpeaker(w);
  const href = upcoming ? "#register" : webinarHref(w);

  return (
    <a
      ref={ref}
      href={href}
      className={`video-card ${inView ? "in-view" : ""}`}
      style={{ "--card-delay": `${index * 100}ms` }}
    >
      <div className="video-thumb" data-topic={topicClass}>
        {thumb ? (
          <img src={thumb} alt="" />
        ) : (
          <div className="video-thumb-fill">{w.topic}</div>
        )}
        <div className="video-overlay">
          <div className="video-play"><PlayIcon /></div>
        </div>
        {upcoming && (
          <span className="video-badge upcoming">Upcoming</span>
        )}
      </div>
      <div className="video-body">
        <h3 className="video-title">{w.title}</h3>
        <div className="video-speaker">{sp.name}</div>
        <div className="video-meta">
          <span className="video-meta-item"><CalendarIcon />{formatDate(w.date)}</span>
          {w.time && <span className="video-meta-item"><ClockIcon />{w.time}</span>}
        </div>
      </div>
    </a>
  );
}

function VideoCardSkeleton({ index }) {
  return (
    <div className="video-card in-view" style={{ "--card-delay": `${index * 100}ms`, pointerEvents: "none" }}>
      <div className="video-thumb" style={{ background: "var(--rule)" }} />
      <div className="video-body">
        <h3 className="video-title" style={{ background: "var(--rule)", color: "transparent", borderRadius: 3 }}>Loading title placeholder long enough</h3>
        <div className="video-speaker" style={{ background: "var(--rule-2)", color: "transparent", borderRadius: 3, marginTop: 8 }}>Loading speaker</div>
      </div>
    </div>
  );
}

function UpcomingPlusRecent({ upcoming, archive, loading }) {
  // 6-cell grid: upcoming (if any) followed by enough archive items to fill.
  const archiveSlice = upcoming ? archive.slice(0, 5) : archive.slice(0, 6);
  const totalCount = archive.length + (upcoming ? 1 : 0);
  const eyebrow = upcoming ? "Next session + recent" : "Recent sessions";

  return (
    <section style={{ padding: "72px 0", borderBottom: "1px solid var(--rule)" }}>
      <div className="wrap">
        <div className="section-head">
          <div className="head-l">
            <span className="num">/ 01</span>
            <span className="eyebrow">{eyebrow}</span>
          </div>
          <span className="caption mono" style={{ color: "var(--ink-4)", fontSize: 11, letterSpacing: "0.06em" }}>
            {Math.min(6, totalCount)} of {totalCount || "—"}
          </span>
        </div>
        <div className="video-grid">
          {loading && archive.length === 0 && !upcoming
            ? Array.from({ length: 6 }).map((_, i) => <VideoCardSkeleton key={i} index={i} />)
            : <>
                {upcoming && <VideoCard key={upcoming.id} w={upcoming} index={0} upcoming />}
                {archiveSlice.map((w, i) => <VideoCard key={w.id} w={w} index={(upcoming ? 1 : 0) + i} />)}
              </>}
        </div>
      </div>
    </section>
  );
}

/* ────────────────────────────────────────────────────────── */

function Archive({ archive, loading }) {
  const [topic, setTopic] = useState("All");
  const filtered = useMemo(
    () => topic === "All" ? archive : archive.filter(w => w.topic === topic),
    [topic, archive],
  );
  const counts = useMemo(() => {
    const c = {};
    archive.forEach(w => { c[w.topic] = (c[w.topic] || 0) + 1; });
    return c;
  }, [archive]);

  return (
    <section style={{ padding: "72px 0 96px" }}>
      <div className="wrap">
        <div className="section-head">
          <div className="head-l">
            <span className="num">/ 02</span>
            <span className="eyebrow">Archive · Filter by topic</span>
          </div>
          <span className="caption mono" style={{ color: "var(--ink-4)", fontSize: 11, letterSpacing: "0.06em" }}>
            {filtered.length} of {archive.length}
          </span>
        </div>

        <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 24 }}>
          {TOPICS.map(tt => {
            const active = tt === topic;
            const n = tt === "All" ? archive.length : (counts[tt] || 0);
            return (
              <button key={tt} onClick={() => setTopic(tt)} disabled={tt !== "All" && !counts[tt]} style={{
                padding: "7px 14px",
                borderRadius: 4,
                border: "1px solid " + (active ? "var(--ink)" : "var(--rule-2)"),
                background: active ? "var(--ink)" : "white",
                color: active ? "white" : "var(--ink-2)",
                fontFamily: "var(--type-mono)", fontSize: 11, letterSpacing: "0.04em",
                fontWeight: 500, cursor: "pointer", transition: "all .12s",
                display: "inline-flex", alignItems: "center", gap: 8,
                opacity: tt !== "All" && !counts[tt] ? 0.4 : 1,
              }}>
                <span>{tt}</span>
                <span style={{ opacity: 0.65, fontVariantNumeric: "tabular-nums" }}>{String(n).padStart(2, "0")}</span>
              </button>
            );
          })}
        </div>

        <div className="table-scroll">
          <table className="data-table">
            <thead>
              <tr>
                <th style={{ width: 110 }}>ID</th>
                <th style={{ width: 130 }}>Date</th>
                <th style={{ width: 160 }}>Topic</th>
                <th>Title</th>
                <th style={{ width: 240 }}>Speaker</th>
                <th style={{ width: 56 }}></th>
              </tr>
            </thead>
            <tbody>
              {loading && archive.length === 0 ? (
                <tr><td colSpan={6} style={{ padding: "32px 16px", color: "var(--ink-4)", fontSize: 13, textAlign: "center" }}>Loading…</td></tr>
              ) : filtered.length === 0 ? (
                <tr><td colSpan={6} style={{ padding: "32px 16px", color: "var(--ink-4)", fontSize: 13, textAlign: "center" }}>No webinars match this topic.</td></tr>
              ) : filtered.map(w => {
                const sp = primarySpeaker(w);
                return (
                  <tr key={w.id} onClick={() => { window.location.href = webinarHref(w); }} style={{ cursor: "pointer" }}>
                    <td className="col-mono">{w.id}</td>
                    <td className="col-mono">{formatDate(w.date)}</td>
                    <td><Tag kind={TAG[w.topic] || "violet"}>{w.topic}</Tag></td>
                    <td><strong style={{ fontSize: 14.5, color: "var(--ink)" }}>{w.title}</strong></td>
                    <td>
                      <div style={{ fontSize: 13.5, color: "var(--ink-2)" }}>{sp.name}</div>
                      {sp.aff && <div className="col-mono" style={{ marginTop: 2, fontSize: 11 }}>{sp.aff}</div>}
                    </td>
                    <td style={{ textAlign: "right", color: "var(--indigo-500)", fontSize: 14 }}>▶</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </section>
  );
}

/* ────────────────────────────────────────────────────────── */

function WebinarsPage() {
  const { data, loading } = useApi("webinars", { upcoming: null, archive: [] });
  const upcoming = data && data.upcoming ? data.upcoming : null;
  const archive = data && Array.isArray(data.archive) ? data.archive : [];
  return (
    <>
      <Nav active="webinars" />
      <Header />
      <UpcomingPlusRecent upcoming={upcoming} archive={archive} loading={loading} />
      <Archive archive={archive} loading={loading} />
      <Footer />
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<WebinarsPage />);
