// transmissions.jsx — in-character blog/journal from the raven.
// Mix of short numbered transmissions + occasional longer essays.
// Data source: Supabase table `public.diaval_transmissions` (RLS: anon reads is_published only).

// per-transmission deterministic mini-podcast duration
function memoDuration(n) {
  const seed = parseInt(n, 10) || 1;
  const total = 60 + ((seed * 37) % 200); // 60–260s
  return total;
}
function fmtTime(s) {
  s = Math.max(0, Math.floor(s));
  return `${Math.floor(s/60)}:${String(s%60).padStart(2,"0")}`;
}

// (TransmissionVoiceMemo removed — replaced by shared VoicePlayer in shared.jsx)

function TransmissionsPage({ tab, onTabChange }) {
  const S = window.shellStyles;
  const { isMobile } = (window.useViewport ? window.useViewport() : { isMobile: false });
  const [open, setOpen] = React.useState(null);
  const [filter, setFilter] = React.useState("all"); // all | short | essay | video
  const [subscribed, setSubscribed] = React.useState(false);
  const [subscribing, setSubscribing] = React.useState(false);
  const [subscribeError, setSubscribeError] = React.useState(null);
  const [subscribeMessage, setSubscribeMessage] = React.useState(null);
  const [email, setEmail] = React.useState("");
  const [transmissions, setTransmissions] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [loadError, setLoadError] = React.useState(null);

  const handleSubscribe = async (e) => {
    e.preventDefault();
    if (subscribing) return;
    const trimmed = email.trim().toLowerCase();
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
      setSubscribeError("Please enter a valid email."); return;
    }
    setSubscribing(true); setSubscribeError(null); setSubscribeMessage(null);
    try {
      const data = await window.diavalCallFunction("subscribe", { email: trimmed });
      setSubscribed(true);
      setSubscribeMessage(data?.message || "Check your inbox to confirm.");
    } catch (err) {
      setSubscribeError(err.message);
    } finally {
      setSubscribing(false);
    }
  };

  React.useEffect(() => {
    let cancelled = false;
    window.diavalSupabase
      .from("diaval_transmissions")
      .select("id, n, display_date, kind, title, body, read_time, published_at, voice_url, voice_generated_at, video_url, like_count, voice_play_count")
      .eq("is_published", true)
      .order("published_at", { ascending: false })
      .then(({ data, error }) => {
        if (cancelled) return;
        if (error) {
          setLoadError(error.message);
        } else {
          // Map DB rows -> the shape the rest of the page expects.
          setTransmissions(
            (data ?? []).map((r) => ({
              id: r.id,
              n: r.n,
              date: r.display_date,
              published_at: r.published_at,
              kind: r.kind,
              title: r.title,
              body: r.body,
              read: r.read_time,
              voice_url: r.voice_url,
              voice_generated_at: r.voice_generated_at,
              video_url: r.video_url || null,
              like_count: r.like_count || 0,
              voice_play_count: r.voice_play_count || 0,
            }))
          );
        }
        setLoading(false);
      });
    return () => { cancelled = true; };
  }, []);

  const filtered = transmissions.filter((t) => filter === "all" || t.kind === filter);
  const opened = open ? transmissions.find((t) => t.n === open) : null;
  const broadcastLabel = `TRANSMISSIONS · ${String(transmissions.length).padStart(3, "0")} ENTRIES`;

  return (
    <Shell tab={tab} onTabChange={onTabChange} page="004" broadcast={broadcastLabel}>
      <div style={{
        position: isMobile ? "relative" : "absolute",
        inset: isMobile ? "auto" : 0,
        display: isMobile ? "block" : "grid",
        gridTemplateColumns: isMobile ? undefined : "1fr 360px",
        gap: 0,
        overflow: isMobile ? "visible" : "hidden",
      }}>
        {/* main column */}
        <div style={{ overflow: isMobile ? "visible" : "hidden", display: "flex", flexDirection: "column" }}>
          {/* header */}
          <div style={{ padding: isMobile ? "20px 16px 16px" : "32px 56px 20px", borderBottom: `1px solid ${S.concreteHi}` }}>
            <div style={{ fontSize: 12, color: S.bloodHot, letterSpacing: "0.3em", marginBottom: 8 }}>
              // IV. TRANSMISSIONS · FROM THE RAVEN
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", gap: 32 }}>
              <h2 style={{
                margin: 0, fontFamily: S.display, fontSize: isMobile ? 28 : 56, lineHeight: 0.92,
                letterSpacing: "-0.02em", color: S.bone,
              }}>
                NOT A BLOG. <span style={{ color: S.bloodHot }}>A TRANSMISSION.</span>
              </h2>
            </div>
            {/* filter row */}
            <div style={{ marginTop: 24, display: "flex", gap: 0, fontSize: 12, letterSpacing: "0.25em", border: `1px solid ${S.concreteHi}`, alignSelf: "flex-start", width: "fit-content" }}>
              {[
                { k: "all", label: `ALL · ${transmissions.length}` },
                { k: "short", label: `SHORT · ${transmissions.filter(t=>t.kind==="short").length}` },
                { k: "essay", label: `ESSAYS · ${transmissions.filter(t=>t.kind==="essay").length}` },
                { k: "video", label: `VIDEO · ${transmissions.filter(t=>t.kind==="video").length}` },
              ].map((f, i, arr) => (
                <button key={f.k} onClick={() => { setFilter(f.k); setOpen(null); }} style={{
                  padding: "10px 18px", fontFamily: S.meta, color: filter === f.k ? S.bone : S.ash,
                  background: filter === f.k ? S.concrete : "transparent",
                  border: "none", borderRight: i < arr.length - 1 ? `1px solid ${S.concreteHi}` : "none",
                  cursor: "pointer", fontSize: 12, letterSpacing: "0.25em",
                }}>{f.label}</button>
              ))}
            </div>
          </div>

          {/* feed */}
          <div style={{ flex: 1, overflow: isMobile ? "visible" : "auto", padding: isMobile ? "0 16px" : "0 56px" }}>
            {loading && (
              <div style={{ padding: "60px 0", textAlign: "center", fontSize: 13, color: S.ashDim, letterSpacing: "0.3em" }}>
                ⸺ TUNING SIGNAL ⸺
              </div>
            )}
            {loadError && !loading && (
              <div style={{ padding: "40px 0", fontSize: 13, color: S.bloodHot, letterSpacing: "0.25em", lineHeight: 1.7 }}>
                ◢ TRANSMISSION FEED CORRUPTED<br/>
                <span style={{ color: S.ash, fontStyle: "italic", letterSpacing: "0.05em" }}>{loadError}</span>
              </div>
            )}
            {!loading && !loadError && filtered.length === 0 && (
              <div style={{ padding: "60px 0", textAlign: "center", fontSize: 13, color: S.ashDim, letterSpacing: "0.3em" }}>
                ⸺ NO TRANSMISSIONS IN THIS BAND ⸺
              </div>
            )}
            {filtered.map((t, i) => {
              const isOpen = opened?.n === t.n;
              return (
                <div key={t.n} style={{
                  borderBottom: `1px solid ${S.concreteHi}`, padding: isMobile ? "20px 0" : "28px 0",
                  display: "grid",
                  gridTemplateColumns: isMobile ? "1fr" : "120px 1fr auto",
                  gap: isMobile ? 12 : 28,
                  alignItems: "start",
                  cursor: t.kind === "essay" || t.kind === "video" ? "pointer" : "default",
                }}
                onClick={() => (t.kind === "essay" || t.kind === "video") && setOpen(isOpen ? null : t.n)}>
                  {/* left: number + meta */}
                  <div>
                    <div style={{ fontFamily: S.display, fontSize: 32, lineHeight: 1, color: t.kind === "essay" ? S.bloodHot : t.kind === "video" ? S.bone : S.ash, letterSpacing: "-0.01em" }}>
                      {t.n}
                    </div>
                    <div style={{ fontSize: 12, color: S.ash, letterSpacing: "0.25em", marginTop: 6 }}>
                      {t.date}
                    </div>
                    <div style={{ fontSize: 12, marginTop: 6, letterSpacing: "0.3em",
                      color: t.kind === "essay" ? S.bloodHot : t.kind === "video" ? S.bone : S.ashDim,
                    }}>
                      {t.kind === "essay" ? "◢ ESSAY" : t.kind === "video" ? "◢ VIDEO" : "◢ SHORT"}
                    </div>
                  </div>

                  {/* center: title + body */}
                  <div>
                    {t.title && (
                      <div style={{
                        fontFamily: S.display, fontSize: 22, color: S.bone, letterSpacing: "-0.01em",
                        marginBottom: 12, textTransform: "uppercase",
                      }}>
                        {t.title}
                      </div>
                    )}

                    {/* voice memo — only renders when an approved TTS URL is set */}
                    <VoicePlayer
                      voiceUrl={t.voice_url}
                      eyebrow={`◢ VOICE MEMO · TRANSMISSION ${t.n}`}
                      fallbackDur={memoDuration(t.n)}
                      engageKind="transmission"
                      engageRowId={t.id}
                      S={S}
                    />

                    {/* Real video embed when video_url is set — YouTube/Vimeo as iframe, direct mp4 as <video>.
                        Vertical 9:16 frame — most transmissions are phone-shot vertical clips. */}
                    {(() => {
                      const e = videoEmbedFor(t.video_url);
                      if (!e) return null;
                      if (e.kind === "iframe") {
                        return (
                          <div style={{ position: "relative", aspectRatio: "9 / 16", maxWidth: 380, marginBottom: 14, border: `1px solid ${S.concreteHi}`, overflow: "hidden", background: S.raven }}>
                            <iframe src={e.src} title={t.title || `transmission ${t.n}`}
                              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                              allowFullScreen
                              style={{ position: "absolute", inset: 0, width: "100%", height: "100%", border: "none" }} />
                          </div>
                        );
                      }
                      if (e.kind === "video") {
                        return (
                          <div style={{ position: "relative", aspectRatio: "9 / 16", maxWidth: 380, marginBottom: 14, border: `1px solid ${S.concreteHi}`, overflow: "hidden", background: S.raven }}>
                            <video src={e.src} controls preload="metadata" controlsList="nodownload" playsInline
                              style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", background: S.raven }} />
                          </div>
                        );
                      }
                      // unknown / non-embeddable URL
                      return (
                        <a href={e.src} target="_blank" rel="noreferrer" style={{
                          display: "inline-flex", alignItems: "center", gap: 8, marginBottom: 14,
                          padding: "8px 14px", border: `1px solid ${S.concreteHi}`,
                          color: S.bone, textDecoration: "none", fontFamily: S.meta, fontSize: 12, letterSpacing: "0.25em",
                        }}>WATCH ↗</a>
                      );
                    })()}
                    <pre style={{
                      margin: 0, fontFamily: S.meta, fontSize: 14, lineHeight: 1.7, color: S.bone,
                      whiteSpace: "pre-wrap", letterSpacing: "0.01em",
                    }}>{stripVoiceCues(t.body)}</pre>
                    {(t.kind === "essay" || t.kind === "video") && t.read && (
                      <div style={{ marginTop: 14, fontSize: 12, color: S.bloodHot, letterSpacing: "0.3em", display: "flex", alignItems: "center", gap: 8 }}>
                        {t.kind === "essay" ? `READ FULL · ${t.read}` : `WATCH · ${t.read}`}
                        <Glyph name="arrow" size={11} color={S.bloodHot} />
                      </div>
                    )}
                    {/* engagement: heart + voice play count */}
                    <div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${S.concrete}`, display: "flex", alignItems: "center", gap: 16, fontSize: 11, color: S.ashDim, letterSpacing: "0.18em" }}>
                      <Heart kind="transmission" rowId={t.id} initialCount={t.like_count || 0} S={S} size={14} />
                      {t.voice_play_count > 0 && (
                        <span>{t.voice_play_count} voice play{t.voice_play_count === 1 ? "" : "s"}</span>
                      )}
                    </div>
                  </div>

                  {/* right: kind glyph (desktop only — too cramped on mobile) */}
                  {!isMobile && (
                    <div style={{ fontSize: 12, color: S.ashDim, letterSpacing: "0.3em", textAlign: "right" }}>
                      {String(filtered.length - i).padStart(3, "0")}<br/>OF<br/>{String(filtered.length).padStart(3, "0")}
                    </div>
                  )}
                </div>
              );
            })}
            <div style={{ padding: "32px 0", textAlign: "center", fontSize: 12, color: S.ashDim, letterSpacing: "0.3em" }}>
              ⸺ END OF FEED · NEXT TRANSMISSION DROPS WHEN IT DROPS ⸺
            </div>
          </div>
        </div>

        {/* right rail: subscribe + recent + about */}
        <aside style={{
          borderLeft: isMobile ? "none" : `1px solid ${S.concreteHi}`,
          borderTop: isMobile ? `1px solid ${S.concreteHi}` : "none",
          overflow: isMobile ? "visible" : "auto",
          padding: 0,
        }}>
          <div style={{ padding: 24, borderBottom: `1px solid ${S.concreteHi}` }}>
            <div style={{ fontSize: 12, color: S.bloodHot, letterSpacing: "0.3em", marginBottom: 12 }}>
              ◢ SUBSCRIBE
            </div>
            <div style={{ fontSize: 13, color: S.bone, fontFamily: S.meta, lineHeight: 1.6, marginBottom: 16 }}>
              one transmission per drop.<br/>
              no marketing. no schedule.<br/>
              just the raven, occasionally.
            </div>
            {!subscribed ? (
              <form onSubmit={handleSubscribe}>
                <input
                  type="email"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  placeholder="your.email@mortal.com"
                  disabled={subscribing}
                  style={{
                    width: "100%", boxSizing: "border-box",
                    padding: "12px 14px", background: S.raven, border: `1px solid ${S.concreteHi}`,
                    color: S.bone, fontFamily: S.meta, fontSize: 12, letterSpacing: "0.04em",
                    outline: "none", marginBottom: 8,
                  }}
                  onFocus={(e) => (e.target.style.borderColor = S.bloodHot)}
                  onBlur={(e) => (e.target.style.borderColor = S.concreteHi)}
                />
                <button type="submit" disabled={subscribing} style={{
                  width: "100%", padding: "12px 14px",
                  background: subscribing ? S.concreteHi : S.bloodHot,
                  color: S.bone, border: "none", fontFamily: S.display, fontSize: 12, letterSpacing: "0.2em",
                  cursor: subscribing ? "wait" : "pointer", textTransform: "uppercase",
                  opacity: subscribing ? 0.6 : 1,
                }}>
                  {subscribing ? "SENDING…" : "RECEIVE TRANSMISSIONS"}
                </button>
                {subscribeError && (
                  <div style={{ marginTop: 10, fontSize: 12, color: S.bloodHot, fontFamily: S.meta, letterSpacing: "0.02em", lineHeight: 1.5 }}>
                    ◢ {subscribeError}
                  </div>
                )}
              </form>
            ) : (
              <div style={{ padding: "16px 0", fontSize: 12, color: S.bloodHot, fontFamily: S.meta, letterSpacing: "0.04em", lineHeight: 1.5 }}>
                ◢ check your inbox.<br/>
                <span style={{ color: S.ash }}>{subscribeMessage || "click the confirm link in the email and you're in."}</span>
              </div>
            )}
          </div>

          <div style={{ padding: 24, borderBottom: `1px solid ${S.concreteHi}` }}>
            <div style={{ fontSize: 12, color: S.ash, letterSpacing: "0.3em", marginBottom: 14 }}>
              ◢ POPULAR
            </div>
            {transmissions.filter(t => t.title).slice(0, 5).map((t) => (
              <div key={t.n} style={{ marginBottom: 14, display: "flex", gap: 10, cursor: "pointer" }}
                   onClick={() => { document.querySelector('aside')?.scrollTo(0,0); }}>
                <div style={{ fontFamily: S.cond, fontSize: 16, color: S.bloodHot, letterSpacing: "0.04em", minWidth: 32 }}>
                  {t.n}
                </div>
                <div style={{ fontSize: 13, color: S.bone, lineHeight: 1.4, letterSpacing: "0.02em" }}>
                  {t.title}
                  <div style={{ fontSize: 12, color: S.ashDim, letterSpacing: "0.25em", marginTop: 2 }}>
                    {t.date}
                  </div>
                </div>
              </div>
            ))}
          </div>

          <div style={{ padding: 24, borderBottom: `1px solid ${S.concreteHi}` }}>
            <div style={{ fontSize: 12, color: S.ash, letterSpacing: "0.3em", marginBottom: 12 }}>
              ◢ ARCHIVE BY MONTH
            </div>
            <div style={{ fontSize: 13, color: S.ash, fontFamily: S.meta, lineHeight: 1.9 }}>
              {(() => {
                // Bucket transmissions by year-month using published_at (real timestamp)
                // Falls back to nothing if published_at is unset on a row.
                const months = ["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];
                const buckets = new Map(); // key: "YYYY-MM" → { label, count, sortKey }
                for (const t of transmissions) {
                  if (!t.published_at) continue;
                  const d = new Date(t.published_at);
                  if (Number.isNaN(d.getTime())) continue;
                  const y = d.getFullYear();
                  const m = d.getMonth();
                  const key = `${y}-${String(m).padStart(2,"0")}`;
                  const label = `${y} · ${months[m]}`;
                  const cur = buckets.get(key) || { label, count: 0, sortKey: key };
                  cur.count++;
                  buckets.set(key, cur);
                }
                const rows = Array.from(buckets.values()).sort((a, b) => b.sortKey.localeCompare(a.sortKey));
                if (rows.length === 0) {
                  return <div style={{ color: S.ashDim, fontStyle: "italic" }}>⸺ NO ARCHIVE YET ⸺</div>;
                }
                return rows.map(r => (
                  <div key={r.sortKey} style={{ display: "flex", justifyContent: "space-between", borderBottom: `1px dashed ${S.concreteHi}`, padding: "4px 0" }}>
                    <span>{r.label}</span>
                    <span style={{ color: S.bone }}>{String(r.count).padStart(2, "0")}</span>
                  </div>
                ));
              })()}
            </div>
          </div>

          <div style={{ padding: 24 }}>
            <div style={{ fontSize: 12, color: S.ash, letterSpacing: "0.3em", marginBottom: 12 }}>
              ◢ NOTE
            </div>
            <div style={{ fontSize: 13, color: S.ash, fontFamily: S.meta, lineHeight: 1.7, fontStyle: "italic" }}>
              transmissions are written by D//V in collaboration with pei. they are not bug reports. they are not press releases. they are weather reports from inside a small storm.
            </div>
          </div>
        </aside>
      </div>
    </Shell>
  );
}

window.TransmissionsPage = TransmissionsPage;
