---
/**
 * Newsroom-style post grid: cover image, date + tag, title. Client-side
 * search and batched "Load more" only toggle visibility; every card is
 * server-rendered for crawlers and no-JS readers.
 *
 * Topic tabs come through the `filters` slot so the index and tag pages
 * can mark their own active tab.
 */
import BlogCover from './BlogCover.astro';
import { isoDate, readingTimeOf, type BlogPost } from '../../lib/blog';

interface Props {
  posts: BlogPost[];
  /** Cards shown initially and added per "Load more" click. */
  batch?: number;
}
const { posts, batch = 12 } = Astro.props;
---
<div data-archive data-batch={batch}>
  <!-- TOOLBAR: topic tabs + search -->
  <div class="flex flex-wrap items-center justify-between gap-x-6 gap-y-4 pb-6 border-b border-[color:var(--border)]">
    <slot name="filters" />
    <div class="flex items-center gap-4 ml-auto">
      <label class="relative block">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none">
          <circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" />
        </svg>
        <input
          type="search"
          placeholder="Search posts"
          data-archive-search
          class="h-8 w-44 md:w-56 pr-3 rounded-[8px] bg-[color:var(--surface-2)] ring-1 ring-[color:var(--border)] text-[12.5px] text-foreground placeholder:text-muted-foreground outline-none focus:bg-white focus:ring-[#38bdf8] transition-colors"
          style="padding-left: 2.125rem;"
        />
      </label>
      <span class="text-[11px] font-mono text-muted-foreground whitespace-nowrap">{posts.length} {posts.length === 1 ? 'post' : 'posts'}</span>
    </div>
  </div>

  <!-- GRID -->
  <div class="mt-8 grid sm:grid-cols-2 lg:grid-cols-3 gap-x-6 gap-y-10">
    {posts.map((post, i) => (
      <a
        href={`/blog/${post.id}/`}
        data-post-card
        data-search={`${post.data.title} ${post.data.description} ${post.data.tags.join(' ')}`.toLowerCase()}
        class="group flex flex-col"
      >
        <div class="relative aspect-[16/10] rounded-[14px] overflow-hidden ring-1 ring-[color:var(--border)] group-hover:ring-[#0284c7]/40 transition-all duration-200 group-hover:shadow-[0_18px_40px_-16px_rgba(2,32,71,0.3)]">
          <BlogCover post={post} eager={i < 3} />
        </div>
        <div class="mt-4 flex items-center gap-3 text-[10.5px] font-mono text-muted-foreground">
          <time datetime={post.data.pubDate.toISOString()} class="uppercase tracking-[0.14em]">{isoDate(post.data.pubDate)}</time>
          {post.data.tags.slice(0, 2).map((tag) => (
            <span class="uppercase tracking-[0.12em] text-sky-700">{tag}</span>
          ))}
          <span class="ml-auto">{readingTimeOf(post)}</span>
        </div>
        <h3 class="mt-2 text-[16.5px] md:text-[17.5px] font-semibold tracking-[-0.015em] leading-[1.3] text-heading group-hover:text-[#0369a1] transition-colors">
          {post.data.title}
        </h3>
        <p class="mt-1.5 text-[13px] text-foreground/60 leading-relaxed line-clamp-2">{post.data.description}</p>
      </a>
    ))}
  </div>

  <!-- EMPTY STATE (search with no hits) -->
  <div class="py-16 text-center" data-archive-empty hidden>
    <p class="text-[14px] text-foreground/65">Nothing matches that search.</p>
    <p class="mt-1 text-[12px] font-mono text-muted-foreground">Try a different word, or clear the field.</p>
  </div>

  <!-- LOAD MORE -->
  <div class="mt-12 flex justify-center" data-archive-controls hidden>
    <button
      type="button"
      data-archive-more
      class="inline-flex items-center gap-2.5 h-10 px-5 rounded-[10px] text-[13.5px] font-medium bg-[color:var(--surface-2)] text-foreground ring-1 ring-[color:var(--border)] hover:bg-[color:var(--surface-3)] transition-colors"
    >
      Load more
      <span class="font-mono text-[11px] text-muted-foreground" data-archive-remaining></span>
    </button>
  </div>
</div>

<script>
  function init(root: HTMLElement) {
    const cards = Array.from(root.querySelectorAll<HTMLElement>('[data-post-card]'));
    const search = root.querySelector<HTMLInputElement>('[data-archive-search]');
    const controls = root.querySelector<HTMLElement>('[data-archive-controls]');
    const moreBtn = root.querySelector<HTMLElement>('[data-archive-more]');
    const remaining = root.querySelector<HTMLElement>('[data-archive-remaining]');
    const empty = root.querySelector<HTMLElement>('[data-archive-empty]');
    if (!cards.length || !controls || !moreBtn || !remaining || !empty) return;

    const batch = parseInt(root.getAttribute('data-batch') || '12', 10);
    let visible = Math.min(batch, cards.length);
    let query = '';

    const apply = () => {
      let shown = 0;
      let hiddenByBatch = 0;
      cards.forEach((card) => {
        if (query) {
          const hit = (card.getAttribute('data-search') || '').includes(query);
          card.hidden = !hit;
          if (hit) shown++;
        } else if (shown < visible) {
          card.hidden = false;
          shown++;
        } else {
          card.hidden = true;
          hiddenByBatch++;
        }
      });
      empty.hidden = shown > 0;
      controls.hidden = !!query || hiddenByBatch === 0;
      remaining.textContent = `${hiddenByBatch} more`;
    };

    moreBtn.addEventListener('click', () => {
      visible = Math.min(visible + batch, cards.length);
      apply();
    });

    if (search) {
      search.addEventListener('input', () => {
        query = search.value.trim().toLowerCase();
        apply();
      });
    }

    if (query || cards.length > visible) apply();
  }

  document.querySelectorAll<HTMLElement>('[data-archive]').forEach(init);
</script>
