function StoryViewer({ story, onClose }) {
  const [pages, setPages] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [page, setPage] = React.useState(0);

  React.useEffect(() => {
    if (!story) return;
    setLoading(true);
    setPage(0);
    setPages(null);
    const db = window.__db;
    const fs = window.__fs;
    if (!db || !fs || !story.userId || !story.id) { setLoading(false); return; }
    fs.getDoc(fs.doc(db, `users/${story.userId}/stories/${story.id}`))
      .then(snap => {
        if (snap.exists()) {
          const d = snap.data();
          setPages(Array.isArray(d.pages) ? d.pages : []);
        }
      })
      .catch(e => console.warn("Story fetch failed:", e))
      .finally(() => setLoading(false));
  }, [story?.id]);

  if (!story) return null;

  const hue = storyHue(story.id);
  const bg = `linear-gradient(135deg, hsl(${hue},65%,62%), hsl(${(hue+60)%360},70%,45%))`;
  const currentPage = pages && pages[page];
  const totalPages = pages ? pages.length : (story.pages || 0);
  const storyUser = USERS.find(u => u.uid === story.userId) || { uid: story.userId };

  return (
    <>
      <div className="drawer-backdrop" onClick={onClose}/>
      <div className="drawer story-viewer-drawer">
        {/* Header */}
        <header style={{ flexShrink: 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1, minWidth: 0 }}>
            <div style={{ width: 36, height: 36, borderRadius: 8, background: bg, flexShrink: 0 }}/>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontWeight: 600, fontSize: 14, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                {story.title || "Untitled"}
              </div>
              <div style={{ fontSize: 11, color: "var(--ink-4)" }}>
                {story.childName ? `${story.childName} · ` : ""}{story.ageGroup || ""}{story.therapeuticTheme ? ` · ${story.therapeuticTheme}` : ""}
              </div>
            </div>
          </div>
          <div className="spacer"/>
          <button className="btn ghost icon sm" onClick={onClose}><Icon.close size={14}/></button>
        </header>

        {/* Meta bar */}
        <div style={{ flexShrink: 0, padding: "10px 24px", borderBottom: "1px solid var(--border)", display: "flex", gap: 16, alignItems: "center", fontSize: 12 }}>
          <UserCell user={storyUser}/>
          <div className="spacer"/>
          {story.rating > 0 && <span style={{ color: "var(--accent)" }}>{"★".repeat(story.rating)}<span style={{ opacity: .25 }}>{"★".repeat(5 - story.rating)}</span></span>}
          {story.therapeuticTheme && <span className="badge">{story.therapeuticTheme}</span>}
          <span className="muted">{fmtRelative(story.createdAt)}</span>
        </div>

        {/* Body */}
        <div style={{ flex: 1, overflowY: "auto" }}>
          {loading ? (
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "60px 0", justifyContent: "center", color: "var(--ink-4)" }}>
              <Icon.rotate size={16} style={{ animation: "spin 1s linear infinite" }}/>
              <span style={{ fontSize: 13 }}>Loading story…</span>
            </div>
          ) : pages === null ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-4)", fontSize: 13 }}>
              Could not load story pages.
            </div>
          ) : (
            <>
              {/* Page illustration */}
              <div style={{ position: "relative", background: bg, aspectRatio: "16/9" }}>
                {currentPage?.illustrationUrl ? (
                  <img src={currentPage.illustrationUrl} alt=""
                    style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }}/>
                ) : (
                  <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
                    <Icon.book size={40} style={{ opacity: .3, color: "white" }}/>
                  </div>
                )}
                {/* Page indicator overlay */}
                <div style={{ position: "absolute", bottom: 12, right: 14, background: "rgba(0,0,0,.45)", color: "white", fontSize: 11, borderRadius: 20, padding: "3px 10px", fontWeight: 500 }}>
                  {page + 1} / {totalPages}
                </div>
              </div>

              {/* Story text */}
              <div style={{ padding: "24px 28px" }}>
                <p style={{ fontSize: 16, lineHeight: 1.75, color: "var(--ink)", fontFamily: "var(--fraunces)", margin: 0 }}>
                  {currentPage?.text || <span style={{ color: "var(--ink-4)" }}>No text for this page.</span>}
                </p>
              </div>

              {/* Page navigation */}
              {pages.length > 1 && (
                <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "0 28px 28px", justifyContent: "center" }}>
                  <button className="btn sm" onClick={() => setPage(p => Math.max(0, p - 1))} disabled={page === 0}>
                    ← Prev
                  </button>
                  <div style={{ display: "flex", gap: 6 }}>
                    {pages.map((_, i) => (
                      <button key={i} onClick={() => setPage(i)} style={{
                        width: 8, height: 8, borderRadius: "50%", border: "none", cursor: "pointer", padding: 0,
                        background: i === page ? "var(--accent)" : "var(--border-2)",
                        transition: "background .15s",
                      }}/>
                    ))}
                  </div>
                  <button className="btn sm" onClick={() => setPage(p => Math.min(pages.length - 1, p + 1))} disabled={page === pages.length - 1}>
                    Next →
                  </button>
                </div>
              )}
            </>
          )}
        </div>
      </div>
    </>
  );
}

function StorySortTh({ label, col, sort, setSort, align }) {
  const active = sort === col;
  return (
    <th style={{textAlign: align||"left", cursor:"pointer", userSelect:"none", whiteSpace:"nowrap",
                color: active ? "var(--ink)" : "var(--ink-3)"}}
        onClick={() => setSort(col)}>
      {label}
      <span style={{marginLeft:4, fontSize:9, opacity: active ? 1 : 0, transition:"opacity .15s"}}>▼</span>
    </th>
  );
}

function PageStories() {
  const [search, setSearch] = React.useState("");
  const [filterTheme, setFilterTheme] = React.useState("all");
  const [sort, setSort] = React.useState("created");
  const [view, setView] = React.useState("grid");
  const [selectedStory, setSelectedStory] = React.useState(null);

  React.useEffect(() => {
    const handler = e => setSelectedStory(e.detail);
    window.addEventListener("adminOpenStory", handler);
    return () => window.removeEventListener("adminOpenStory", handler);
  }, []);

  const rated = STORIES.filter(s => s.rating > 0);
  const avgRating = rated.length
    ? (rated.reduce((a,s) => a + s.rating, 0) / rated.length).toFixed(1)
    : null;

  const filtered = STORIES.filter(s => {
    const sTheme = (s.therapeuticTheme || s.theme || "").toLowerCase();
    const sKid   = (s.childName || s.kid || "").toLowerCase();
    const sTitle = (s.title || "").toLowerCase();
    const q = search.toLowerCase();
    if (search && !(sTheme.includes(q) || sKid.includes(q) || sTitle.includes(q))) return false;
    if (filterTheme !== "all" && (s.therapeuticTheme || s.theme) !== filterTheme) return false;
    return true;
  }).sort((a, b) => {
    if (sort === "created") return (b.createdAt || "").localeCompare(a.createdAt || "");
    if (sort === "rating")  return (b.rating || 0) - (a.rating || 0);
    if (sort === "stories") return (b.stories || 0) - (a.stories || 0);
    if (sort === "kid")     return (a.childName || "").localeCompare(b.childName || "");
    if (sort === "title")   return (a.title || "").localeCompare(b.title || "");
    if (sort === "theme")   return (a.therapeuticTheme || "").localeCompare(b.therapeuticTheme || "");
    if (sort === "age")     return (a.ageGroup || "").localeCompare(b.ageGroup || "");
    if (sort === "pages")   return (b.pages || 5) - (a.pages || 5);
    return 0;
  }).slice(0, 60);

  return (
    <>
      <StoryViewer story={selectedStory} onClose={() => setSelectedStory(null)}/>
      <div className="page-header">
        <div><h1>Stories</h1><div className="sub">{KPIS.storiesTotal.toLocaleString()} generated all-time · {KPIS.storiesToday.toLocaleString()} today</div></div>
      </div>

      <div className="kpi-grid">
        <KPI label="Today"      value={compact(KPIS.storiesToday)} spark={STORIES_SERIES.slice(-14)} sparkColor="var(--accent)"/>
        <KPI label="All-time"   value={compact(KPIS.storiesTotal)}/>
        <KPI label="Rated"      value={compact(rated.length)} unit=""/>
        <KPI label="Avg rating" value={avgRating || "—"} unit={avgRating ? "★" : ""}/>
        <KPI label="Flagged"    value={MODERATION.length > 0 ? String(MODERATION.length) : "—"}/>
      </div>

      <div className="card">
        <div className="toolbar">
          <div className="input search" style={{flex:1, maxWidth:340}}>
            <Icon.search size={13}/>
            <input placeholder="Search title, theme, kid name…" value={search} onChange={e=>setSearch(e.target.value)}/>
          </div>
          <div className="input">
            <span className="muted">Theme:</span>
            <select value={filterTheme} onChange={e=>setFilterTheme(e.target.value)}>
              <option value="all">All</option>
              {THEMES.map(t=><option key={t} value={t}>{t}</option>)}
            </select>
          </div>
          <div className="spacer"/>
          <div className="seg">
            <button data-active={view==="grid"} onClick={()=>setView("grid")}>Grid</button>
            <button data-active={view==="table"} onClick={()=>setView("table")}>Table</button>
          </div>
        </div>

        {view==="grid" ? (
          <div style={{padding:16, display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(200px,1fr))", gap:14}}>
            {filtered.length === 0 && <div style={{gridColumn:"1/-1"}}><EmptyState icon="book" message="No stories yet" sub="Generated stories will appear here"/></div>}
            {filtered.map(s=><StoryCard key={s.id} story={s} onClick={()=>setSelectedStory(s)}/>)}
          </div>
        ) : (
          <div className="table-wrap">
            <table className="tbl">
              <thead>
                <tr>
                  <StorySortTh label="Title"   col="title"   sort={sort} setSort={setSort}/>
                  <StorySortTh label="Kid"     col="kid"     sort={sort} setSort={setSort}/>
                  <th>User</th>
                  <StorySortTh label="Theme"   col="theme"   sort={sort} setSort={setSort}/>
                  <StorySortTh label="Age"     col="age"     sort={sort} setSort={setSort}/>
                  <StorySortTh label="Pages"   col="pages"   sort={sort} setSort={setSort} align="right"/>
                  <StorySortTh label="Rating"  col="rating"  sort={sort} setSort={setSort}/>
                  <StorySortTh label="Created" col="created" sort={sort} setSort={setSort}/>
                </tr>
              </thead>
              <tbody>
                {filtered.length === 0 && <tr><td colSpan={8}><EmptyState icon="book" message="No stories yet"/></td></tr>}
                {filtered.map(s => {
                  const hue        = storyHue(s.id);
                  const storyTheme = s.therapeuticTheme || s.theme || null;
                  const kid        = s.childName || s.kid || null;
                  const storyUser  = USERS.find(u => u.uid === s.userId) || {uid: s.userId || "?"};
                  const rating     = s.rating || 0;
                  const created    = s.createdAt || s.date;
                  const bg         = `linear-gradient(135deg, hsl(${hue},65%,62%), hsl(${(hue+60)%360},70%,45%))`;
                  return (
                    <tr key={s.id} style={{cursor:"pointer"}} onClick={()=>setSelectedStory(s)}>
                      <td><div style={{display:"flex", alignItems:"center", gap:8}}>
                        <div style={{width:24, height:24, borderRadius:4, background:bg, flexShrink:0}}/>
                        <span style={{fontWeight:500}}>{s.title || "Untitled"}</span>
                      </div></td>
                      <td>{kid || <span className="muted">—</span>}</td>
                      <td><UserCell user={storyUser}/></td>
                      <td>{storyTheme ? <span className="badge">{storyTheme}</span> : <span className="muted">—</span>}</td>
                      <td className="muted">{s.ageGroup || "—"}</td>
                      <td className="num">{s.pages || 5}</td>
                      <td style={{color:"var(--accent)", letterSpacing:1}}>
                        {rating > 0
                          ? <>{"★".repeat(rating)}<span style={{opacity:.25}}>{"★".repeat(5-rating)}</span></>
                          : <span className="muted">—</span>}
                      </td>
                      <td className="muted">{fmtRelative(created)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            <div style={{padding:"10px 14px", fontSize:12, color:"var(--ink-3)", borderTop:"1px solid var(--border)"}}>
              Showing {filtered.length} of {KPIS.storiesTotal.toLocaleString()} stories
            </div>
          </div>
        )}
      </div>
    </>
  );
}

window.PageStories = PageStories;
