/* ============================================================
   CONSUMER PAGES — Article, Category, Login, Bookmarks, Account
   window: Article, Category, Login, Bookmarks, Account
   ============================================================ */
(function () {
  const { useApp, H, Icon, ArticleCard, ImgPH, MediaFrame, Views, ReactionBar } = window;

  const HTML_RX = /<\/?[a-z][\s\S]*?>/i;

  /* ---------------- Article detail ----------------
     The list/featured endpoints return summaries (no body), so when the user
     opens an article we fetch the full detail. We keep the summary as a fast
     placeholder, then merge the body+media when the detail arrives.        */
  function Article({ id }) {
    const app = useApp();
    const summary = app.state.articles.find(x => x.id === id) || null;
    const [detail, setDetail] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const viewedRef = React.useRef(false);

    React.useEffect(() => {
      let cancelled = false;
      setLoading(true);
      setDetail(null);
      window.API.publicArticles.detail(id)
        .then(d => {
          if (cancelled) return;
          // mapArticle normalises field names (titleBn → bn, etc).
          const mapped = window.AppStore && window.AppStore.mapDetail ? window.AppStore.mapDetail(d) : d;
          setDetail(mapped);
          // the list endpoints carry no reaction counts; the detail DTO does —
          // push them into articleState so ReactionBar shows persisted counts
          app.syncArticleState(id, { views: mapped.views, reactions: mapped.reactions });
        })
        .catch(() => { /* leave detail null; we render the summary fallback */ })
        .finally(() => { if (!cancelled) setLoading(false); });
      return () => { cancelled = true; };
    }, [id]);

    React.useEffect(() => {
      if (!viewedRef.current && (detail || summary)) {
        viewedRef.current = true;
        app.addView(id);
      }
    }, [id, detail, summary]);

    const a = detail || summary;
    if (!a && loading) return <div className="wrap" style={{ padding: 80, textAlign: "center" }}><p className="muted">{H.t("loading")}</p></div>;
    if (!a) return <div className="wrap" style={{ padding: 80, textAlign: "center" }}><p className="muted">{H.t("notFound")}</p></div>;

    const st = app.state.articleState[a.id] || { views: a.views || 0 };
    const cat = H.catBy(a.cat);
    const marked = app.state.bookmarks.includes(a.id);
    const related = app.state.articles.filter(x => x.cat === a.cat && x.id !== a.id).slice(0, 3);
    const more = app.state.articles.filter(x => x.id !== a.id).slice(0, 4);
    const en = app.state.lang === "en";
    const primaryBody   = (en ? a.body_en : a.body_bn) || "";
    const secondaryBody = (en ? a.body_bn : a.body_en) || "";
    const body = primaryBody.trim() ? primaryBody : secondaryBody;
    const fellBack = !primaryBody.trim() && !!secondaryBody.trim();
    const isHtmlBody = HTML_RX.test(body);
    const plainParas = (!isHtmlBody && body) ? body.split("\n\n") : [];
    // Summary-only articles (feeds that ship 1-2 sentences and extraction
    // failed): the body just duplicates the excerpt, so we suppress it and
    // point readers at the source instead. bodySource comes from the backend;
    // the string comparison covers articles ingested before that field existed.
    const excerptText = (H.pick(a, "excerpt") || "").trim();
    const isSummaryOnly = a.bodySource === "summary" ||
                          (!!body && !isHtmlBody && body.trim() === excerptText);
    const showBody = !!body && !isSummaryOnly;

    return (
      <div className="fade-in">
        <div className="wrap" style={{ maxWidth: 1100 }}>
          <div style={{ display: "grid", gridTemplateColumns: "minmax(0,1fr) 300px", gap: 44, paddingTop: 30 }} className="art-grid">
            <article>
              {/* breadcrumb */}
              <div className="meta" style={{ marginBottom: 16 }}>
                <button onClick={() => app.nav("home")} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--ink-3)", padding: 0 }}>{H.t("home")}</button>
                <Icon name="chevR" size={13} />
                <button onClick={() => app.nav("category", { slug: a.cat })} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--accent-ink)", padding: 0, fontWeight: 600 }}>{H.pick(cat, "label")}</button>
              </div>

              {a.source === "rss" && <span className="badge gray" style={{ marginBottom: 12, display: "inline-flex", alignItems: "center", gap: 5 }}><Icon name="rss" size={11} /> {H.t("source")}: {a.feed}</span>}

              <h1 className="serif" style={{ fontSize: "clamp(30px,4vw,46px)", fontWeight: 700, lineHeight: 1.12, margin: "6px 0 16px" }}>{H.pick(a, "title")}</h1>
              <p className="ink2" style={{ fontSize: "clamp(17px,1.8vw,20px)", lineHeight: 1.55, marginBottom: 22, fontFamily: "var(--font-head)" }}>{H.pick(a, "excerpt")}</p>

              {/* byline */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 12, borderTop: "1px solid var(--line)", borderBottom: "1px solid var(--line)", padding: "14px 0", marginBottom: 24 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
                  <span style={{ width: 40, height: 40, borderRadius: "50%", background: "var(--surface-2)", border: "1px solid var(--line)", display: "grid", placeItems: "center", fontWeight: 700, color: "var(--ink-2)" }}>{H.pick(a, "author").charAt(0)}</span>
                  <div>
                    <div style={{ fontWeight: 700, fontSize: 14.5 }}>{H.pick(a, "author")}</div>
                    <div className="meta" style={{ fontSize: 12.5 }}>{H.rel(a.ts)}<span className="dot" />{H.num(a.mins)} {H.t("minRead")}<span className="dot" /><Views n={st.views} /></div>
                  </div>
                </div>
                <div style={{ display: "flex", gap: 8 }}>
                  <button className="btn sm" data-active={marked} onClick={() => app.toggleBookmark(a.id)}
                    style={marked ? { borderColor: "var(--accent)", color: "var(--accent-ink)", background: "var(--accent-wash)" } : null}>
                    <Icon name="bookmark" size={15} fill={marked} /> {marked ? H.t("saved") : H.t("save")}
                  </button>
                  <button className="btn sm" onClick={() => app.toast(H.t("linkCopied"))}><Icon name="share" size={15} /></button>
                </div>
              </div>

              {/* hero media (image, video, embed, or audio) */}
              <figure style={{ margin: "0 0 26px" }}>
                <MediaFrame
                  kind={a.mediaKind || "image"}
                  url={a.mediaUrl || a.img}
                  thumbnail={a.mediaThumbnail || a.img}
                  mime={a.mediaMime}
                  label={H.pick(a, "title")}
                  style={{ width: "100%", aspectRatio: "16/9", borderRadius: "var(--radius)" }} />
                <figcaption className="muted" style={{ fontSize: 12.5, marginTop: 8, paddingRight: 4 }}>{H.t("imageCaption")}</figcaption>
              </figure>

              {/* body */}
              <div className="article-body" style={{ fontFamily: "var(--font-head)", fontSize: 19, lineHeight: 1.78, color: "var(--ink)" }}>
                {fellBack && showBody && (
                  <p className="muted" style={{ fontSize: 12.5, marginBottom: 14, fontStyle: "italic" }}>
                    {en ? "Source language: Bengali" : "উৎস ভাষা: ইংরেজি"}
                  </p>
                )}
                {!body && loading && (
                  <p className="muted" style={{ fontStyle: "italic" }}>{H.t("loading")}</p>
                )}
                {!showBody && !loading && !a.sourceLink && !isSummaryOnly && (
                  <p className="muted" style={{ fontStyle: "italic" }}>{en ? "Full story not available." : "সম্পূর্ণ প্রতিবেদন পাওয়া যায়নি।"}</p>
                )}
                {showBody && isHtmlBody && (
                  <div className="article-content article-body-html" dangerouslySetInnerHTML={{ __html: body }} />
                )}
                {showBody && !isHtmlBody && (
                  <div className="article-content">
                    {plainParas.map((p, idx) => (
                      <p key={idx} style={{ marginBottom: 22 }}>{p}</p>
                    ))}
                  </div>
                )}
                {!showBody && !loading && a.sourceLink && (
                  <div className="source-cta">
                    <p className="muted" style={{ marginBottom: 12 }}>
                      {en ? "Only a summary of this story is available here." : "এখানে এই প্রতিবেদনের শুধু সারসংক্ষেপ পাওয়া যাচ্ছে।"}
                    </p>
                    <a className="btn primary" href={a.sourceLink} target="_blank" rel="noopener noreferrer"
                       style={{ display: "inline-flex", alignItems: "center", gap: 7, textDecoration: "none" }}>
                      <Icon name="rss" size={14} />
                      {en ? `Read the full article at ${a.feed || "the source"}` : `${a.feed || "উৎস"}-এ সম্পূর্ণ প্রতিবেদন পড়ুন`}
                    </a>
                  </div>
                )}
              </div>

              {/* reactions */}
              <div style={{ borderTop: "1px solid var(--line)", borderBottom: "1px solid var(--line)", padding: "22px 0", margin: "30px 0", display: "flex", flexDirection: "column", gap: 14 }}>
                <span className="kicker">{H.t("yourReaction")}</span>
                <ReactionBar a={a} />
              </div>

              {/* related */}
              <h3 className="serif nowrap" style={{ fontSize: 22, fontWeight: 700, borderBottom: "2px solid var(--ink)", paddingBottom: 10, marginBottom: 18 }}>{H.t("related")}</h3>
              <div style={{ display: "grid", gap: 18 }}>
                {related.map(r => <ArticleCard key={r.id} a={r} size="row" />)}
              </div>
            </article>

            {/* sidebar */}
            <aside>
              <div style={{ position: "sticky", top: 168 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, borderBottom: "2px solid var(--accent)", paddingBottom: 9 }}>
                  <Icon name="bolt" size={15} fill style={{ color: "var(--accent)" }} />
                  <h3 className="serif nowrap" style={{ fontSize: 18, fontWeight: 700 }}>{H.t("readMore")}</h3>
                </div>
                {more.map(m => (
                  <div key={m.id} style={{ borderBottom: "1px solid var(--line-2)", padding: "13px 0" }}>
                    <ArticleCard a={m} size="mini" />
                  </div>
                ))}
              </div>
            </aside>
          </div>
        </div>
      </div>
    );
  }

  /* ---------------- Category page ---------------- */
  function Category({ slug }) {
    const app = useApp();
    const cat = H.catBy(slug);
    const [sort, setSort] = React.useState("new");
    let list = app.state.articles.filter(a => a.cat === slug);
    if (sort === "new") list = [...list].sort((a, b) => b.ts - a.ts);
    else list = [...list].sort((a, b) => ((app.state.articleState[b.id] || {}).views || 0) - ((app.state.articleState[a.id] || {}).views || 0));
    const lead = list[0], rest = list.slice(1);

    return (
      <div className="fade-in wrap" style={{ paddingTop: 30 }}>
        <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", flexWrap: "wrap", gap: 16, borderBottom: "2px solid var(--ink)", paddingBottom: 16, marginBottom: 26 }}>
          <div>
            <div className="kicker" style={{ marginBottom: 6 }}>{app.state.lang === "en" ? cat.bn : cat.en}</div>
            <h1 className="serif" style={{ fontSize: "clamp(34px,5vw,52px)", fontWeight: 700 }}>{H.pick(cat, "label")}</h1>
          </div>
          <div style={{ display: "flex", gap: 6, background: "var(--surface-2)", padding: 4, borderRadius: 999, border: "1px solid var(--line)" }}>
            {[["new", H.t("sortNew")], ["top", H.t("sortTop")]].map(([k, l]) => (
              <button key={k} onClick={() => setSort(k)}
                style={{ border: 0, padding: "7px 16px", borderRadius: 999, cursor: "pointer", fontSize: 13.5, fontWeight: 600,
                  background: sort === k ? "var(--surface)" : "transparent", color: sort === k ? "var(--accent-ink)" : "var(--ink-3)", boxShadow: sort === k ? "var(--shadow-1)" : "none" }}>{l}</button>
            ))}
          </div>
        </div>

        {!list.length ? <p className="muted" style={{ padding: 60, textAlign: "center" }}>{H.t("noCategoryNews")}</p> : (
          <div style={{ display: "grid", gridTemplateColumns: "1.6fr 320px", gap: "var(--gap)" }} className="cat-page">
            <div>
              <div style={{ marginBottom: 28, paddingBottom: 28, borderBottom: "1px solid var(--line)" }}><ArticleCard a={lead} size="lead" /></div>
              <div style={{ display: "grid", gap: 24 }}>
                {rest.map(a => <ArticleCard key={a.id} a={a} size="row" />)}
              </div>
            </div>
            <aside>
              <div style={{ position: "sticky", top: 168, background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--radius)", padding: 20 }}>
                <div className="kicker" style={{ marginBottom: 12 }}>{H.pick(cat, "label")}</div>
                <p className="ink2" style={{ fontSize: 14, lineHeight: 1.6 }}>{H.t("catLabel", cat)}</p>
                <div style={{ marginTop: 16, paddingTop: 16, borderTop: "1px solid var(--line)", display: "flex", justifyContent: "space-between" }}>
                  <span className="muted" style={{ fontSize: 13 }}>{H.t("totalNews")}</span>
                  <span className="serif" style={{ fontWeight: 700 }}>{H.num(list.length)}</span>
                </div>
              </div>
            </aside>
          </div>
        )}
      </div>
    );
  }

  /* ---------------- Login / Signup ---------------- */
  function Login() {
    const app = useApp();
    const [mode, setMode] = React.useState("login");
    const [name, setName] = React.useState("");
    const [email, setEmail] = React.useState("");
    const [pw, setPw] = React.useState("");
    const submit = async (e) => {
      e.preventDefault();
      try {
        await app.login(mode === "signup" ? name : (name || "পাঠক"),
                        email || "reader@example.com",
                        pw || "probhat_demo",
                        mode);
        app.nav("home");
      } catch (_) { /* toast shown by store */ }
    };
    return (
      <div className="fade-in" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", minHeight: "calc(100vh - 156px)" }}>
        <div className="login-art" style={{ background: "var(--ink)", color: "var(--bg)", padding: "60px 56px", display: "flex", flexDirection: "column", justifyContent: "space-between", position: "relative", overflow: "hidden" }}>
          <div style={{ position: "absolute", inset: 0, opacity: .5, background: "repeating-linear-gradient(-45deg, transparent, transparent 16px, oklch(1 0 0 / 0.03) 16px, oklch(1 0 0 / 0.03) 17px)" }} />
          <div className="serif" style={{ fontSize: 32, fontWeight: 700, position: "relative" }}>{app.state.lang === "en" ? "Probhat" : "প্রভাত"}<span style={{ color: "var(--accent)" }}>.</span></div>
          <div style={{ position: "relative" }}>
            <h2 className="serif" style={{ fontSize: 38, fontWeight: 700, lineHeight: 1.15, marginBottom: 16 }}>{app.state.lang === "en" ? <>Read. React.<br />Save.</> : <>পড়ুন। প্রতিক্রিয়া দিন।<br />সংরক্ষণ করুন।</>}</h2>
            <p style={{ opacity: .8, fontSize: 16, lineHeight: 1.6, maxWidth: 360 }}>{app.state.lang === "en" ? "Create an account to save your favourite stories, react, and get news tuned to your interests." : "একটি অ্যাকাউন্ট খুলে প্রিয় সংবাদ সংরক্ষণ করুন, প্রতিক্রিয়া জানান এবং নিজের পছন্দ অনুযায়ী খবর পান।"}</p>
          </div>
          <div className="muted" style={{ position: "relative", color: "rgba(255,255,255,.5)", fontSize: 12.5 }}>© {H.num(2026)} {app.state.lang === "en" ? "Probhat" : "প্রভাত"}</div>
        </div>
        <div style={{ display: "grid", placeItems: "center", padding: "40px 24px" }}>
          <form onSubmit={submit} style={{ width: "min(380px,100%)" }}>
            <h1 className="serif" style={{ fontSize: 30, fontWeight: 700, marginBottom: 6 }}>{mode === "login" ? H.t("welcomeBack") : H.t("newAccount")}</h1>
            <p className="muted" style={{ fontSize: 14, marginBottom: 26 }}>{mode === "login" ? H.t("loginSubtitle") : H.t("signupSubtitle")}</p>
            <div style={{ display: "grid", gap: 16 }}>
              {mode === "signup" && (
                <label className="field"><span className="lbl">{H.t("fullName")}</span>
                  <input value={name} onChange={e => setName(e.target.value)} placeholder={app.state.lang === "en" ? "Your name" : "আপনার নাম"} /></label>
              )}
              <label className="field"><span className="lbl">{H.t("email")}</span>
                <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="you@example.com" /></label>
              <label className="field"><span className="lbl">{H.t("password")}</span>
                <input type="password" value={pw} onChange={e => setPw(e.target.value)} placeholder="••••••••" /></label>
              <button className="btn primary" type="submit" style={{ justifyContent: "center", padding: "12px", fontSize: 15 }}>
                {mode === "login" ? H.t("loginBtn") : H.t("signupBtn")}
              </button>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 12, margin: "20px 0", color: "var(--ink-3)", fontSize: 12 }}>
              <span style={{ flex: 1, height: 1, background: "var(--line)" }} />{H.t("or")}<span style={{ flex: 1, height: 1, background: "var(--line)" }} />
            </div>
            <button type="button" className="btn" onClick={async () => { try { await app.login(app.state.lang === "en" ? "Guest Reader" : "অতিথি পাঠক", "guest" + Date.now() + "@probhat.local", "probhat_demo", "signup"); app.nav("home"); } catch (_) {} }} style={{ width: "100%", justifyContent: "center", padding: "11px" }}>{H.t("continueAsGuest")}</button>
            <p className="muted" style={{ fontSize: 13.5, textAlign: "center", marginTop: 22 }}>
              {mode === "login" ? H.t("noAccount") + " " : H.t("haveAccount") + " "}
              <button type="button" onClick={() => setMode(mode === "login" ? "signup" : "login")} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--accent-ink)", fontWeight: 700, fontSize: 13.5 }}>
                {mode === "login" ? H.t("register") : H.t("login")}
              </button>
            </p>
          </form>
        </div>
      </div>
    );
  }

  /* ---------------- Bookmarks ---------------- */
  function Bookmarks() {
    const app = useApp();
    const list = app.state.bookmarks.map(id => app.state.articles.find(a => a.id === id)).filter(Boolean);
    return (
      <div className="fade-in wrap" style={{ paddingTop: 30, minHeight: "50vh" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, borderBottom: "2px solid var(--ink)", paddingBottom: 16, marginBottom: 26 }}>
          <Icon name="bookmark" size={22} fill style={{ color: "var(--accent)" }} />
          <h1 className="serif" style={{ fontSize: "clamp(28px,4vw,40px)", fontWeight: 700 }}>{H.t("bookmarks")}</h1>
          <span className="chip" style={{ marginRight: 6 }}>{H.num(list.length)}</span>
        </div>
        {!list.length ? (
          <div style={{ textAlign: "center", padding: "70px 20px" }}>
            <div style={{ display: "inline-grid", placeItems: "center", width: 64, height: 64, borderRadius: "50%", background: "var(--surface-2)", marginBottom: 16, color: "var(--ink-3)" }}><Icon name="bookmark" size={28} /></div>
            <p className="serif" style={{ fontSize: 20, marginBottom: 8 }}>{H.t("noBookmarks")}</p>
            <p className="muted" style={{ marginBottom: 20 }}>{H.t("bookmarkHint")}</p>
            <button className="btn primary" onClick={() => app.nav("home")}>{H.t("readNews")}</button>
          </div>
        ) : (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(300px,1fr))", gap: "var(--gap)" }}>
            {list.map(a => <ArticleCard key={a.id} a={a} size="tall" />)}
          </div>
        )}
      </div>
    );
  }

  /* ---------------- Account ---------------- */
  function Account() {
    const app = useApp();
    const u = app.state.user;
    if (!u) { app.nav("login"); return null; }
    const reactCount = Object.keys(app.state.myReactions).length;
    return (
      <div className="fade-in wrap" style={{ paddingTop: 40, maxWidth: 760, minHeight: "50vh" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 18, marginBottom: 30 }}>
          <span style={{ width: 64, height: 64, borderRadius: "50%", background: "var(--accent)", color: "#fff", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 28 }}>{u.initials}</span>
          <div>
            <h1 className="serif" style={{ fontSize: 28, fontWeight: 700 }}>{u.name}</h1>
            <p className="muted">{u.email}</p>
          </div>
          <button className="btn danger sm" style={{ marginRight: "auto" }} onClick={() => { app.logout(); app.nav("home"); }}><Icon name="logout" size={15} /> {H.t("logout")}</button>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 16, marginBottom: 30 }}>
          {[[H.t("bookmarks"), app.state.bookmarks.length], [H.t("reactions"), reactCount], [H.t("read"), 12]].map(([l, v]) => (
            <div key={l} style={{ background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--radius)", padding: "22px 18px", textAlign: "center" }}>
              <div className="serif" style={{ fontSize: 34, fontWeight: 700, color: "var(--accent-ink)" }}>{H.num(v)}</div>
              <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>{l}</div>
            </div>
          ))}
        </div>
        <button className="btn" onClick={() => app.nav("bookmarks")} style={{ width: "100%", justifyContent: "space-between", padding: "16px 18px" }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 10 }}><Icon name="bookmark" size={17} /> {H.t("backToBookmarks")}</span><Icon name="chevR" size={16} />
        </button>
      </div>
    );
  }

  /* ---------------- Static org pages (about/contact/…) ---------------- */
  function StaticPage({ slug }) {
    const app = useApp();
    const p = (window.SEED.ORG_PAGES || []).find(x => x.slug === slug);
    if (!p) {
      return (
        <div className="fade-in wrap" style={{ paddingTop: 30, minHeight: "50vh", textAlign: "center" }}>
          <p className="serif" style={{ fontSize: 20, margin: "70px 0 20px" }}>{H.t("notFound")}</p>
          <button className="btn primary" onClick={() => app.nav("home")}>{H.t("home")}</button>
        </div>
      );
    }
    const body = app.state.lang === "en" ? (p.body_en || p.body_bn) : (p.body_bn || p.body_en);
    return (
      <div className="fade-in wrap" style={{ paddingTop: 30, maxWidth: 760, minHeight: "50vh" }}>
        <div style={{ borderBottom: "2px solid var(--ink)", paddingBottom: 16, marginBottom: 26 }}>
          <h1 className="serif" style={{ fontSize: "clamp(28px,4vw,40px)", fontWeight: 700 }}>{H.pick(p, "label")}</h1>
        </div>
        {body.split(/\n\n+/).map((para, i) => (
          <p key={i} className="ink2" style={{ fontSize: 16, lineHeight: 1.7, marginBottom: 18, whiteSpace: "pre-line" }}>{para}</p>
        ))}
      </div>
    );
  }

  Object.assign(window, { Article, Category, Login, Bookmarks, Account, StaticPage });
})();
