/* global React */

/* ============================================================
   Browse — the full Vol. 08 index
   ============================================================ */

const BROWSE_SUPABASE_URL = "https://txxeefepmwqfptlzfxkf.supabase.co";
const BROWSE_SUPABASE_KEY = "sb_publishable_ziRn1I6oEYiUfLVdxvzmbw_AShSqb7Z";

// Which language's index is this? Set per page via window.BROWSE_LOCALE, else
// read from <html lang>, else English. Drives the data query and all paths so
// /<lang>/browse/ shows that language's guides and links its own pages.
const BROWSE_LOCALES = ["en", "es", "fr", "de", "pt", "zh", "ar", "hi"];
const BROWSE_LOCALE = (() => {
  try {
    const w = (typeof window !== "undefined" && window.BROWSE_LOCALE) || "";
    const h = (typeof document !== "undefined" && document.documentElement && document.documentElement.lang) || "";
    const cand = (w || h || "en").slice(0, 2).toLowerCase();
    return BROWSE_LOCALES.includes(cand) ? cand : "en";
  } catch (_e) { return "en"; }
})();

// Realtime: ask Iris to write a brand-new guide for a query with no existing
// page. The function applies the strict safety + scope gate before building;
// on success it returns { ok, slug } and we navigate there (the edge worker
// renders it). This is an explicit, user-triggered action — never automatic.
async function askIris(query, setBuilding, setAskMsg) {
  setBuilding(true); setAskMsg(null);
  try {
    const r = await fetch(`${BROWSE_SUPABASE_URL}/functions/v1/iris-realtime`, {
      method: "POST",
      headers: { apikey: BROWSE_SUPABASE_KEY, authorization: `Bearer ${BROWSE_SUPABASE_KEY}`, "content-type": "application/json" },
      body: JSON.stringify({ query, locale: BROWSE_LOCALE }),
    });
    const j = await r.json().catch(() => null);
    if (j && j.ok && j.slug) { window.location.href = j.slug; return; }
    setAskMsg((j && j.message) || "Iris couldn’t build that one — try rephrasing it as a how-to.");
  } catch (_e) {
    setAskMsg("That took longer than expected — Iris may still be writing it. Give it a moment and try the search again.");
  }
  setBuilding(false);
}

const SHELVES = [
  { n: "01", lane: "health",  slug: "mind",       name: "Mind",       dek: "Focus, mood, the days you can’t name." },
  { n: "02", lane: "health",  slug: "body",       name: "Body",       dek: "Symptoms, sleep, the ordinary wellness." },
  { n: "03", lane: "health",  slug: "soul",       name: "Soul",       dek: "Breath, stillness, the quiet practices." },
  { n: "04", lane: "health",  slug: "prevention", name: "Prevention", dek: "Screenings, habits, staying ahead." },
  { n: "05", lane: "health",  slug: "care",       name: "Care",       dek: "Labs, doctors, useful supplements." },
  { n: "06", lane: "health",  slug: "recovery",   name: "Recovery",   dek: "The long road back, on purpose." },
  { n: "07", lane: "fitness", slug: "train",      name: "Train",      dek: "The work itself — cardio, lifts, running." },
  { n: "08", lane: "fitness", slug: "build",      name: "Build",      dek: "Muscle, strength, body composition." },
  { n: "09", lane: "fitness", slug: "fuel",       name: "Fuel",       dek: "Eating around training. Protein, timing, hydration." },
  { n: "10", lane: "fitness", slug: "move",       name: "Move",       dek: "Walking, mobility, yoga, the in-betweens." },
  { n: "11", lane: "fitness", slug: "diet",       name: "Diet",       dek: "How you eat overall — calories, plant-based, fasting." },
  { n: "12", lane: "fitness", slug: "recover",    name: "Recover",    dek: "Rest, sleep for recovery, deloads, return-to-training." },
];

const LANE_LABEL = { health: "Health", fitness: "Fitness" };

/* Curated, hand-built essays that live outside the iris `pages` table but should
   still surface in the index. Rendered in their own "From the founder" group
   (not as a "How to …" leaf). en-only. */
const CURATED_ESSAYS = [
  {
    slug: "/en/contributors/jt/the-things-he-never-talked-about/",
    href: "/en/contributors/jt/the-things-he-never-talked-about/",
    title: "The Things He Never Talked About",
    meta_description: "JT’s Father’s Day essay — on the silence men keep around their own health, and the kind of strength that turns out not to be strength at all.",
    lane: "health",
    shelf: "__essay",
    kind: "essay",
  },
];

function browseParseSlug(slug) {
  if (!slug || !slug.startsWith("/")) return { lane: null, shelf: null };
  const parts = slug.split("/").filter(Boolean);
  if (parts[0] !== BROWSE_LOCALE) return { lane: null, shelf: null };
  return { lane: parts[1] || null, shelf: parts[2] || null };
}

function browseTitleFromSlug(slug) {
  const parts = slug.split("/").filter(Boolean);
  const last = parts.at(-1) || slug;
  const raw = last.replace(/-/g, " ");
  return raw.replace(/\b\w/g, (c) => c.toUpperCase());
}

function browseFormatTitle(t) {
  if (!t) return "";
  // Trim leading "How to " so the rail can render the italic ascender consistently.
  return t.replace(/^How to /i, "");
}

/* ---------------- Crumb ---------------- */
function BrowseCrumb() {
  return (
    <div className="crumb">
      <div className="crumb-inner">
        <div className="crumb-trail">
          <a href={`/${BROWSE_LOCALE}/`}>How To: Health &amp; Fitness</a>
          <span className="sep">/</span>
          <span className="here">The Index</span>
        </div>
        <div>Vol. 08 · Full archive · Updated daily</div>
      </div>
    </div>
  );
}
window.BrowseCrumb = BrowseCrumb;

/* ---------------- Editorial hero ---------------- */
function BrowseHero({ total, healthCount, fitnessCount }) {
  return (
    <section className="hhero browse-hero" data-screen-label="01 Browse Hero">
      <div className="hhero-inner">
        <div>
          <div className="hhero-eyebrow">
            <span className="dot" />
            <span>The Index — Vol. 08</span>
          </div>
          <h1>
            Every how-to,<br />
            on one <span className="it">shelf</span>.
          </h1>
          <p className="lede">
            The whole issue, alphabetized and searchable. Filter by lane — Health or Fitness — narrow to a shelf, or search for the thing you actually want to do. New guides land here first.
          </p>
          <div className="meta-row">
            <span><strong>{total.toLocaleString()}</strong> guides</span>
            <span className="sep">·</span>
            <span><strong>12</strong> shelves</span>
            <span className="sep">·</span>
            <span><strong>02</strong> lanes</span>
            <span className="sep">·</span>
            <span>Updated daily</span>
          </div>
        </div>
        <aside className="hhero-aside">
          <div className="a-eyebrow">A note from the desk</div>
          <p>
            “We don’t hide the back issues. If we published it, it’s in here — even the ones nobody’s asked for yet.”
          </p>
          <div className="by">
            <span className="ava">E.</span>
            <span>By <strong>The Editors</strong> · Vol. 08, Spring/Summer ’26</span>
          </div>
        </aside>
      </div>
    </section>
  );
}

/* ---------------- Toolbar (search + lane toggle) ---------------- */
function BrowseToolbar({ query, setQuery, activeLane, setLane, counts }) {
  return (
    <section className="browse-toolbar" data-screen-label="02 Toolbar">
      <div className="frame">
        <div className="sec-head">
          <div className="num">No. 07</div>
          <h2 className="title">Find your <span className="display italic" style={{ color: "var(--accent)" }}>one thing.</span></h2>
          <div className="meta">Type, narrow,<br/>open.</div>
        </div>

        <div className="bt-row">
          <div className="bt-search">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" aria-hidden="true">
              <circle cx="11" cy="11" r="7" />
              <path d="m20 20-3.5-3.5" strokeLinecap="round" />
            </svg>
            <span className="bt-prefix">how to</span>
            <input
              type="search"
              value={query}
              placeholder="sleep through the whole night…"
              onChange={(e) => setQuery(e.target.value)}
              aria-label="Search every guide"
            />
            {query ? (
              <button className="bt-clear" onClick={() => setQuery("")} aria-label="Clear search">×</button>
            ) : null}
          </div>

          <div className="bt-lane-toggle">
            <button className={activeLane === "all" ? "active" : ""} onClick={() => setLane("all")}>
              Both lanes <em>{counts.all}</em>
            </button>
            <button className={activeLane === "health" ? "active" : ""} onClick={() => setLane("health")}>
              <span className="lane-mark health" /> Health <em>{counts.health}</em>
            </button>
            <button className={activeLane === "fitness" ? "active" : ""} onClick={() => setLane("fitness")}>
              <span className="lane-mark fitness" /> Fitness <em>{counts.fitness}</em>
            </button>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------------- The Index — shelf rail + grouped list ---------------- */
function BrowseIndex({ rows, loading, error, activeLane, activeShelf, setShelf, counts, query }) {
  const visibleShelves = SHELVES.filter((s) => activeLane === "all" || s.lane === activeLane);
  const [building, setBuilding] = React.useState(false);
  const [askMsg, setAskMsg] = React.useState(null);

  // Group rows by shelf when no shelf filter active; otherwise flat
  const groups = React.useMemo(() => {
    if (activeShelf) {
      const filtered = rows.filter((r) => r.shelf === activeShelf);
      const shelfMeta = SHELVES.find((s) => s.slug === activeShelf);
      return [{ shelf: shelfMeta, items: filtered }];
    }
    const essays = rows.filter((r) => r.kind === "essay");
    const map = new Map();
    for (const s of visibleShelves) map.set(s.slug, { shelf: s, items: [] });
    map.set("__unshelved", { shelf: { n: "—", name: "Forthcoming", dek: "Generated. Awaiting a shelf assignment.", lane: null }, items: [] });
    for (const r of rows) {
      if (r.kind === "essay") continue; // shown in its own group below
      if (activeLane !== "all" && r.lane !== activeLane && r.lane !== null) continue;
      if (activeLane !== "all" && r.lane === null) continue;
      if (r.shelf && map.has(r.shelf)) map.get(r.shelf).items.push(r);
      else map.get("__unshelved").items.push(r);
    }
    const ordered = [...map.values()].filter((g) => g.items.length > 0);
    if (essays.length) ordered.unshift({ shelf: { n: "·", slug: "__essay", name: "From the founder", dek: "A personal essay from JT.", lane: null }, items: essays });
    return ordered;
  }, [rows, activeShelf, activeLane, visibleShelves]);

  const totalShown = groups.reduce((sum, g) => sum + g.items.length, 0);

  return (
    <section id="index" className="browse-index" data-screen-label="03 The Index">
      <div className="frame">
        <div className="sec-head">
          <div className="num">No. 08</div>
          <h2 className="title">The whole <span className="display italic" style={{ color: "var(--accent)" }}>shelf.</span></h2>
          <div className="meta">
            {loading ? "Loading…" : error ? "Couldn’t load." : <>{totalShown.toLocaleString()} guide{totalShown === 1 ? "" : "s"} {query ? `for “${query}”` : "showing"}</>}
          </div>
        </div>

        <div className="bi-grid">
          {/* Sticky shelf rail */}
          <aside className="bi-rail">
            <div className="r-eyebrow">
              <span className="dot" />
              <span>{activeLane === "all" ? "12 shelves" : `${visibleShelves.length} shelves · ${LANE_LABEL[activeLane]}`}</span>
            </div>
            <button
              className={`bi-shelf ${activeShelf === null ? "is-active" : ""}`}
              onClick={() => setShelf(null)}
            >
              <span className="num">—</span>
              <span className="name">All shelves</span>
              <span className="ct">{counts.lane[activeLane] || 0}</span>
            </button>
            {visibleShelves.map((s) => (
              <button
                key={s.slug}
                className={`bi-shelf lane-${s.lane} ${activeShelf === s.slug ? "is-active" : ""}`}
                onClick={() => setShelf(activeShelf === s.slug ? null : s.slug)}
              >
                <span className="num">{s.n}</span>
                <span className="name">{s.name}<span className="it">.</span></span>
                <span className="ct">{counts.shelf[s.slug] || 0}</span>
              </button>
            ))}
            {counts.shelf.__unshelved ? (
              <button
                className={`bi-shelf is-pending ${activeShelf === "__pending" ? "is-active" : ""}`}
                onClick={() => setShelf(null)}
                disabled
                title="Generated but not yet placed on a shelf"
              >
                <span className="num">··</span>
                <span className="name">Forthcoming</span>
                <span className="ct">{counts.shelf.__unshelved}</span>
              </button>
            ) : null}
          </aside>

          {/* Grouped index list */}
          <div className="bi-list">
            {loading ? (
              <div className="bi-state">Loading the issue…</div>
            ) : error ? (
              <div className="bi-state is-err">Couldn’t load the index: {error}</div>
            ) : groups.length === 0 ? (
              <div className="bi-state" style={{ display: "flex", flexDirection: "column", gap: 16, alignItems: "flex-start" }}>
                {query ? (
                  askMsg ? (
                    <p style={{ margin: 0, lineHeight: 1.6, maxWidth: "52ch" }}>{askMsg}</p>
                  ) : building ? (
                    <p style={{ margin: 0, lineHeight: 1.6 }}>
                      <strong style={{ color: "var(--accent)" }}>Iris is writing “{query}”…</strong><br />
                      <span style={{ opacity: 0.7, fontSize: "0.9em" }}>This takes about half a minute — hang tight.</span>
                    </p>
                  ) : (
                    <>
                      <p style={{ margin: 0, lineHeight: 1.6 }}>No guide for “{query}” yet.</p>
                      <button
                        onClick={() => askIris(query, setBuilding, setAskMsg)}
                        style={{ cursor: "pointer", font: "inherit", fontWeight: 600, color: "#1f1810", background: "var(--accent, #c79a4e)", border: "none", borderRadius: 2, padding: "13px 22px" }}
                      >
                        Ask Iris to write it →
                      </button>
                    </>
                  )
                ) : "Nothing matches that combination. Try clearing a filter — or rephrase the search."}
              </div>
            ) : (
              groups.map((g) => (
                <div key={g.shelf.slug || g.shelf.name} className="bi-group">
                  <header className="bi-group-head">
                    <div className="g-num">{g.shelf.n}</div>
                    <h3 className="g-name">
                      {g.shelf.lane ? <a href={`/${BROWSE_LOCALE}/${g.shelf.lane}/${g.shelf.slug}/`}>{g.shelf.name}<span className="it">.</span></a> : <span>{g.shelf.name}<span className="it">.</span></span>}
                    </h3>
                    <div className="g-meta">
                      <span>{g.items.length} guide{g.items.length === 1 ? "" : "s"}</span>
                      {g.shelf.dek ? <><span className="sep">·</span><span className="g-dek">{g.shelf.dek}</span></> : null}
                    </div>
                  </header>
                  <ol className="bi-rows">
                    {g.items.map((r, i) => (
                      <BrowseRow key={r.slug} row={r} index={i + 1} />
                    ))}
                  </ol>
                </div>
              ))
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

function BrowseRow({ row, index }) {
  const isReachable = !!row.href;
  const titleText = browseFormatTitle(row.title);
  return (
    <li className={`bi-row ${isReachable ? "" : "is-pending"}`}>
      {isReachable ? (
        <a href={row.href} className="bi-link">
          <span className="bi-num">{String(index).padStart(2, "0")}</span>
          <div className="bi-body">
            <h4 className="bi-title">{row.kind === "essay" ? <span className="it">{row.title}</span> : <>How to <span className="it">{titleText}</span></>}</h4>
            {row.meta_description ? <p className="bi-dek">{row.meta_description}</p> : null}
          </div>
          <span className="bi-arr">→</span>
        </a>
      ) : (
        <div className="bi-link is-pending-link">
          <span className="bi-num">··</span>
          <div className="bi-body">
            <h4 className="bi-title">How to <span className="it">{titleText}</span></h4>
            <p className="bi-dek bi-pending-note">Generated. Awaiting shelf assignment — visit later.</p>
          </div>
          <span className="bi-arr">·</span>
        </div>
      )}
    </li>
  );
}

/* ---------------- Browse — main composer ---------------- */
function Browse() {
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [activeLane, setActiveLane] = React.useState("all");
  const [activeShelf, setActiveShelf] = React.useState(null);
  const [query, setQuery] = React.useState(() => {
    try { return new URLSearchParams(window.location.search).get("q") || ""; } catch { return ""; }
  });

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      try {
        const all = [];
        let from = 0;
        const pageSize = 1000;
        while (true) {
          const res = await fetch(
            `${BROWSE_SUPABASE_URL}/rest/v1/pages?select=slug,title,meta_description,updated_at&locale=eq.${BROWSE_LOCALE}&status=eq.published&order=title.asc`,
            {
              headers: {
                apikey: BROWSE_SUPABASE_KEY,
                Authorization: `Bearer ${BROWSE_SUPABASE_KEY}`,
                Range: `${from}-${from + pageSize - 1}`,
              },
            }
          );
          if (!res.ok) throw new Error(`Supabase ${res.status}`);
          const batch = await res.json();
          all.push(...batch);
          if (batch.length < pageSize) break;
          from += pageSize;
        }
        if (cancelled) return;
        setRows(all);
        setLoading(false);
      } catch (err) {
        if (cancelled) return;
        setError(err.message);
        setLoading(false);
      }
    }
    load();
    return () => { cancelled = true; };
  }, []);

  const enriched = React.useMemo(() => {
    const base = rows
      .map((r) => {
        const { lane, shelf } = browseParseSlug(r.slug);
        return {
          ...r,
          lane,
          shelf,
          title: r.title || browseTitleFromSlug(r.slug),
          href: r.slug.startsWith("/") ? r.slug : null,
        };
      })
      // Hide hub-level rows (depth < 4 — anything that's only /en/lane/shelf/)
      .filter((r) => !r.href || r.href.split("/").filter(Boolean).length >= 4);
    const curated = BROWSE_LOCALE === "en" ? CURATED_ESSAYS : [];
    return [...curated, ...base];
  }, [rows]);

  const counts = React.useMemo(() => {
    const c = {
      all: enriched.length,
      lane: { all: enriched.length, health: 0, fitness: 0 },
      shelf: { __unshelved: 0 },
    };
    for (const s of SHELVES) c.shelf[s.slug] = 0;
    for (const r of enriched) {
      if (r.lane === "health") c.lane.health += 1;
      else if (r.lane === "fitness") c.lane.fitness += 1;
      if (r.shelf && c.shelf[r.shelf] !== undefined) c.shelf[r.shelf] += 1;
      else if (!r.shelf || !r.lane) c.shelf.__unshelved += 1;
    }
    return c;
  }, [enriched]);

  const filtered = React.useMemo(() => {
    const q = query.trim().toLowerCase();
    return enriched.filter((r) => {
      if (activeLane !== "all" && r.lane !== activeLane) return false;
      if (activeShelf && r.shelf !== activeShelf) return false;
      if (q) {
        const hay = (r.title + " " + (r.meta_description || "") + " " + r.slug).toLowerCase();
        if (!hay.includes(q)) return false;
      }
      return true;
    });
  }, [enriched, activeLane, activeShelf, query]);

  function setLane(lane) {
    setActiveLane(lane);
    setActiveShelf(null);
  }

  return (
    <React.Fragment>
      <BrowseCrumb />
      <BrowseHero total={counts.all} healthCount={counts.lane.health} fitnessCount={counts.lane.fitness} />
      <BrowseToolbar
        query={query}
        setQuery={setQuery}
        activeLane={activeLane}
        setLane={setLane}
        counts={counts.lane}
      />
      <BrowseIndex
        rows={filtered}
        loading={loading}
        error={error}
        activeLane={activeLane}
        activeShelf={activeShelf}
        setShelf={setActiveShelf}
        counts={counts}
        query={query.trim()}
      />
    </React.Fragment>
  );
}

window.Browse = Browse;
