<script lang="ts">
    import { fileUrl } from '$lib/api/client';
    import type { Manga } from '$lib/api/client';
    import type { AuthorRef, GenreRef } from '$lib/api/mangas';
    import { overflowTooltip } from '$lib/actions/overflowTooltip';
    import BookImage from '@lucide/svelte/icons/book-image';

    let {
        manga,
        authors = [],
        genres = [],
        unreadCount,
        progress,
        testid
    }: {
        manga: Manga;
        authors?: AuthorRef[];
        genres?: GenreRef[];
        /**
         * Number of unread chapters since the user's last read position.
         * Shown as a small badge in the cover's top-right corner; 0 or
         * undefined hides the badge. Counts past 99 cap at "99+".
         */
        unreadCount?: number;
        /**
         * Fraction read [0..1]. Rendered as a thin bar overlaid on the
         * bottom edge of the cover. Out-of-range values clamp; non-
         * positive values hide the bar entirely.
         */
        progress?: number;
        testid?: string;
    } = $props();

    const unreadLabel = $derived(
        unreadCount && unreadCount > 0
            ? unreadCount > 99
                ? '99+'
                : String(unreadCount)
            : null
    );

    const progressPct = $derived(
        progress != null && progress > 0 ? Math.min(progress, 1) * 100 : null
    );
</script>

<li class="manga-card" data-testid={testid}>
    <a href="/manga/{manga.id}" class="cover-link" aria-hidden="true" tabindex="-1">
        {#if manga.cover_image_path}
            <img
                src={fileUrl(manga.cover_image_path)}
                alt=""
                class="cover"
                loading="lazy"
                decoding="async"
            />
        {:else}
            <div class="cover cover-placeholder">
                <BookImage size={36} aria-hidden="true" />
            </div>
        {/if}
        {#if unreadLabel}
            <span
                class="unread-badge"
                data-testid="unread-badge"
                aria-label="{unreadLabel} unread chapter{unreadLabel === '1' ? '' : 's'}"
            >
                {unreadLabel}
            </span>
        {/if}
        {#if progressPct != null}
            <span class="cover-progress" data-testid="cover-progress" aria-hidden="true">
                <span
                    class="cover-progress-fill"
                    data-testid="cover-progress-fill"
                    style="width: {progressPct}%;"
                ></span>
            </span>
        {/if}
    </a>
    <div class="meta">
        <a href="/manga/{manga.id}" class="title" use:overflowTooltip={manga.title}>{manga.title}</a>
        {#if authors.length > 0}
            <span class="author">{authors.map((a) => a.name).join(', ')}</span>
        {/if}
        {#if genres.length > 0}
            <span class="genres">{genres.map((g) => g.name).join(' · ')}</span>
        {/if}
    </div>
</li>

<style>
    /* `.manga-card` layout lives in tokens.css so the catalog cards and the
       loading skeleton share one definition. */

    .cover-link {
        display: block;
        line-height: 0;
        position: relative;
    }

    .unread-badge {
        position: absolute;
        top: var(--space-1);
        right: var(--space-1);
        min-width: 22px;
        height: 22px;
        padding: 0 6px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: var(--primary);
        color: var(--primary-contrast);
        font-size: var(--font-xs);
        font-weight: var(--weight-semibold);
        line-height: 1;
        border-radius: var(--radius-pill);
        box-shadow: var(--shadow-sm);
        pointer-events: none;
    }

    .cover-progress {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 3px;
        background: rgba(0, 0, 0, 0.35);
        border-bottom-left-radius: var(--radius-md);
        border-bottom-right-radius: var(--radius-md);
        overflow: hidden;
    }

    .cover-progress-fill {
        display: block;
        height: 100%;
        background: var(--primary);
    }

    .cover {
        width: 100%;
        aspect-ratio: 2 / 3;
        object-fit: cover;
        border-radius: var(--radius-md);
        background: var(--surface);
    }

    .cover-placeholder {
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--text-muted);
        user-select: none;
    }

    .meta {
        display: flex;
        flex-direction: column;
        min-width: 0;
        gap: var(--space-1);
    }

    .title {
        font-weight: var(--weight-semibold);
        font-size: var(--font-sm);
        line-height: var(--leading-tight);
        color: var(--text);
        overflow: hidden;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        -webkit-box-orient: vertical;
        /* A title made of a single unbreakable string would push the
           card past its 1fr column. `anywhere` keeps normal whitespace
           breaks preferred but lets the renderer cut a long word. */
        overflow-wrap: anywhere;
    }

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

    .author,
    .genres {
        color: var(--text-muted);
        font-size: var(--font-xs);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* On phones the catalog packs 4 covers per row — at that width
       the author + genre lines just become two strips of ellipsized
       noise, and dropping them keeps every cell exactly the same
       height (cover + 2-line title clamp). */
    @media (max-width: 640px) {
        .author,
        .genres {
            display: none;
        }
    }
</style>
