/* career-journey.jsx — The "Career Journey" view
 *
 * Phase-grouped horizontal timeline, full-page job hero (no accordion box),
 * 30s auto-rotation while idle, a hidden Intermission easter egg sitting
 * between AKQA and NatGeo that opens the Bali photo modal, and a case-study
 * modal that opens when a stat card is clicked.
 */

/* global React, ReactDOM, CHAPTERS, CASE_STUDIES, StatClickContext, Cover, GuideBinder,
          Bloom, Splatter, MobileNavTray,
          ChapterFoundation, ChapterScale, ChapterEnterprise,
          ChapterComplexity, ChapterHypergrowth, ChapterDepth, ChapterIndependence */

const { useState: useStateCJ, useEffect: useEffectCJ, useRef: useRefCJ } = React;

/* ============================================================
   Timeline chapters — four named chapters of the career.
   Each chapter contains 1-3 jobs (referenced by CHAPTER id).
   ============================================================ */
const CJ_PHASES = [
  { id: "foundations",  label: "Foundations",      blurb: "where the craft was learned", chapterIds: ["foundation"] },
  { id: "craft",        label: "Craft Refinement", blurb: "where it was sharpened",       chapterIds: ["scale"] },
  { id: "scaling",      label: "Scaling",          blurb: "where it met complexity",      chapterIds: ["enterprise", "complexity", "hypergrowth"] },
  { id: "implementing", label: "Implementation",   blurb: "where I apply it all",         chapterIds: ["depth", "independence"] },
];

/* Map chapter id → 1-based index of its parent timeline chapter (1..4). */
function timelineChapterIndex(chId) {
  const i = CJ_PHASES.findIndex((p) => p.chapterIds.includes(chId));
  return i < 0 ? 1 : i + 1;
}

/* Auto-rotate cadence (ms) + idle-pause window. */
const CJ_ROTATE_MS = 30000;
const CJ_IDLE_RESUME_MS = 12000;  /* resume rotation N ms after the user last engaged */

/* Pull just the date range out of the eyebrow.
   e.g., "2005 — 2010 · Washington, DC" → "2005–2010" */
function cjDateRange(eyebrow) {
  if (!eyebrow) return "";
  const m = eyebrow.match(/(\d{4}\s*[—–-]\s*(?:\d{4}|Present))/i);
  if (m) return m[0].replace(/\s*[—–-]\s*/, "–");
  return eyebrow.split("·")[0].trim();
}

/* Pull location segment(s) out of the eyebrow (everything after the dates). */
function cjLocation(eyebrow) {
  if (!eyebrow) return "";
  const parts = eyebrow.split("·").map((s) => s.trim()).filter(Boolean);
  return parts.slice(1).join(" · ");
}

/* Map chapter id → its rendered chapter component */
function renderChapter(id) {
  switch (id) {
    case "foundation":   return <ChapterFoundation />;
    case "scale":        return <ChapterScale />;
    case "enterprise":   return <ChapterEnterprise />;
    case "complexity":   return <ChapterComplexity />;
    case "hypergrowth":  return <ChapterHypergrowth />;
    case "depth":        return <ChapterDepth />;
    case "independence": return <ChapterIndependence />;
    default: return null;
  }
}

/* ============================================================
   HorizontalTimeline — the career-story sub-navigation.
   A single horizontal band of 4 colour-coded groups; under each
   group sit its companies (with dates). Selecting a company swaps the
   active job in the content area below. No left rail, no frames —
   plain in-page DOM. Wraps to a horizontal scroll strip on mobile
   (see .cs-nav in styles.css). The group accent colour is set per
   group via the --group CSS variable so each grouping reads distinctly.
   ============================================================ */
const CJ_GROUP_COLORS = {
  foundations:  "var(--accent)",
  craft:        "var(--bloom)",
  scaling:      "color-mix(in oklab, var(--accent) 50%, var(--bloom))",
  implementing: "color-mix(in oklab, var(--bloom) 55%, var(--ink))",
};

function HorizontalTimeline({ phases, chaptersById, activeId, onSelect, rotateProgress }) {
  /* Minimized by default (only the CH#/label/blurb headers show). Hovering the
     nav expands it to reveal the job links; rolling off — or clicking a job —
     collapses it again (state, not :hover, so a click resets it cleanly). */
  const [open, setOpen] = useStateCJ(false);

  /* The active job — painted on the mobile tray trigger so the reader sees the
     current chapter + company without opening the drawer. */
  const activeCh = chaptersById[activeId] || null;
  const activeChapterNum = String(timelineChapterIndex(activeId)).padStart(2, "0");

  return (
    <nav
      className="cs-nav"
      data-open={open}
      onMouseEnter={() => setOpen(true)}
      onMouseLeave={() => setOpen(false)}
      aria-label="Career chapters timeline">
      <ol className="cs-nav__groups">
        {phases.map((phase, phaseIdx) => {
          /* Find each chapter in the phase, preserving CHAPTERS order */
          const items = phase.chapterIds
            .map((id) => chaptersById[id])
            .filter(Boolean);
          return (
            <li
              key={phase.id}
              className="cs-nav__group"
              data-phase={phase.id}
              style={{ "--group": CJ_GROUP_COLORS[phase.id] || "var(--accent)" }}>
              <header className="cs-nav__group-head">
                <span className="cs-nav__group-num">CH. {String(phaseIdx + 1).padStart(2, "0")}</span>
                <h3 className="cs-nav__group-label">{phase.label}</h3>
                <p className="cs-nav__group-blurb">{phase.blurb}</p>
              </header>
              <ul className="cs-nav__companies" role="tablist" aria-label={`${phase.label} chapters`}>
                {items.map((ch) => {
                  const active = activeId === ch.id;
                  return (
                    <li key={ch.id} className="cs-nav__company-item">
                      <button
                        type="button"
                        role="tab"
                        aria-selected={active}
                        aria-controls={`cj-hero-${ch.id}`}
                        data-active={active}
                        className="cs-nav__node"
                        onClick={() => { setOpen(false); onSelect(ch.id); }}>
                        <span className="cs-nav__node-dot" aria-hidden="true">
                          {active && (
                            <span
                              className="cs-nav__node-progress"
                              style={{ "--p": `${rotateProgress}%` }}
                              aria-hidden="true" />
                          )}
                        </span>
                        <span className="cs-nav__node-company">{ch.company}</span>
                        <span className="cs-nav__node-dates">{cjDateRange(ch.eyebrow)}</span>
                      </button>
                    </li>
                  );
                })}
              </ul>
            </li>
          );
        })}
      </ol>

      {/* Mobile: the four-group timeline collapses to a left slide-out tray.
          The trigger shows the active chapter + company; the tray reproduces
          the full phase-grouped, colour-capped index. */}
      {typeof MobileNavTray !== "undefined" && (
        <MobileNavTray
          eyebrow="Career chapters"
          current={{ num: `Ch. ${activeChapterNum}`, label: activeCh ? activeCh.company : "Career story" }}
          title="The career story">
          {(close) => (
            <div className="mnav-groups">
              {phases.map((phase, phaseIdx) => {
                const items = phase.chapterIds
                  .map((id) => chaptersById[id])
                  .filter(Boolean);
                return (
                  <section
                    key={phase.id}
                    className="mnav-group"
                    style={{ "--group": CJ_GROUP_COLORS[phase.id] || "var(--accent)" }}>
                    <header className="mnav-group__head">
                      <span className="mnav-group__num">CH. {String(phaseIdx + 1).padStart(2, "0")}</span>
                      <h3 className="mnav-group__label">{phase.label}</h3>
                      <p className="mnav-group__blurb">{phase.blurb}</p>
                    </header>
                    <ul className="mnav-list" role="list">
                      {items.map((ch) => {
                        const active = activeId === ch.id;
                        return (
                          <li key={ch.id}>
                            <button
                              type="button"
                              className="mnav-item mnav-item--company"
                              data-active={active}
                              aria-current={active ? "true" : undefined}
                              onClick={() => { onSelect(ch.id); close(); }}>
                              <span className="mnav-item__title">{ch.company}</span>
                              <span className="mnav-item__dates">{cjDateRange(ch.eyebrow)}</span>
                              {active && <span className="mnav-item__here">you&rsquo;re here</span>}
                            </button>
                          </li>
                        );
                      })}
                    </ul>
                  </section>
                );
              })}
            </div>
          )}
        </MobileNavTray>
      )}
    </nav>
  );
}

/* ============================================================
   JobHero — full-bleed "meta card" for the active job.
   Shows: chapter nod, title (active variant), company, dates,
   location, industry/descriptor, series (dateline).
   Renders on the page background — no border, no card box.
   ============================================================ */
function JobHero({ chapter }) {
  if (!chapter) return null;
  const dates       = cjDateRange(chapter.eyebrow);
  const location    = cjLocation(chapter.eyebrow);
  const title       = chapter.titleOptions[chapter.titleDefault];
  return (
    <header
      key={chapter.id}
      className="cj-hero"
      id={`cj-hero-${chapter.id}`}
      data-phase={phaseForChapter(chapter.id)}>
      <h2 className="cj-hero__title">{title}</h2>
      <p className="cj-hero__subtitle">{chapter.subtitle}</p>
      {/* Meta layout: top row = Company / Role / Location / Dates.
          Bottom row = Industry / Series (funding stage / scaleup / startup).
          Each row is its own dl so the rows always sit on separate lines
          even when one of the bottom fields is missing. */}
      <dl className="cj-hero__meta cj-hero__meta--top">
        <div className="cj-hero__meta-pair">
          <dt>Company</dt>
          <dd><strong>{chapter.company}</strong></dd>
        </div>
        <div className="cj-hero__meta-pair">
          <dt>Role</dt>
          <dd>{chapter.role}</dd>
        </div>
        {location && (
          <div className="cj-hero__meta-pair">
            <dt>Location</dt>
            <dd>{location}</dd>
          </div>
        )}
        <div className="cj-hero__meta-pair">
          <dt>Dates</dt>
          <dd>{dates}</dd>
        </div>
      </dl>
      {(chapter.descriptor || chapter.series) && (
        <dl className="cj-hero__meta cj-hero__meta--bottom">
          {chapter.descriptor && (
            <div className="cj-hero__meta-pair">
              <dt>Industry</dt>
              <dd>{chapter.descriptor}</dd>
            </div>
          )}
          {chapter.series && (
            <div className="cj-hero__meta-pair cj-hero__meta-pair--series">
              <dt>Series</dt>
              <dd>{chapter.series}</dd>
            </div>
          )}
        </dl>
      )}
    </header>
  );
}

function phaseForChapter(chId) {
  const p = CJ_PHASES.find((ph) => ph.chapterIds.includes(chId));
  return p ? p.id : "foundations";
}

/* ============================================================
   CaseStudyModal — STAR+ formatted, reads from window.CASE_STUDIES
   ============================================================ */
const STAR_SECTIONS = [
  { label: "Context",      key: "context"     },
  { label: "Problem",      key: "problem"     },
  { label: "My Role",      key: "myRole"      },
  { label: "What I Built", key: "whatIBuilt"  },
  { label: "How I Led It", key: "howILedIt"   },
  { label: "Outcome",      key: "outcome"     },
  { label: "Throughline",  key: "throughline" },
];

function CaseStudyModal({ csKey, onClose }) {
  const cs = (typeof CASE_STUDIES !== "undefined" && CASE_STUDIES[csKey]) || null;

  /* Lock body scroll while open; restore on close */
  useEffectCJ(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, []);

  /* ESC closes */
  useEffectCJ(() => {
    function onKey(e) { if (e.key === "Escape") onClose(); }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const fallback = (
    <div className="cs-modal" role="dialog" aria-modal="true" onClick={onClose}>
      <div className="cs-modal__card" onClick={(e) => e.stopPropagation()}>
        <header className="cs-modal__head">
          <p className="cs-modal__eyebrow">Case Study</p>
          <h2 className="cs-modal__title">Coming soon</h2>
          <p className="cs-modal__stat">No entry for <code>{csKey}</code> in case-studies.jsx.</p>
          <button type="button" className="cs-modal__close" onClick={onClose} aria-label="Close">×</button>
        </header>
      </div>
    </div>
  );

  const content = (
    <div className="cs-modal" role="dialog" aria-modal="true" aria-label={cs && cs.title} onClick={onClose}>
      <div className="cs-modal__card" onClick={(e) => e.stopPropagation()}>
        <header className="cs-modal__head">
          <p className="cs-modal__eyebrow">Case Study</p>
          <h2 className="cs-modal__title">{cs && cs.title}</h2>
          {cs && cs.statLabel && <p className="cs-modal__stat">{cs.statLabel}</p>}
          <button type="button" className="cs-modal__close" onClick={onClose} aria-label="Close case study">×</button>
          {/* These case studies are still drafts — a subtle stamp signals so. */}
          <span className="cs-modal__stamp" aria-hidden="true">Coming soon</span>
        </header>

        <div className="cs-modal__body">
          {STAR_SECTIONS.map((s) => {
            const v = cs && cs[s.key];
            if (!v) return null;
            const paras = String(v).split(/\n\n+/);
            const showFig = s.key === "whatIBuilt" && cs.fig === "guideBinder" && typeof GuideBinder !== "undefined";
            return (
              <section key={s.key} className="cs-modal__section">
                <h3 className="cs-modal__sec-label">{s.label}</h3>
                {paras.map((p, i) => <p key={i}>{p}</p>)}
                {/* Relocated Fig. 4 animation (its caption travels inside the
                    GuideBinder component) — see ChapterComplexity. */}
                {showFig && (
                  <div className="cs-modal__fig">
                    <GuideBinder />
                  </div>
                )}
              </section>
            );
          })}
        </div>
      </div>
    </div>
  );

  return ReactDOM.createPortal(cs ? content : fallback, document.body);
}

/* ============================================================
   CareerJourneyView — composes phase timeline + active job hero
   + full-page chapter content, with 30s auto-rotation and pause
   on user engagement.
   ============================================================ */
function CareerJourneyView({ setView }) {
  const chaptersById = React.useMemo(() => {
    const map = {};
    CHAPTERS.forEach((c) => { map[c.id] = c; });
    return map;
  }, []);

  /* Initial active job: parse URL fragment, else first chapter */
  const initialId = (() => {
    const h = (window.location.hash || "").replace(/^#/, "");
    if (h && CHAPTERS.some((c) => c.id === h)) return h;
    return CHAPTERS[0]?.id || null;
  })();

  const [activeId, setActiveId] = useStateCJ(initialId);
  const [modalKey, setModalKey] = useStateCJ(null);
  const [rotateProgress, setRotateProgress] = useStateCJ(0);    /* 0..100 for the active node's ring */
  const [paused, setPaused] = useStateCJ(false);
  const idleTimerRef = useRefCJ(null);
  const tickRef = useRefCJ(null);
  const cycleStartRef = useRefCJ(Date.now());
  const heroRef = useRefCJ(null);
  const wrapRef = useRefCJ(null);

  /* Select a chapter — used by clicks and the rotation tick. */
  function selectChapter(id, { user = false } = {}) {
    setActiveId(id);
    history.replaceState(null, "", `#${id}`);
    cycleStartRef.current = Date.now();
    setRotateProgress(0);
    if (user) {
      pauseForEngagement();
      /* Scroll to the very top of the page on a job click (not a fixed offset
         below the nav) — the reader starts the new role from the top. */
      window.scrollTo({ top: 0, behavior: "smooth" });
    }
  }

  /* Advance to the next chapter in CHAPTERS order, wrapping. */
  function advanceChapter() {
    const i = CHAPTERS.findIndex((c) => c.id === activeId);
    const j = ((i < 0 ? 0 : i) + 1) % CHAPTERS.length;
    selectChapter(CHAPTERS[j].id);
  }

  /* Step one role chronologically (−1 prev / +1 next), wrapping — used by the
     flanking arrows and the ← → keys. Counts as user engagement. */
  function stepChapter(delta) {
    const i = CHAPTERS.findIndex((c) => c.id === activeId);
    if (i < 0) return;
    const j = (i + delta + CHAPTERS.length) % CHAPTERS.length;
    selectChapter(CHAPTERS[j].id, { user: true });
  }

  /* Engagement → pause the rotation for an idle window. */
  function pauseForEngagement() {
    setPaused(true);
    if (idleTimerRef.current) clearTimeout(idleTimerRef.current);
    idleTimerRef.current = setTimeout(() => {
      setPaused(false);
      cycleStartRef.current = Date.now();
      setRotateProgress(0);
    }, CJ_IDLE_RESUME_MS);
  }

  /* Listen for engagement within the journey section: pointer move/click,
     scroll, key press. Each resets the idle window. */
  useEffectCJ(() => {
    const el = wrapRef.current;
    if (!el) return;
    function onActivity() { pauseForEngagement(); }
    el.addEventListener("pointermove", onActivity, { passive: true });
    el.addEventListener("pointerdown", onActivity, { passive: true });
    el.addEventListener("wheel", onActivity, { passive: true });
    el.addEventListener("keydown", onActivity);
    return () => {
      el.removeEventListener("pointermove", onActivity);
      el.removeEventListener("pointerdown", onActivity);
      el.removeEventListener("wheel", onActivity);
      el.removeEventListener("keydown", onActivity);
    };
  }, []);

  /* Rotation tick: every 250ms update the ring; when full, advance. */
  useEffectCJ(() => {
    if (paused || modalKey) {
      if (tickRef.current) clearInterval(tickRef.current);
      tickRef.current = null;
      return;
    }
    cycleStartRef.current = Date.now();
    setRotateProgress(0);
    tickRef.current = setInterval(() => {
      const elapsed = Date.now() - cycleStartRef.current;
      const pct = Math.min(100, (elapsed / CJ_ROTATE_MS) * 100);
      setRotateProgress(pct);
      if (elapsed >= CJ_ROTATE_MS) {
        advanceChapter();
      }
    }, 250);
    return () => {
      if (tickRef.current) clearInterval(tickRef.current);
      tickRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [paused, activeId, modalKey]);

  /* Open a case study modal from a stat-card click */
  function openCaseStudy(chId, statIdx) {
    setModalKey(`${chId}-${statIdx}`);
  }

  /* Keyboard navigation: ← → moves between chapters and pauses rotation */
  useEffectCJ(() => {
    function onKey(e) {
      if (modalKey) return;
      if (!["ArrowLeft", "ArrowRight"].includes(e.key)) return;
      const tag = (document.activeElement && document.activeElement.tagName) || "";
      if (["INPUT", "TEXTAREA"].includes(tag)) return;
      stepChapter(e.key === "ArrowRight" ? 1 : -1);
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeId, modalKey]);

  const activeChapter = chaptersById[activeId] || CHAPTERS[0];

  /* Chapter label folded into the page header — updates as the reader steps
     through the career story (e.g. "Chapter 01 · Foundations"). */
  const cjChapterNum  = timelineChapterIndex(activeChapter.id);
  const cjChapterName = (CJ_PHASES.find((p) => p.id === phaseForChapter(activeChapter.id)) || {}).label;
  const cjChapterLabel = `Chapter ${String(cjChapterNum).padStart(2, "0")}${cjChapterName ? ` · ${cjChapterName}` : ""}`;

  return (
    <StatClickContext.Provider value={openCaseStudy}>
      <section
        ref={wrapRef}
        className="cs-page"
        id="career-journey"
        data-phase={phaseForChapter(activeChapter.id)}
        aria-label="A career story">

        {/* Decorative watermarks + splash marks (same vocab as the rest of the
            zine). Positioned absolutely behind everything; non-interactive. */}
        <div className="cj__watermarks" aria-hidden="true">
          {typeof Bloom !== "undefined" && (
            <>
              <Bloom color="var(--accent)" size={460} top={-100} left={-170} seed={3} opacity={0.4} />
              <Bloom color="var(--bloom)" size={420} top={"55%"} left={"86%"} seed={7} opacity={0.32} />
            </>
          )}
          {typeof Splatter !== "undefined" && (
            <>
              <Splatter color="var(--ink)" size={220} seed={11} style={{ top: "10%", right: "4%" }} />
              <Splatter color="var(--accent)" size={180} seed={19} style={{ top: "78%", left: "4%" }} />
            </>
          )}
        </div>

        {/* Roles/jobs timeline nav — moved above the page header so it stays
            locked under the masthead sub-nav permanently (hover-to-expand
            behavior unchanged). */}
        <HorizontalTimeline
          phases={CJ_PHASES}
          chaptersById={chaptersById}
          activeId={activeId}
          onSelect={(id) => selectChapter(id, { user: true })}
          rotateProgress={rotateProgress}
        />

        {/* Page eyebrow only — headline + sub-header removed for a simpler page. */}
        <header className="svc__hero cs-story-head">
          <div className="eyebrow"><span>Career story: {cjChapterLabel}</span></div>
        </header>

        <div className="cs-content">
          {/* Subtle prev/next arrows — step through the roles chronologically
              (same wrap-around order as the ← → keys). */}
          <button
            type="button"
            className="cj__nav-arrow cj__nav-arrow--prev"
            aria-label="Previous role"
            onClick={() => stepChapter(-1)}>
            <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
              <path d="M15 5l-7 7 7 7" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </button>

          <div className="cj__stage" ref={heroRef} key={activeChapter.id}>
            <JobHero chapter={activeChapter} />
            <div className="cj__chapter-wrap">
              {renderChapter(activeChapter.id)}
            </div>
          </div>

          <button
            type="button"
            className="cj__nav-arrow cj__nav-arrow--next"
            aria-label="Next role"
            onClick={() => stepChapter(1)}>
            <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
              <path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </button>
        </div>

        {/* Cross-promo → the Services page (#services switches the view). */}
        <div className="xpromo">
          {typeof SubstackSignup !== "undefined" && <SubstackSignup />}
          <span className="xpromo__label">Ready to put this to work?</span>
          <a className="xpromo__link" href="#services">How we engage &rarr;</a>
        </div>
      </section>

      {modalKey && (
        <CaseStudyModal
          csKey={modalKey}
          onClose={() => setModalKey(null)}
        />
      )}

    </StatClickContext.Provider>
  );
}

Object.assign(window, { CareerJourneyView });
