import {readonly, writable} from "svelte/store";

import type {Readable, Subscriber, Unsubscriber} from "svelte/store";

export interface Cached<T> extends Readable<T>{
    reload: () => void;
}

export function cached<T>(normal: T, init: () => Promise<T>): Cached<T> {
    const store = writable<T>(normal);
    let first = true;

    const reload = () => {
        init().then(data => {
            store.set(data);
        });
    }

    return {
        ...readonly(store),
        subscribe: (run: Subscriber<T>, invalidate?: (value?: T) => void): Unsubscriber => {
            if(first) {
                first = false;
                reload();
            }
            return store.subscribe(run, invalidate);
        },
        reload
    };
}

export function cachedFamily<T, K>(normal: K, init: (arg0: T) => Promise<K>): (arg: T) => Cached<K> {
    const stores: Map<T, Cached<K>> = new Map();
    return (arg: T) => {
        if(stores.has(arg)) {
            return stores.get(arg)!!;
        } else {
            const store = writable<K>(normal);
            let first = true;

            const reload = () => {
                init(arg).then(data => {
                    store.set(data);
                });
            }

            const cachedStore = {
                ...readonly(store),
                subscribe: (run: Subscriber<K>, invalidate?: (value?: K) => void): Unsubscriber => {
                    if(first) {
                        first = false;
                        reload();
                    }
                    return store.subscribe(run, invalidate);
                },
                reload
            } as Cached<K>;

            stores.set(arg, cachedStore);
            return cachedStore;
        }
    }
}
