function fmtInline(s) {
  let h = String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  h = h.replace(/&lt;(\/?)(b|strong|i|em|mark|u)&gt;/gi, "<$1$2>");
  h = h.replace(/&lt;br\s*\/?&gt;/gi, "<br/>");
  h = h.replace(/&lt;a href="(https?:\/\/[^"]*|\/[^"]*)"&gt;/gi, '<a href="$1" target="_blank" rel="noopener noreferrer">');
  h = h.replace(/&lt;\/a&gt;/gi, "</a>");
  return h;
}
/* ============================================================
   COMMONS — Read (stories) — uniform card feed, pure text
   ============================================================ */

function Read({ go }) {
  const feat = ARTICLES.find(a => a.feat);
  const ordered = feat ? [feat, ...ARTICLES.filter(a => !a.feat)] : ARTICLES.slice();

  return (
    <div className="view read">
      <section className="comm-banner">
        <div className="shell comm-banner-inner">
          <div>
            <h1 className="comm-title serif" style={{ "--i": 0 }}>Stories worth <span className="italic">keeping</span>.</h1>
            <p className="read-mast-sub" style={{ "--i": 1, margin: "10px 0 0", textAlign: "left" }}>Essays, history and honest profiles on Punjabi life — at home and away.</p>
          </div>
          <button className="btn btn-primary comm-new" style={{ "--i": 2 }} onClick={() => go("write")}><Icon name="plus" size={16} /> Write a story</button>
        </div>
      </section>

      <div className="shell">
        <div style={{ maxWidth: 820, margin: "24px auto 0", display: "grid", gap: 16 }}>
          {ordered.map((a, i) => (
            <article key={a.id} className="lead" style={{ display: "block", padding: "28px 32px", "--i": i }} onClick={() => go("read/" + a.id)}>
              <div className="lead-copy" style={{ padding: 0 }}>
                <span className="kicker">{a.kicker} · {a.date}{a.feat ? " · Featured" : ""}</span>
                <h2 className="lead-title serif">{a.title}</h2>
                <p className="lead-dek">{a.dek}</p>
                <div className="byline">
                  <Avatar seed={a.authorU} label={a.author} size={32} />
                  <span><b>{a.author}</b><i>{a.date} · {a.read} read</i></span>
                </div>
                <span className="lead-link">Read the story <Icon name="arrowRight" size={16} /></span>
              </div>
            </article>
          ))}
          {ordered.length === 0 && (
            <div className="pf-empty">
              <Icon name="book" size={28} />
              <b className="serif">No stories yet</b>
              <p>Be the first to write for the diaspora.</p>
              <button className="btn btn-primary" onClick={() => go("write")}>Write a story</button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ---------- Story composer (text only) + edit mode ---------- */
function StoryCompose({ go, editId }) {
  const user = (typeof window !== "undefined" && window.__USER__) || null;
  const editing = editId ? ((typeof ARTICLES !== "undefined" ? ARTICLES : []).find(a => a.id === editId) || null) : null;
  const [title, setTitle] = useState(editing ? editing.title : "");
  const [cat, setCat] = useState(editing ? (editing.cat || editing.kicker || "Story") : "Story");
  const [dek, setDek] = useState(editing ? (editing.dek || "") : "");
  const [body, setBody] = useState(editing ? ((editing.body && editing.body.length) ? editing.body.join("\n\n") : "") : "");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const cats = ["Story", "History", "Culture", "Guide", "Profile", "Opinion", "Music", "Food"];

  if (!user) {
    return (
      <div className="view reader">
        <div className="shell reader-shell">
          <div className="pf-empty" style={{ marginTop: 80 }}>
            <Icon name="book" size={28} />
            <b className="serif">Sign in to write</b>
            <p>Log in to publish a story for the diaspora.</p>
            <button className="btn btn-primary" onClick={() => document.dispatchEvent(new CustomEvent("ipanjab:auth"))}>Log in</button>
          </div>
        </div>
      </div>
    );
  }

  const publish = async () => {
    if (busy) return;
    if (!title.trim() || !body.trim()) { setErr("A title and some words are needed."); return; }
    setBusy(true); setErr("");
    try {
      const url = editing ? "/api/articles/update" : "/api/articles";
      const payload = editing ? { id: editing._id, title: title.trim(), tag: cat, excerpt: dek.trim(), body: body.trim() } : { title: title.trim(), tag: cat, excerpt: dek.trim(), body: body.trim() };
      const r = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) });
      const j = await r.json().catch(() => ({}));
      if (r.ok) { location.hash = editing ? ("/read/" + editing.id) : "/read"; location.reload(); }
      else { setErr(j.error || "Could not save."); setBusy(false); }
    } catch (_) { setErr("Network error — please try again."); setBusy(false); }
  };

  const lab = { fontWeight: 600, fontSize: 14, color: "var(--ink)" };
  return (
    <div className="view reader">
      <div className="shell reader-shell" style={{ paddingTop: 8 }}>
        <button className="back" onClick={() => go(editing ? ("read/" + editing.id) : "read")}><Icon name="arrowLeft" size={16} /> Stories</button>
        <span className="kicker">{editing ? "Editing your story" : "Write for iPanjab"}</span>
        <h1 className="reader-title serif" style={{ marginTop: 6 }}>{editing ? "Edit your story." : "Tell a story."}</h1>
        <div style={{ display: "grid", gap: 18, marginTop: 26 }}>
          <label style={{ display: "grid", gap: 8 }}><span style={lab}>Title</span>
            <input className="auth-input" placeholder="A headline worth the read" value={title} onChange={e => setTitle(e.target.value)} /></label>
          <div style={{ display: "grid", gap: 8 }}><span style={lab}>Category</span>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>{cats.map(c => <button key={c} className="chip" data-on={cat === c} onClick={() => setCat(c)}>{c}</button>)}</div></div>
          <label style={{ display: "grid", gap: 8 }}><span style={lab}>Summary</span>
            <input className="auth-input" placeholder="One line shown in the story list" value={dek} onChange={e => setDek(e.target.value)} /></label>
          <label style={{ display: "grid", gap: 8 }}><span style={lab}>Story <span style={{ color: "var(--ink-faint)", fontWeight: 400 }}>· blank line = new paragraph; &lt;b&gt; and &lt;mark&gt; supported</span></span>
            <textarea className="auth-input" style={{ minHeight: 320, resize: "vertical", lineHeight: 1.65 }} placeholder="Write your story…" value={body} onChange={e => setBody(e.target.value)} /></label>
          {err && <div className="auth-err">{err}</div>}
          <div><button className="btn btn-primary" data-dim={busy} onClick={publish}><Icon name="check" size={16} /> {busy ? "Saving…" : (editing ? "Save changes" : "Publish story")}</button></div>
        </div>
      </div>
    </div>
  );
}

/* ---------- Reader (text only) ---------- */
function Reader({ id, go }) {
  const a = ARTICLES.find(x => x.id === id) || ARTICLES[0];
  const user = (typeof window !== "undefined" && window.__USER__) || null;
  const [progress, setProgress] = useState(0);
  const [liked, setLiked] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const onScroll = () => {
      const el = ref.current; if (!el) return;
      const total = el.offsetHeight - window.innerHeight;
      const passed = Math.min(1, Math.max(0, (window.scrollY - el.offsetTop + 120) / Math.max(1, total)));
      setProgress(passed);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, [id]);
  const more = ARTICLES.filter(x => x.id !== a.id).slice(0, 2);
  const people = (typeof window !== "undefined" && window.__DATA__ && window.__DATA__.people) || [];
  const authorP = people.find(x => x.name === a.author);
  const goAuthor = authorP ? () => go("profile/u" + authorP.id) : null;
  const aLink = goAuthor ? { cursor: "pointer" } : null;
  const share = (typeof shareThing === "function") ? () => shareThing("read/" + a.id, a.title) : undefined;
  const isOwner = !!(user && (a.authorId != null && String(a.authorId) === String(user.id) || (a.author && user.name && a.author === user.name) || user.isAdmin));
  const delStory = async () => {
    if (!window.confirm("Delete this story? This cannot be undone.")) return;
    try {
      const r = await fetch("/api/articles/delete", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: a._id }) });
      if (r.ok) { location.hash = "/read"; location.reload(); } else { alert("Could not delete."); }
    } catch (_) { alert("Network error."); }
  };

  return (
    <div className="view reader" ref={ref}>
      <div className="read-progress" style={{ transform: `scaleX(${progress})` }} />
      <div className="shell reader-shell">
        <button className="back" onClick={() => go("read")}><Icon name="arrowLeft" size={16} /> Stories</button>
        <header className="reader-head">
          <span className="kicker">{a.kicker} · {a.cat}</span>
          <h1 className="reader-title serif">{a.title}</h1>
          <p className="reader-dek serif">{a.dek}</p>
          <div className="reader-byline">
            <span onClick={goAuthor || undefined} style={aLink}><Avatar seed={a.authorU} label={a.author} size={42} /></span>
            <div className="reader-by-txt">
              <b onClick={goAuthor || undefined} style={aLink}>{a.author}</b>
              <span>{a.date} · {a.read} read</span>
            </div>
            <div className="reader-actions">
              {isOwner && <button className="icon-pill" aria-label="Edit story" title="Edit" onClick={() => go("write/" + a.id)}><Icon name="edit" size={18} /></button>}
              {isOwner && <button className="icon-pill" aria-label="Delete story" title="Delete" onClick={delStory}><Icon name="x" size={18} /></button>}
              <button className={"icon-pill" + (liked ? " on" : "")} onClick={() => setLiked(!liked)} aria-label="Like"><Icon name="heart" size={18} /></button>
              <button className="icon-pill" aria-label="Share" onClick={share}><Icon name="share" size={18} /></button>
            </div>
          </div>
        </header>
        <article className="prose" style={{ marginTop: 30 }}>
          {((a.body && a.body.length) ? a.body : ARTICLE_BODY).map((p, i) => (
            <p key={i} className={i === 0 ? "lede" : ""} dangerouslySetInnerHTML={{ __html: fmtInline(p) }} />
          ))}
        </article>

        <div className="reader-foot surface">
          <div className="byline">
            <span onClick={goAuthor || undefined} style={aLink}><Avatar seed={a.authorU} label={a.author} size={48} /></span>
            <span><b onClick={goAuthor || undefined} style={aLink}>{a.author}{vTick(a.author)}</b><i>Writes about people and the places that hold them.</i></span>
          </div>
          <FollowButton name={a.author} />
        </div>

        <div className="section-head" style={{ marginTop: 52 }}>
          <h2 className="serif">Keep reading</h2>
        </div>
        <div style={{ display: "grid", gap: 16 }}>
          {more.map((m, i) => (
            <article key={m.id} className="lead" style={{ display: "block", padding: "24px 28px", "--i": i }} onClick={() => { window.scrollTo(0, 0); go("read/" + m.id); }}>
              <div className="lead-copy" style={{ padding: 0 }}>
                <span className="kicker">{m.kicker} · {m.date}</span>
                <h2 className="lead-title serif">{m.title}</h2>
                <p className="lead-dek">{m.dek}</p>
                <div className="byline sm"><Avatar seed={m.authorU} label={m.author} size={24} /><span><b>{m.author}</b><i>{m.read} read</i></span></div>
              </div>
            </article>
          ))}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Read, Reader, StoryCompose });
