import { onMounted, onServerPrefetch, type ShallowRef, shallowRef } from "vue";
import useDJSSRContext from "@/useDJSSRContext.ts";

declare global {
    // deno-lint-ignore no-var
    var appstate: Partial<Record<string, unknown>>;
}

export default function useAsyncState<T>(
    key: string,
    getter: (context: { hostUrl: string }) => Promise<T | null>,
    options?: { suspensible: boolean },
): { result: ShallowRef<T | null>; stateIsReady: Promise<unknown> } {
    const ssrContext = useDJSSRContext();
    const isClient = typeof ssrContext === "undefined";

    const registry = ssrContext?.registry ?? globalThis?.appstate;

    const hostUrl = isClient ? globalThis.location.origin : "http://localhost:8080";

    const state = shallowRef<T | null>(null);

    let resolve = () => {};
    const promise = new Promise<void>((res) => {
        resolve = res;
    });

    if (key in registry) {
        state.value = registry[key] as T;
        delete registry[key];
        resolve();
    } else {
        if (!isClient) {
            resolve();
        }
        onServerPrefetch(async () => {
            const result = await getter({ hostUrl });
            registry[key] = result;
            state.value = result;
        });
        if (options?.suspensible ?? true) {
            getter({ hostUrl }).then((result) => {
                state.value = result;
                resolve();
            }).catch(resolve);
        } else {
            onMounted(async () => {
                state.value = await getter({ hostUrl });
                resolve();
            });
        }
    }

    return { result: state, stateIsReady: promise };
}