import type { Class } from "@common/types";

export namespace Resources {
    const resources = new Map<Function, Map<string, any>>();

    export function get<T>(id: string): T | undefined;
    export function get(ctor: StringConstructor, id: string): string | undefined;
    export function get(ctor: NumberConstructor, id: string): number | undefined;
    export function get(ctor: BooleanConstructor, id: string): boolean | undefined;
    export function get<T>(ctor: Class<T>, id: string): T | undefined;
    export function get<T>(ctorOrId: Class<T> | string, id?: string): T | undefined {
        const ctor = typeof ctorOrId === 'string' ? undefined : ctorOrId;
        id = typeof ctorOrId === 'string' ? ctorOrId : id;
        if (id == null) return undefined;
        if (ctor == null) {
            for (const ns of resources.values()) {
                if (ns.has(id)) {
                    return ns.get(id) as T;
                }
            }
            return undefined
        }

        return resources.get(ctor)?.get(id) as T;
    }

    export function add<T>(id: string, value: NonNullable<T>): string {
        const ctor = value.constructor;
        const namespace: Map<string, T> = resources.get(ctor) ?? new Map();
        if (namespace.has(id)) throw new Error(`Resource "${id}" is already registered`);
        namespace.set(id, value);
        resources.set(ctor, namespace);
        return id;
    }

    export function update<T>(id: string, value: NonNullable<T>): string {
        const ctor = value.constructor;
        const namespace: Map<string, T> = resources.get(ctor) ?? new Map();
        namespace.set(id, value);
        resources.set(ctor, namespace);
        return id;
    }
}
