<script lang="ts">
    import type { Component } from 'svelte';

    export interface BottomNavTab {
        label: string;
        href: string;
        icon: Component<{ size?: number; 'aria-hidden'?: boolean | 'true' | 'false' }>;
        /**
         * URL pathname prefixes that mark this tab as active. Longest
         * matching prefix wins across tabs, so order matters less than
         * specificity (e.g. '/profile/account' beats '/profile'). The
         * tab's own `href` is implicitly included.
         */
        match: string[];
    }

    let {
        tabs,
        currentPath,
        testid = 'bottom-nav'
    }: {
        tabs: BottomNavTab[];
        currentPath: string;
        testid?: string;
    } = $props();

    /**
     * Pick the tab with the longest `match` prefix that matches the
     * current path. Ties (no match) fall back to no active tab. Each
     * tab's own href is treated as a match candidate too, so a Home
     * tab pointing at '/' is active on '/' without an explicit entry.
     */
    const activeHref = $derived.by(() => {
        let best: { href: string; len: number } | null = null;
        for (const tab of tabs) {
            const candidates = [tab.href, ...tab.match];
            for (const prefix of candidates) {
                if (!prefixMatches(currentPath, prefix)) continue;
                if (!best || prefix.length > best.len) {
                    best = { href: tab.href, len: prefix.length };
                }
            }
        }
        return best?.href ?? null;
    });

    function prefixMatches(path: string, prefix: string): boolean {
        if (prefix === '/') return path === '/';
        return path === prefix || path.startsWith(prefix + '/');
    }
</script>

<nav class="bottom-nav" aria-label="Primary" data-testid={testid}>
    {#each tabs as tab (tab.href + tab.label)}
        {@const isActive = activeHref === tab.href}
        <a
            href={tab.href}
            class="tab"
            class:active={isActive}
            aria-current={isActive ? 'page' : undefined}
            data-testid={`${testid}-${tab.label.toLowerCase()}`}
        >
            <tab.icon size={22} aria-hidden="true" />
            <span class="label">{tab.label}</span>
        </a>
    {/each}
</nav>

<style>
    .bottom-nav {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: var(--z-sticky);
        /* Explicit columns with `minmax(0, 1fr)` so a single wide tab
           label can't push the bar past the viewport edge. `grid-auto-
           columns: 1fr` resolves to `minmax(auto, 1fr)`, whose auto
           min == intrinsic content width — exactly what we don't want. */
        display: grid;
        grid-template-columns: repeat(var(--bottom-nav-tabs, 4), minmax(0, 1fr));
        background: var(--surface);
        border-top: 1px solid var(--border);
        /* Safe-area inset lifts the bar above the iOS home indicator
           without collapsing the layout on non-notch devices (env()
           resolves to 0 there). */
        padding-bottom: var(--safe-bottom);
        padding-left: var(--safe-left);
        padding-right: var(--safe-right);
        transition: transform 220ms ease-out;
    }

    /* Reader fullscreen mode slides the bar off-screen, mirroring the
       top-header pattern in +layout.svelte. */
    :global(html[data-reader-fullscreen='true']) .bottom-nav {
        transform: translateY(100%);
    }

    .tab {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        padding: var(--space-2) var(--space-1);
        min-height: 56px;
        /* Mirror the grid-column min-width:0 escape so a long label
           clips with the cell rather than expanding it. */
        min-width: 0;
        color: var(--text-muted);
        text-decoration: none;
        transition: color var(--transition);
    }

    .tab:hover {
        color: var(--text);
        text-decoration: none;
    }

    .tab.active {
        color: var(--primary);
    }

    .label {
        max-width: 100%;
        font-size: var(--font-xs);
        font-weight: var(--weight-medium);
        line-height: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
</style>
