/* global React, Icons, TweetCard, PodcastCard, NewsCard, SkeletonRow, NewsSkeletonRow, Empty, dayKey, dayLabel */
// The Deck view: three columns (News, curated Tweets, Podcasts). Generic
// Column shell with an in-column filter strip, day dividers, incremental
// chunked rendering, and a seen-watermark divider (advanced only while the
// tab is genuinely visible, so a hidden-tab reload cannot mark items seen).
(() => {
  const e = React.createElement;
  const { useState, useMemo, useEffect } = React;

  const SEEN_KEY = "dujour:seen:v1";
  function readSeen() {
    try { return JSON.parse(localStorage.getItem(SEEN_KEY)) || {}; }
    catch { return {}; }
  }
  function useSeenWatermark(colKey, newestUnix) {
    const [prev] = useState(() => readSeen()[colKey] || 0);
    useEffect(() => {
      if (!newestUnix || document.hidden) return;  // never advance on a hidden reload
      const all = readSeen();
      if ((all[colKey] || 0) < newestUnix) {
        all[colKey] = newestUnix;
        try { localStorage.setItem(SEEN_KEY, JSON.stringify(all)); } catch { /* ignore */ }
      }
    }, [colKey, newestUnix]);
    return prev;
  }

  function useChunked(items, chunk = 40) {
    const [limit, setLimit] = useState(chunk);
    useEffect(() => { setLimit(chunk); }, [items, chunk]);
    const sentinelRef = React.useCallback((node) => {
      if (!node) return;
      const io = new IntersectionObserver((entries) => {
        if (entries.some((en) => en.isIntersecting)) setLimit((n) => n + chunk);
      }, { root: node.closest(".col-body"), rootMargin: "600px" });
      io.observe(node);
    }, [chunk]);
    return {
      visible: items.slice(0, limit),
      sentinel: items.length > limit
        ? e("div", { ref: sentinelRef, className: "col-sentinel", key: "sentinel" },
            e("button", { className: "pod-expand", style: { padding: "12px 14px" },
              onClick: () => setLimit((n) => n + chunk) }, `Show older (${items.length - limit} more)`))
        : null,
    };
  }

  function Column({ icon, title, count, children, filters }) {
    const [showFilters, setShowFilters] = useState(false);
    const bodyRef = React.useRef(null);
    return e("section", { className: "col", "aria-label": title },
      e("header", { className: "col-head" },
        e("span", { className: "col-icon" }, icon),
        e("button", { className: "col-title", title: "Jump to top",
          onClick: () => bodyRef.current && bodyRef.current.scrollTo({ top: 0, behavior: "smooth" }) }, title),
        count != null && e("span", { className: "col-count tabnum" }, count),
        filters && e("div", { className: "col-tools" },
          e("button", { className: `col-tool${showFilters ? " on" : ""}`,
            title: "Filters", "aria-label": "Toggle filters",
            onClick: () => setShowFilters(!showFilters) }, e(Icons.Filter, { size: 13 })))),
      filters && showFilters && e("div", { className: "col-filters" }, filters),
      e("div", { className: "col-body", ref: bodyRef }, children));
  }

  function withDividers(items, prevSeen, keyOf, render) {
    const out = [];
    let lastDay = null, seenPlaced = prevSeen <= 0;
    items.forEach((it) => {
      const dk = dayKey(it.created_unix);
      if (dk !== lastDay) {
        out.push(e("div", { className: "day-div", key: `d-${dk}` }, dayLabel(it.created_unix)));
        lastDay = dk;
      }
      if (!seenPlaced && it.created_unix <= prevSeen) {
        out.push(e("div", { className: "unseen-div", key: "seen" }, "seen up to here"));
        seenPlaced = true;
      }
      out.push(render(it, keyOf(it)));
    });
    return out;
  }

  // ---------- News ----------
  function NewsColumn({ news, loading }) {
    const [q, setQ] = useState("");
    const [src, setSrc] = useState("all");
    const items = useMemo(() => news.filter((n) => {
      if (src !== "all" && n.source !== src) return false;
      if (q && !`${n.title} ${n.feed}`.toLowerCase().includes(q.toLowerCase())) return false;
      return true;
    }), [news, q, src]);
    const { visible, sentinel } = useChunked(items, 40);
    const filters = e(React.Fragment, null,
      e("input", { type: "search", placeholder: "Filter headlines...", value: q,
        onChange: (ev) => setQ(ev.target.value) }),
      ["all", "WSJ", "Bloomberg"].map((s) => e("button", { key: s,
        className: `fpill${src === s ? " on" : ""}`, onClick: () => setSrc(s) },
        s === "all" ? "All" : s)));
    return e(Column, { icon: e(Icons.News, { size: 15 }), title: "News", count: items.length, filters },
      loading ? [1, 2, 3, 4, 5].map((i) => e(NewsSkeletonRow, { key: i }))
        : items.length
          ? [...visible.map((n) => e(NewsCard, { n, key: n.id })), sentinel]
          : e(Empty, null, "// no headlines"));
  }

  // ---------- Tweets (single curated column) ----------
  function TweetsColumn({ tweets, loading }) {
    const [q, setQ] = useState("");
    const [minScore, setMinScore] = useState(50);
    const [mediaOnly, setMediaOnly] = useState(false);
    const [hideReplies, setHideReplies] = useState(false);
    const items = useMemo(() => {
      const f = tweets.filter((t) => {
        if ((t.curation_score == null ? 0 : t.curation_score) < minScore) return false;
        if (mediaOnly && !(t.media && t.media.length)) return false;
        if (hideReplies && t.is_reply) return false;
        if (q && !`${t.text} ${t.handle} ${t.author_name || ""}`.toLowerCase().includes(q.toLowerCase())) return false;
        return true;
      });
      return [...f].sort((a, b) => b.created_unix - a.created_unix);  // curated, chronological
    }, [tweets, q, minScore, mediaOnly, hideReplies]);
    const newest = items.length ? items[0].created_unix : 0;
    const prevSeen = useSeenWatermark("tweets", newest);
    const active = !!(q || mediaOnly || hideReplies || minScore !== 50);
    const { visible, sentinel } = useChunked(items, 40);
    const filters = e(React.Fragment, null,
      e("input", { type: "search", placeholder: "Filter...", value: q,
        onChange: (ev) => setQ(ev.target.value) }),
      [40, 50, 65, 80].map((s) => e("button", { key: s,
        className: `fpill${minScore === s ? " on" : ""}`, onClick: () => setMinScore(s) }, `${s}+`)),
      e("button", { className: `fpill${mediaOnly ? " on" : ""}`, onClick: () => setMediaOnly(!mediaOnly) }, "Media"),
      e("button", { className: `fpill${hideReplies ? " on" : ""}`, onClick: () => setHideReplies(!hideReplies) }, "No replies"));
    return e(Column, { icon: e(Icons.Tweet, { size: 15 }), title: "Tweets", count: items.length, filters },
      loading ? [1, 2, 3, 4, 5].map((i) => e(SkeletonRow, { key: i }))
        : items.length
          ? [...withDividers(visible, active ? 0 : prevSeen, (t) => t.id, (t) => e(TweetCard, { t, key: t.id })), sentinel]
          : e(Empty, null, "// nothing above this signal", e("br"), "lower the score filter"));
  }

  // ---------- Podcasts ----------
  function PodcastColumn({ podcasts, loading }) {
    const [minScore, setMinScore] = useState(0);
    const items = useMemo(() => podcasts.filter((p) => (p.interest_score || 0) >= minScore),
      [podcasts, minScore]);
    const { visible, sentinel } = useChunked(items, 24);
    const filters = e(React.Fragment, null,
      [0, 60, 80].map((s) => e("button", { key: s, className: `fpill${minScore === s ? " on" : ""}`,
        onClick: () => setMinScore(s) }, s === 0 ? "All" : `${s}+`)));
    return e(Column, { icon: e(Icons.Mic, { size: 15 }), title: "Podcasts", count: items.length, filters },
      loading ? [1, 2, 3].map((i) => e(SkeletonRow, { key: i }))
        : items.length
          ? [...visible.map((p) => e(PodcastCard, { p, key: p.video_id })), sentinel]
          : e(Empty, null, "// no episodes this window"));
  }

  function DeckView({ data, loading }) {
    return e("div", { className: "deck" },
      e(NewsColumn, { news: (data && data.news) || [], loading }),
      e(TweetsColumn, { tweets: (data && data.tweets) || [], loading }),
      e(PodcastColumn, { podcasts: (data && data.podcasts) || [], loading }));
  }

  Object.assign(window, { DeckView });
})();
