<script lang="ts">
    import { api } from "$lib/api.js";
    import type { EventStatus } from "@blade-and-brawn/api";
    import { onMount } from "svelte";

    type EventRow = NonNullable<
        Awaited<ReturnType<typeof api.events.get>>["data"]
    >[number];

    const LIMIT = 25;

    const STATUS_BADGE: Record<EventStatus, string> = {
        waiting: "badge-ghost",
        available: "badge-info",
        processing: "badge-warning",
        failed: "badge-error",
        resolved: "badge-success",
    };

    const groups = (await api.events.groups.get()).data ?? [];

    let events = $state<EventRow[]>([]);
    let loading = $state(true);
    let loadError = $state<string | null>(null);
    let offset = $state(0);
    let group = $state("");
    let status = $state<EventStatus | "">("");
    let retryingIds = $state<string[]>([]);

    function errorMessage(err: unknown): string {
        const value = (err as { value?: { error?: string } })?.value;
        return (
            value?.error ??
            (err instanceof Error ? err.message : "Unknown error")
        );
    }

    function formatLabel(value: string): string {
        return value
            .replace(/_/g, " ")
            .replace(/\b\w/g, (c) => c.toUpperCase());
    }

    function formatDate(value: string | Date | null): string {
        if (!value) return "—";
        return new Date(value).toLocaleString();
    }

    function errorSummary(lastError: unknown): string {
        if (
            lastError &&
            typeof lastError === "object" &&
            "message" in lastError
        ) {
            return String((lastError as { message: unknown }).message);
        }
        return "View error";
    }

    async function refresh() {
        loading = true;
        loadError = null;
        try {
            const res = await api.events.get({
                query: {
                    group: group || undefined,
                    status: status || undefined,
                    limit: LIMIT,
                    offset,
                },
            });
            if (res.error) throw res.error;
            events = res.data as EventRow[];
        } catch (err) {
            loadError = errorMessage(err);
        } finally {
            loading = false;
        }
    }

    function setGroup(value: string) {
        group = value;
        offset = 0;
        refresh();
    }

    function setStatus(value: string) {
        status = value as EventStatus | "";
        offset = 0;
        refresh();
    }

    function prevPage() {
        offset = Math.max(0, offset - LIMIT);
        refresh();
    }

    function nextPage() {
        offset += LIMIT;
        refresh();
    }

    async function retry(id: string) {
        retryingIds = [...retryingIds, id];
        try {
            const res = await api.events({ id }).retry.post();
            if (res.error) throw res.error;
            await refresh();
        } catch (err) {
            loadError = errorMessage(err);
        } finally {
            retryingIds = retryingIds.filter((x) => x !== id);
        }
    }

    onMount(refresh);
</script>

<div class="w-full flex items-center gap-2 flex-wrap mt-10 mb-5">
    <select
        class="select select-sm w-40"
        value={group}
        onchange={(e) => setGroup(e.currentTarget.value)}
    >
        <option value="">All groups</option>
        {#each groups as group}
            <option value={group}>{formatLabel(group)}</option>
        {/each}
    </select>

    <select
        class="select select-sm w-40"
        value={status}
        onchange={(e) => setStatus(e.currentTarget.value)}
    >
        <option value="">All statuses</option>
        <option value="waiting">Waiting</option>
        <option value="available">Available</option>
        <option value="processing">Processing</option>
        <option value="failed">Failed</option>
        <option value="resolved">Resolved</option>
    </select>

    <button
        class="btn btn-secondary btn-sm"
        onclick={refresh}
        disabled={loading}
    >
        {loading ? "Refreshing..." : "Refresh"}
    </button>

    <div class="flex-1"></div>

    <button
        class="btn btn-neutral btn-sm"
        onclick={prevPage}
        disabled={offset === 0 || loading}
    >
        Prev
    </button>
    <button
        class="btn btn-neutral btn-sm"
        onclick={nextPage}
        disabled={events.length < LIMIT || loading}
    >
        Next
    </button>
</div>

{#if loadError}
    <div role="alert" class="alert alert-error w-full mb-4">
        <span>{loadError}</span>
    </div>
{/if}

<div class="w-full overflow-x-auto">
    <table class="table">
        <thead>
            <tr>
                <th>Group</th>
                <th>Type</th>
                <th>Status</th>
                <th>Source</th>
                <th>Created</th>
                <th>Started</th>
                <th>Ended</th>
                <th>Errors</th>
                <th>Rate limits</th>
                <th>Last error</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            {#each events as event (event.id)}
                <tr class="hover:bg-base-300">
                    <td>{formatLabel(event.group)}</td>
                    <td>{formatLabel(event.type)}</td>
                    <td
                        ><div class="badge {STATUS_BADGE[event.status]}">
                            {event.status}
                        </div></td
                    >
                    <td>{event.source}</td>
                    <td class="whitespace-nowrap"
                        >{formatDate(event.created_at)}</td
                    >
                    <td class="whitespace-nowrap"
                        >{formatDate(event.started_at)}</td
                    >
                    <td class="whitespace-nowrap"
                        >{formatDate(event.ended_at)}</td
                    >
                    <td>{event.errors}</td>
                    <td>{event.rate_limits}</td>
                    <td>
                        {#if event.last_error}
                            <details>
                                <summary
                                    class="cursor-pointer text-error text-sm"
                                >
                                    {errorSummary(event.last_error)}
                                </summary>
                                <pre
                                    class="text-xs whitespace-pre-wrap max-w-md">{JSON.stringify(
                                        event.last_error,
                                        null,
                                        2,
                                    )}</pre>
                            </details>
                        {:else}
                            —
                        {/if}
                    </td>
                    <td>
                        {#if event.status === "failed"}
                            <button
                                class="btn btn-primary btn-xs"
                                disabled={retryingIds.includes(event.id)}
                                onclick={() => retry(event.id)}
                            >
                                {retryingIds.includes(event.id)
                                    ? "Retrying..."
                                    : "Retry"}
                            </button>
                        {/if}
                    </td>
                </tr>
            {:else}
                <tr>
                    <td colspan="11" class="text-center opacity-60">
                        {loading ? "Loading..." : "No events found"}
                    </td>
                </tr>
            {/each}
        </tbody>
    </table>
</div>
