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

    type ProductRow = NonNullable<
        Awaited<ReturnType<typeof api.commerce.products.get>>["data"]
    >[number];

    type SyncStatus = EventStatus | "none";

    const LIMIT = 25;

    let products = $state<ProductRow[]>([]);
    let loading = $state(true);
    let loadError = $state<string | null>(null);
    let offset = $state(0);

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

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

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

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

    const synchronizer = $state({
        status: "none" as SyncStatus,
        syncingPProductIds: [] as number[],
        get isInProgress() {
            return (
                this.status !== "failed" &&
                this.status !== "resolved" &&
                this.status !== "none"
            );
        },
        poll: async function () {
            const res = await api.commerce.products.sync.get();
            if (res.error) {
                synchronizer.status = "none";
                synchronizer.syncingPProductIds = [];
            } else {
                synchronizer.status = res.data.status;
                synchronizer.syncingPProductIds = res.data.syncingPProductIds;
            }
        },
        startPolling: () => {
            const intervalId = setInterval(async () => {
                const wasInProgress = synchronizer.isInProgress;
                await synchronizer.poll();
                if (!synchronizer.isInProgress) {
                    clearInterval(intervalId);
                    if (wasInProgress) refresh();
                }
            }, 100);
        },
        syncAll: async () => {
            synchronizer.startPolling();
            await api.commerce.products.sync.post();
        },
        sync: async (pProductId: number) => {
            synchronizer.startPolling();
            await api.commerce.products.sync({ pProductId }).post();
        },
    });

    onMount(async () => {
        await synchronizer.poll();
        if (synchronizer.isInProgress) {
            synchronizer.startPolling();
        }
        await refresh();
    });
</script>

<div class="w-full flex items-center gap-2 flex-wrap mt-10 mb-5">
    <button
        disabled={synchronizer.isInProgress}
        onclick={() => synchronizer.syncAll()}
        class="btn btn-primary btn-sm"
    >
        {#if synchronizer.isInProgress}
            Syncing...
        {:else}
            Sync all
        {/if}
    </button>

    <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={products.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>Name</th>
                <th>Status</th>
                <th>Sync</th>
            </tr>
        </thead>
        <tbody>
            {#each products as product (product.pProduct.id)}
                <tr class="hover:bg-base-300">
                    <td
                        ><button
                            onclick={async () => {
                                const res = await api.commerce
                                    .products({
                                        pProductId: product.pProduct.id,
                                    })
                                    .get();
                                console.log(res.data);
                            }}
                            class="cursor-pointer underline"
                        >
                            {product.pProduct.name}
                        </button></td
                    >
                    <td>
                        {#if synchronizer.syncingPProductIds.includes(product.pProduct.id)}
                            <div class="badge badge-warning">Syncing...</div>
                        {:else if product.isSynced}
                            <div class="badge badge-success">Synced</div>
                        {:else}
                            <div class="badge badge-error">Desynced</div>
                        {/if}
                    </td>
                    <td>
                        <button
                            disabled={synchronizer.status === "processing"}
                            onclick={() =>
                                synchronizer.sync(product.pProduct.id)}
                            class="btn btn-primary btn-xs"
                        >
                            Sync
                        </button>
                    </td>
                </tr>
            {:else}
                <tr>
                    <td colspan="3" class="text-center opacity-60">
                        {loading ? "Loading..." : "No products found"}
                    </td>
                </tr>
            {/each}
        </tbody>
    </table>
</div>
