<script lang="ts">
    type Props = {
        page: number;
        totalPages: number;
        onChange: (page: number) => void;
        testid?: string;
    };

    let { page, totalPages, onChange, testid }: Props = $props();

    type Slot = number | 'ellipsis';

    // Compact layout: always show first + last, surround the current page with
    // its direct neighbours, and use "…" to elide the rest. Keeps the bar to
    // at most 7 buttons regardless of totalPages.
    function buildSlots(p: number, total: number): Slot[] {
        if (total <= 7) {
            return Array.from({ length: total }, (_, i) => i + 1);
        }
        const out: Slot[] = [1];
        if (p <= 4) {
            for (let i = 2; i <= 5; i++) out.push(i);
            out.push('ellipsis');
            out.push(total);
        } else if (p >= total - 3) {
            out.push('ellipsis');
            for (let i = total - 4; i <= total; i++) out.push(i);
        } else {
            out.push('ellipsis');
            out.push(p - 1);
            out.push(p);
            out.push(p + 1);
            out.push('ellipsis');
            out.push(total);
        }
        return out;
    }

    const slots = $derived(buildSlots(page, totalPages));
</script>

{#if totalPages > 1}
    <nav class="pager" aria-label="Pagination" data-testid={testid}>
        <button
            type="button"
            class="step"
            disabled={page <= 1}
            onclick={() => onChange(page - 1)}
            aria-label="Previous page"
        >
            ‹ Prev
        </button>

        {#each slots as slot, i (i)}
            {#if slot === 'ellipsis'}
                <span class="ellipsis" aria-hidden="true">…</span>
            {:else}
                <button
                    type="button"
                    class="num"
                    class:active={slot === page}
                    aria-current={slot === page ? 'page' : undefined}
                    aria-label={`Go to page ${slot}`}
                    onclick={() => onChange(slot)}
                >
                    {slot}
                </button>
            {/if}
        {/each}

        <button
            type="button"
            class="step"
            disabled={page >= totalPages}
            onclick={() => onChange(page + 1)}
            aria-label="Next page"
        >
            Next ›
        </button>
    </nav>
{/if}

<style>
    .pager {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--space-1);
        margin: var(--space-4) 0;
        justify-content: center;
    }

    .step,
    .num {
        min-width: 36px;
        height: 36px;
        padding: 0 var(--space-2);
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-md);
        color: var(--text);
        cursor: pointer;
        font-size: var(--font-sm);
    }

    .step:hover:not(:disabled),
    .num:hover:not(.active) {
        border-color: var(--primary);
    }

    .step:disabled {
        opacity: 0.4;
        cursor: not-allowed;
    }

    .num.active {
        background: var(--primary);
        color: var(--primary-contrast);
        border-color: var(--primary);
        cursor: default;
    }

    .ellipsis {
        padding: 0 var(--space-1);
        color: var(--text-muted);
        user-select: none;
    }
</style>
