<script lang="ts">
interface Props {
    badge_li: any[];
    event_id: string;
    log_lvl?: number;
}
let { badge_li, event_id, log_lvl = 0 }: Props = $props();

type BucketMin = 5 | 15 | 30 | 60;
let bucket_size: BucketMin = $state(15);
let expanded_bucket: number | null = $state(null);

interface Bucket {
    start_ms: number;
    label: string;
    date_label: string | null;
    count: number;
    badges: any[];
}

interface PrintStats {
    buckets: Bucket[];
    total_printed: number;
    max_count: number;
    span_label: string;
}

function fmt_time(ms: number): string {
    return new Date(ms).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}

function fmt_date(ms: number): string {
    return new Date(ms).toLocaleDateString([], { month: 'short', day: 'numeric' });
}

// Resolved once per page load — timezone abbreviation (e.g. "EDT", "PDT") for the separator label.
const tz_abbr: string =
    Intl.DateTimeFormat('en-US', { timeZoneName: 'short' })
        .formatToParts(new Date())
        .find((p) => p.type === 'timeZoneName')?.value ?? '';

function fmt_date_header(ms: number): string {
    const weekday = new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(ms);
    const date_part = new Intl.DateTimeFormat('en-US', { month: 'long', day: 'numeric' }).format(ms);
    return tz_abbr ? `${weekday} · ${date_part} — ${tz_abbr}` : `${weekday} · ${date_part}`;
}

// Naive UTC strings from the backend have no timezone indicator — append Z so
// the browser parses them as UTC and converts to local time, matching the badge list display.
function parse_utc_ms(dt: string | null | undefined): number {
    if (!dt) return NaN;
    const normalized = dt.match(/Z$|[+-]\d{2}:?\d{2}$/) ? dt : dt + 'Z';
    return new Date(normalized).getTime();
}

let stats: PrintStats = $derived.by(() => {
    const printed = badge_li.filter((b) => (b.print_count ?? 0) >= 1 && b.print_last_datetime);
    if (!printed.length) {
        return { buckets: [], total_printed: 0, max_count: 1, span_label: '' };
    }

    const bucket_ms = bucket_size * 60 * 1000;
    const times = printed
        .map((b) => parse_utc_ms(b.print_last_datetime))
        .filter((t) => !isNaN(t));
    if (!times.length) {
        return { buckets: [], total_printed: printed.length, max_count: 1, span_label: '' };
    }

    const min_raw = Math.min(...times);
    const max_raw = Math.max(...times);
    const start = Math.floor(min_raw / bucket_ms) * bucket_ms;
    const end = Math.ceil((max_raw + 1) / bucket_ms) * bucket_ms;

    const raw_buckets: Omit<Bucket, 'date_label'>[] = [];

    for (let t = start; t < end; t += bucket_ms) {
        const in_bucket = printed.filter((b) => {
            const bt = parse_utc_ms(b.print_last_datetime);
            return bt >= t && bt < t + bucket_ms;
        });
        if (in_bucket.length === 0) continue;

        raw_buckets.push({
            start_ms: t,
            label: fmt_time(t),
            count: in_bucket.length,
            badges: in_bucket
        });
    }

    // Newest-first display; re-assign date separators after reversing.
    raw_buckets.reverse();
    let prev_day = '';
    const buckets: Bucket[] = raw_buckets.map((b) => {
        const day = fmt_date(b.start_ms);
        const date_label = day !== prev_day ? fmt_date_header(b.start_ms) : null;
        prev_day = day;
        return { ...b, date_label };
    });

    const max_count = Math.max(...buckets.map((b) => b.count), 1);
    const span_label =
        buckets.length > 0
            ? `${fmt_date(min_raw)}, ${fmt_time(min_raw)} – ${fmt_time(max_raw)}`
            : '';

    return { buckets, total_printed: printed.length, max_count, span_label };
});

function get_effective_name(badge: any): string {
    return (
        badge.full_name_override ??
        badge.full_name ??
        (`${badge.given_name ?? ''} ${badge.family_name ?? ''}`.trim() || badge.event_badge_id)
    );
}
</script>

<div class="space-y-3">
    <!-- Controls -->
    <div class="flex flex-row flex-wrap items-center gap-3">
        <div class="flex flex-row items-center gap-1">
            <span class="text-sm text-surface-600-400">Window:</span>
            {#each ([5, 15, 30, 60] as BucketMin[]) as sz (sz)}
                <button
                    type="button"
                    onclick={() => { bucket_size = sz; expanded_bucket = null; }}
                    class="btn btn-sm border transition-all"
                    class:preset-filled-primary={bucket_size === sz}
                    class:border-primary-600={bucket_size === sz}
                    class:preset-tonal-surface={bucket_size !== sz}
                    class:border-surface-300-700={bucket_size !== sz}>
                    {sz} min
                </button>
            {/each}
        </div>

        {#if stats.total_printed > 0}
            <span class="text-sm text-surface-600-400">
                {stats.total_printed} printed · {stats.buckets.length} window{stats.buckets.length !== 1 ? 's' : ''} with activity
                {#if stats.span_label}· {stats.span_label}{/if}
            </span>
        {/if}
    </div>

    <!-- Chart / table -->
    {#if stats.total_printed === 0}
        <p class="py-4 text-sm text-surface-600-400">No printed badges found for this event.</p>
    {:else if stats.buckets.length === 0}
        <p class="py-4 text-sm text-surface-600-400">No valid print timestamps found.</p>
    {:else}
        <div class="space-y-0.5">
            {#each stats.buckets as bucket (bucket.start_ms)}
                <!-- Date separator when the day changes -->
                {#if bucket.date_label}
                    <div class="pt-2 pb-1 text-xs font-semibold tracking-wide text-surface-500-400">
                        {bucket.date_label}
                    </div>
                {/if}

                <!-- Bar row -->
                <div class="group rounded border border-transparent hover:border-surface-200 dark:hover:border-surface-700 transition-colors">
                    <button
                        type="button"
                        onclick={() => (expanded_bucket = expanded_bucket === bucket.start_ms ? null : bucket.start_ms)}
                        class="flex w-full flex-row items-center gap-2 rounded px-2 py-1.5 text-left hover:bg-surface-50 dark:hover:bg-surface-900/50 transition-colors">
                        <!-- Time label -->
                        <span class="w-18 shrink-0 font-mono text-sm">
                            {bucket.label}
                        </span>

                        <!-- Bar -->
                        <div class="flex-1 overflow-hidden rounded-sm bg-surface-200 dark:bg-surface-700 h-5">
                            <div
                                class="h-full rounded-sm transition-all duration-300"
                                class:bg-primary-500={bucket.count < stats.max_count}
                                class:bg-primary-400={bucket.count === stats.max_count && stats.max_count > 1}
                                class:dark:bg-primary-400={bucket.count < stats.max_count}
                                class:dark:bg-primary-300={bucket.count === stats.max_count && stats.max_count > 1}
                                style:width="{Math.round((bucket.count / stats.max_count) * 100)}%">
                            </div>
                        </div>

                        <!-- Count -->
                        <span
                            class="w-8 shrink-0 text-right text-sm font-semibold"
                            class:text-primary-600={bucket.count === stats.max_count && stats.max_count > 1}
                            class:dark:text-primary-400={bucket.count === stats.max_count && stats.max_count > 1}>
                            {bucket.count}
                        </span>

                        <!-- Peak chip -->
                        <span class="w-10 shrink-0 text-right">
                            {#if bucket.count === stats.max_count && stats.max_count > 1}
                                <span class="rounded bg-primary-100 dark:bg-primary-900/40 px-1 text-xs text-primary-700 dark:text-primary-300">peak</span>
                            {/if}
                        </span>
                    </button>

                    <!-- Expanded badge list -->
                    {#if expanded_bucket === bucket.start_ms}
                        <div class="mx-2 mb-2 rounded border border-surface-200 dark:border-surface-700 bg-surface-50 dark:bg-surface-900/30 px-3 py-2">
                            <div class="flex flex-row flex-wrap gap-1">
                                {#each bucket.badges as b (b.event_badge_id)}
                                    <a
                                        href={`/events/${event_id}/badges/${b.event_badge_id}/print`}
                                        class="rounded border border-surface-200 dark:border-surface-700 bg-white dark:bg-surface-800 px-2 py-0.5 text-xs hover:border-primary-300 dark:hover:border-primary-600 hover:bg-primary-50 dark:hover:bg-primary-900/20 transition-colors">
                                        {get_effective_name(b)}
                                    </a>
                                {/each}
                            </div>
                            <p class="mt-1.5 text-right text-xs text-surface-500-400">
                                {bucket.count} badge{bucket.count !== 1 ? 's' : ''} printed in this {bucket_size}-min window · click to open
                            </p>
                        </div>
                    {/if}
                </div>
            {/each}
        </div>

        <!-- Summary row -->
        <div class="mt-3 flex flex-row flex-wrap gap-4 border-t border-surface-200 dark:border-surface-700 pt-3 text-sm text-surface-600-400">
            <span>Total printed: <span class="font-semibold text-inherit">{stats.total_printed}</span></span>
            <span>Peak window: <span class="font-semibold text-inherit">{stats.max_count}</span> in {bucket_size} min</span>
            <span>Avg per window: <span class="font-semibold text-inherit">{stats.buckets.length ? (stats.total_printed / stats.buckets.length).toFixed(1) : '—'}</span></span>
        </div>
    {/if}
</div>
