<script lang="ts">
    import Icon from "@iconify/svelte";
    import "$lib/iconify-offline";
    import PostCard from "./PostCard.svelte";
    import EventBadges from "./EventBadges.svelte";
    import Tag from "./Tag.svelte";
    import Pagination from "./Pagination.svelte";
    import type { PostEntry } from "$lib/cms";
    import { postHref, getPostEventInfo } from "$lib/blog-utils";
    import { t as tStatic, T } from "$lib/translations";
    import type { Translations } from "$lib/translations";
    import {
        fetchCommentCounts,
        postSlugForComments,
        type CommentCountsMap,
    } from "$lib/comment-counts";

    interface TagEntry {
        _slug?: string;
        name: string;
        icon?: string;
        color?: string;
    }

    type SearchIndexEntry = {
        slug: string;
        headline: string;
        excerpt: string;
        subheadline: string;
        tags: string[];
        image: string | null;
        created: string | null;
        isEvent: boolean;
        eventDate: string | null;
    };

    let {
        posts = [],
        tags = [],
        activeTag = null,
        currentPage = 1,
        totalPages = 1,
        totalPosts = 0,
        basePath = "/posts",
        translations = {},
        upcomingEvents = [],
        searchIndex = null,
    }: {
        posts: PostEntry[];
        tags: TagEntry[];
        activeTag: string | null;
        currentPage: number;
        totalPages: number;
        totalPosts?: number;
        basePath?: string;
        translations?: Translations | null;
        upcomingEvents?: PostEntry[];
        searchIndex?: SearchIndexEntry[] | null;
    } = $props();

    let query = $state("");
    let year = $state<string>("");
    const normalizedQuery = $derived(query.trim().toLowerCase());
    const isFiltering = $derived(normalizedQuery.length >= 2 || year !== "");

    function yearOf(entry: SearchIndexEntry): string {
        const iso = entry.created ?? "";
        if (!iso) return "";
        const d = new Date(iso);
        return Number.isNaN(d.getTime()) ? "" : String(d.getFullYear());
    }

    const availableYears = $derived.by<string[]>(() => {
        if (!searchIndex) return [];
        const set = new Set<string>();
        for (const p of searchIndex) {
            const y = yearOf(p);
            if (y) set.add(y);
        }
        return Array.from(set).sort((a, b) => b.localeCompare(a));
    });

    const filteredResults = $derived.by<SearchIndexEntry[]>(() => {
        if (!isFiltering || !searchIndex) return [];
        const q = normalizedQuery;
        return searchIndex
            .filter((p) => {
                if (year && yearOf(p) !== year) return false;
                if (q) {
                    const hay =
                        `${p.headline} ${p.excerpt} ${p.subheadline} ${p.tags.join(" ")}`.toLowerCase();
                    if (!hay.includes(q)) return false;
                }
                return true;
            })
            .slice(0, 80);
    });

    function searchResultHref(slug: string): string {
        const norm = (slug ?? "").replace(/^\//, "").trim();
        return norm ? `/post/${encodeURIComponent(norm)}` : "/post";
    }

    function t(key: string, replacements?: Record<string, string | number>) {
        return tStatic(translations ?? null, key, replacements);
    }

    function tagHref(tagSlug: string | null): string {
        if (!tagSlug) return `${basePath}/`;
        return `${basePath}/tag/${encodeURIComponent(tagSlug)}/`;
    }

    const totalCount = $derived(totalPosts);

    // Bulk-fetch comment counts for the visible posts (single request per render).
    let commentCounts = $state<CommentCountsMap>({});
    $effect(() => {
        const ctrl = new AbortController();
        fetchCommentCounts(posts.map(postSlugForComments), {
            signal: ctrl.signal,
        }).then((map) => {
            commentCounts = map;
        });
        return () => ctrl.abort();
    });
</script>

<div class="blog-overview">
    {#if searchIndex}
        <div class="mb-4 flex flex-wrap items-center gap-2">
            <label class="relative block w-full sm:max-w-sm">
                <span class="sr-only">{t(T.blog_search_label)}</span>
                <span
                    class="pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-stein-500"
                >
                    <Icon icon="mdi:magnify" class="h-4 w-4" />
                </span>
                <input
                    type="search"
                    bind:value={query}
                    placeholder={t(T.blog_search_placeholder)}
                    class="w-full rounded-xs border border-stein-300 bg-white py-2 pr-9 pl-8 text-sm focus:border-stein-500 focus:outline-none"
                />
                {#if query}
                    <button
                        type="button"
                        onclick={() => (query = "")}
                        class="absolute top-1/2 right-1.5 -translate-y-1/2 rounded-xs p-1 text-stein-500 hover:bg-stein-100 hover:text-stein-900"
                        aria-label={t(T.blog_search_clear)}
                    >
                        <Icon icon="mdi:close" class="h-4 w-4" />
                    </button>
                {/if}
            </label>
            {#if availableYears.length > 0}
                <label class="relative inline-flex items-center">
                    <span class="sr-only">{t(T.blog_year_label)}</span>
                    <span
                        class="pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-stein-500"
                    >
                        <Icon icon="mdi:calendar" class="h-4 w-4" />
                    </span>
                    <select
                        bind:value={year}
                        class="appearance-none rounded-xs border border-stein-300 bg-white py-2 pr-7 pl-8 text-sm focus:border-stein-500 focus:outline-none"
                    >
                        <option value="">{t(T.blog_year_all)}</option>
                        {#each availableYears as y}
                            <option value={y}>{y}</option>
                        {/each}
                    </select>
                    <span
                        class="pointer-events-none absolute top-1/2 right-1.5 -translate-y-1/2 text-stein-500"
                    >
                        <Icon icon="mdi:chevron-down" class="h-4 w-4" />
                    </span>
                </label>
            {/if}
        </div>
    {/if}

    {#if !isFiltering && upcomingEvents.length > 0}
        <section
            class="not-prose mb-6 rounded-xs border border-stein-200 bg-stein-50 p-4"
        >
            <h2
                class="mb-3 flex items-center gap-2 text-sm font-semibold tracking-wide text-stein-700"
            >
                <Icon icon="mdi:calendar-clock" class="size-7 shrink-0" />
                {t(T.blog_upcoming_events)}
            </h2>
            <ul class="not-prose list-none space-y-2 pl-0">
                {#each upcomingEvents as ev}
                    {@const evInfo = getPostEventInfo(ev)}
                    <li>
                        <a
                            href={postHref(ev)}
                            class="group flex flex-wrap items-center gap-2 no-underline"
                        >
                            <EventBadges eventDate={evInfo.eventDate} />
                            <span
                                class="text-sm text-stein-900 group-hover:text-stein-900"
                                >{ev.headline}</span
                            >
                        </a>
                    </li>
                {/each}
            </ul>
        </section>
    {/if}

    {#if isFiltering}
        <div
            class="mb-3 flex flex-wrap items-center gap-2 text-xs text-stein-600"
        >
            <span>
                {t(T.blog_results_count, { count: filteredResults.length })}
                {#if query}{t(T.blog_results_for, { query })}{/if}
                {#if year}{t(T.blog_results_in_year, { year })}{/if}
            </span>
            <button
                type="button"
                onclick={() => {
                    query = "";
                    year = "";
                }}
                class="text-stein-500 underline hover:text-stein-900"
                >{t(T.blog_filter_reset)}</button
            >
        </div>
        {#if filteredResults.length > 0}
            <div
                class="py-2 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
            >
                {#each filteredResults as hit}
                    <a
                        href={searchResultHref(hit.slug)}
                        class="card-surface flex flex-col overflow-hidden text-stein-900 no-underline transition-colors hover:-translate-y-0.5 hover:shadow-md hover:border-wald-300 transition-[transform,box-shadow,border-color] duration-200"
                    >
                        {#if hit.image}
                            <div
                                class="aspect-3/2 w-full overflow-hidden bg-stein-100"
                            >
                                <img
                                    src={hit.image}
                                    alt={hit.headline}
                                    class="h-full w-full object-cover"
                                    loading="lazy"
                                />
                            </div>
                        {/if}
                        <div class="flex flex-1 flex-col p-4">
                            <h3 class="mb-1 text-base font-semibold">
                                {hit.headline}
                            </h3>
                            {#if hit.excerpt}
                                <p class="text-sm text-stein-700 line-clamp-3">
                                    {hit.excerpt}
                                </p>
                            {/if}
                        </div>
                    </a>
                {/each}
            </div>
        {:else}
            <div
                class="rounded-xs border border-stein-200 bg-white p-6 text-center text-sm text-stein-600"
            >
                {t(T.blog_no_results)}
            </div>
        {/if}
    {:else}
        {#if tags.length > 0}
            <div class="mb-2">
                <div
                    class="flex flex-wrap gap-2"
                    role="navigation"
                    aria-label={t(T.blog_filter_aria)}
                >
                    <Tag
                        label={t(T.blog_tag_all)}
                        href={tagHref(null)}
                        variant={activeTag ? "blue" : "green"}
                        active={!activeTag}
                    />
                    {#each tags as tag}
                        {@const slug = tag._slug ?? ""}
                        <Tag
                            label={tag.name}
                            href={tagHref(slug)}
                            variant={activeTag === slug ? "inactive" : "green"}
                            active={activeTag === slug}
                            icon={tag.icon?.trim() || null}
                            customColor={activeTag === slug
                                ? null
                                : tag.color?.trim() || null}
                        />
                    {/each}
                </div>
            </div>
        {/if}

        <Pagination {currentPage} {totalPages} {basePath} {activeTag} />

        <div class="py-2 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {#each posts as post}
                <PostCard
                    {post}
                    href={postHref(post)}
                    tagBase={`${basePath}/tag`}
                    commentCount={commentCounts[postSlugForComments(post)] ??
                        null}
                />
            {/each}
        </div>

        <div class="flex flex-wrap items-center gap-2">
            <Pagination {currentPage} {totalPages} {basePath} {activeTag} />
            <div class="grow"></div>
            <div class="bg-white rounded-xs font-light">
                <div class="inline-flex text-xs p-2">
                    {#if totalCount > 0}
                        {t(T.blog_count, {
                            visible: posts.length,
                            total: totalCount,
                            current: currentPage,
                            totalPages,
                        })}
                    {:else}
                        {t(T.blog_count, {
                            visible: 0,
                            total: 0,
                            current: currentPage,
                            totalPages,
                        })}
                    {/if}
                </div>
            </div>
        </div>

        <div class="mt-4 text-xs text-stein-600">
            <a
                href="/posts/rss.xml"
                class="inline-flex items-center gap-1 hover:underline"
            >
                <Icon icon="mdi:rss" class="h-3.5 w-3.5" />
                {t(T.blog_rss_subscribe)}
            </a>
        </div>
    {/if}
</div>
