<script>
  import { onMount } from 'svelte';
  import { getJSON } from '$lib/api.js';
  import * as P from '$lib/prefs.js';
  import MoodNav from '$lib/components/MoodNav.svelte';
  import ArticleCard from '$lib/components/ArticleCard.svelte';
  import BoundariesPanel from '$lib/components/BoundariesPanel.svelte';

  let moods = $state([]);
  let selected = $state('today');
  let brief = $state(null);
  let feed = $state([]);
  let userPrefs = $state(P.blank());
  let showBoundaries = $state(false);
  let showHistory = $state(false);
  let loading = $state(true);
  let error = $state('');

  // Session memory (this tab only — cleared on close, no account):
  // every article shown is remembered so Replace never recycles something
  // already seen, and so a replaced-away story stays recoverable in History.
  const seenIds = new Set();
  let history = $state([]);
  function remember(items) {
    for (const a of items || []) {
      if (a && !seenIds.has(a.id)) {
        seenIds.add(a.id);
        history.unshift(a);
      }
    }
  }

  let filtersOn = $derived(P.active(userPrefs));
  let current = $derived(moods.find((m) => m.key === selected));
  let viewLabel = $derived(selected === 'today' ? 'Highlights from Today' : (current?.label ?? ''));
  let viewSubtitle = $derived(
    selected === 'today' ? (brief?.brief_date ?? '') : (current?.description ?? '')
  );

  function mergedParam() {
    const merged = P.merge(userPrefs, current?.filter ?? {});
    return P.param(merged);
  }

  async function select(key) {
    selected = key;
    error = '';
    try {
      // Today = the day's highlights (hero + six). Other moods reveal that
      // category only when chosen.
      if (key === 'today') {
        const q = P.param(userPrefs);
        brief = await getJSON(`/api/brief?limit=7${q ? '&' + q : ''}`);
        remember(brief.items);
      } else {
        const mood = moods.find((m) => m.key === key);
        const q = P.param(P.merge(userPrefs, mood?.filter ?? {}));
        feed = (await getJSON(`/api/feed?limit=24${q ? '&' + q : ''}`)).items;
        remember(feed);
      }
    } catch (e) {
      error = 'Something went quiet — could not reach the feed.';
    }
    if (typeof window !== 'undefined') window.scrollTo({ top: 0, behavior: 'smooth' });
  }

  function refreshPrefs() {
    userPrefs = { ...userPrefs };
    P.save(userPrefs);
    select(selected);
  }
  function applyAction(kind, value) {
    P[kind]?.(userPrefs, value);
    refreshPrefs();
  }

  let notice = $state('');
  function flash(msg) {
    notice = msg;
    if (typeof window !== 'undefined') setTimeout(() => (notice = ''), 4000);
  }

  async function replaceArticle(article) {
    const list = selected === 'today' ? brief?.items : feed;
    if (!list) return;
    const isHero = selected === 'today' && list[0]?.id === article.id;
    // Exclude everything seen this session, so Replace never cycles back.
    const exclude = Array.from(seenIds).join(',');
    const q = mergedParam();
    const url = `/api/replacement?exclude=${exclude}&avoid_paywall=true${isHero ? '&gentle=true' : ''}${q ? '&' + q : ''}`;
    let repl;
    try {
      repl = await getJSON(url);
    } catch {
      flash('Could not reach the feed just now.');
      return;
    }
    if (!repl) {
      flash("That's everything fresh for now — nothing new to swap in.");
      return;
    }
    remember([repl]);
    if (selected === 'today') {
      const i = brief.items.findIndex((a) => a.id === article.id);
      if (i >= 0) {
        brief.items[i] = repl;
        brief = { ...brief, items: [...brief.items] };
      }
    } else {
      const i = feed.findIndex((a) => a.id === article.id);
      if (i >= 0) {
        feed[i] = repl;
        feed = [...feed];
      }
    }
  }

  onMount(async () => {
    userPrefs = P.load();
    try {
      moods = await getJSON('/api/moods');
      await select('today');
    } catch (e) {
      error = 'Could not reach goodNews.';
    }
    loading = false;
  });
</script>

{#if moods.length}
  <MoodNav {moods} {selected} onselect={select} />
{/if}

<div class="toptools">
  <button class="link" class:on={history.length} onclick={() => (showHistory = !showHistory)}>History</button>
  <button class="link" class:on={filtersOn} onclick={() => (showBoundaries = !showBoundaries)}>
    {filtersOn ? 'Boundaries ·' : 'Boundaries'}
  </button>
</div>

{#if showBoundaries}
  <BoundariesPanel prefs={userPrefs} onchange={refreshPrefs} onclose={() => (showBoundaries = false)} />
{/if}

{#if showHistory}
  <section class="panel rise">
    <div class="phead">
      <h2>This session</h2>
      <button class="close" onclick={() => (showHistory = false)}>done</button>
    </div>
    <p class="reassure">Everything you've seen this visit, including stories you swapped away. Kept on this device for this tab only — it clears when you close it. (Saved history & favorites come with sign-in, later.)</p>
    {#if history.length}
      <ul class="hist">
        {#each history as a (a.id)}
          <li>
            <a href={a.url} target="_blank" rel="noopener">{a.title}</a>
            <span class="hsrc">{a.source}</span>
          </li>
        {/each}
      </ul>
    {:else}
      <p class="empty">Nothing yet — your seen stories will appear here.</p>
    {/if}
  </section>
{/if}

{#if notice}
  <p class="notice rise">{notice}</p>
{/if}

{#if loading}
  <p class="muted center pad">Gathering the good news…</p>
{:else if error}
  <p class="muted center pad">{error}</p>
{:else}
  {#key selected}
    <header class="view-head rise">
      <h1>{viewLabel}</h1>
      {#if viewSubtitle}<p class="sub">{viewSubtitle}</p>{/if}
    </header>

    {#if selected === 'today'}
      {#if brief?.items?.length}
        <section class="rise">
          <ArticleCard article={brief.items[0]} hero onaction={applyAction} onreplace={replaceArticle} />
          {#if brief.items.length > 1}
            <div class="grid rest">
              {#each brief.items.slice(1) as a (a.id)}
                <ArticleCard article={a} onaction={applyAction} onreplace={replaceArticle} />
              {/each}
            </div>
          {/if}
        </section>
        <p class="endcap rise">✦ that's the good news for today ✦</p>
      {:else}
        <p class="muted center pad">No highlights yet today — try a calmer filter, or check back soon.</p>
      {/if}
    {:else if feed.length}
      <div class="grid rise">
        {#each feed as a (a.id)}
          <ArticleCard article={a} onaction={applyAction} onreplace={replaceArticle} />
        {/each}
      </div>
    {:else}
      <p class="muted center pad">Nothing in this mood right now — try another, or ease a boundary.</p>
    {/if}
  {/key}
{/if}

<style>
  .toptools { display: flex; justify-content: flex-end; gap: 18px; margin: 2px 0 0; }
  .link {
    background: none; border: none; color: var(--muted);
    font-size: 0.82rem; padding: 4px 2px; letter-spacing: 0.01em;
  }
  .link:hover { color: var(--sage-deep); }
  .link.on { color: var(--sage-deep); font-weight: 600; }

  .view-head { margin: 20px 0 20px; }
  .view-head h1 {
    font-size: clamp(2.1rem, 5.5vw, 2.8rem);
    line-height: 1.05;
  }
  .view-head .sub { margin: 8px 0 0; color: var(--muted); font-size: 1.02rem; }
  .view-head::after {
    content: ''; display: block; width: 46px; height: 3px;
    background: var(--sage); border-radius: 2px; margin-top: 14px; opacity: 0.8;
  }

  /* History panel */
  .panel {
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow); padding: 20px 22px; margin: 8px 0 18px;
  }
  .phead { display: flex; align-items: baseline; justify-content: space-between; }
  .phead h2 { font-size: 1.3rem; }
  .close { background: none; border: none; color: var(--sage-deep); font-size: 0.85rem; text-decoration: underline; }
  .reassure { margin: 4px 0 14px; color: var(--muted); font-size: 0.85rem; }
  .hist { list-style: none; margin: 0; padding: 0; }
  .hist li { padding: 8px 0; border-bottom: 1px solid var(--line); display: flex; gap: 12px; align-items: baseline; }
  .hist li:last-child { border-bottom: none; }
  .hist a { color: var(--ink); }
  .hist a:hover { color: var(--sage-deep); }
  .hsrc { margin-left: auto; color: var(--muted); font-size: 0.78rem; white-space: nowrap; }
  .empty { margin: 0; color: var(--muted); font-style: italic; font-size: 0.85rem; }

  .notice {
    text-align: center; color: var(--sage-deep); background: var(--sage-soft);
    border-radius: 999px; padding: 8px 16px; margin: 10px auto 0; width: fit-content;
    font-size: 0.86rem;
  }
  .rest { margin-top: 18px; }
  .center { text-align: center; }
  .pad { padding: 48px 0; }
  .endcap {
    text-align: center; color: var(--muted); font-family: var(--serif);
    font-style: italic; margin: 40px 0 10px; letter-spacing: 0.02em;
  }
</style>
