export * from "@softarc/native-federation/domain";
import { initFederation as internalInitFederation, } from "@softarc/native-federation-orchestrator";
import { useShimImportMap, useDefaultImportMap, consoleLogger, } from "@softarc/native-federation-orchestrator/options";
let resolveFirstInit;
let rejectFirstInit;
let firstInitCaptured = false;
let federationPromise = new Promise((resolve, reject) => {
    resolveFirstInit = resolve;
    rejectFirstInit = reject;
});
export function initFederation(remotesOrManifestUrl, options = {}) {
    const { cacheTag, shimMode, ...nfOpts } = options;
    const importMapProvider = shimMode === false
        ? useDefaultImportMap()
        : useShimImportMap({ shimMode: true });
    const p = internalInitFederation(remotesOrManifestUrl ?? {}, {
        ...importMapProvider,
        logger: consoleLogger,
        hostRemoteEntry: { url: "./remoteEntry.json", cacheTag },
        ...nfOpts,
    });
    if (!firstInitCaptured) {
        firstInitCaptured = true;
        p.then(resolveFirstInit, rejectFirstInit);
    }
    federationPromise = p;
    return p;
}
function normalizeOptions(optionsOrRemoteName, exposedModule) {
    if (typeof optionsOrRemoteName === "string" && exposedModule) {
        return { remoteName: optionsOrRemoteName, exposedModule };
    }
    if (typeof optionsOrRemoteName === "object" && !exposedModule) {
        return optionsOrRemoteName;
    }
    throw new Error("unexpected arguments: please pass options or a remoteName/exposedModule-pair");
}
function logClientError(error) {
    if (typeof window !== "undefined") {
        console.error(error);
    }
}
async function resolveRemoteNameFromEntry(remoteEntry) {
    const res = await fetch(remoteEntry);
    if (!res.ok) {
        throw new Error(`Failed to fetch remoteEntry at ${remoteEntry}: ${res.status} ${res.statusText}`);
    }
    const info = (await res.json());
    if (!info.name) {
        throw new Error(`remoteEntry at ${remoteEntry} does not declare a 'name'`);
    }
    return info.name;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function loadRemoteModule(optionsOrRemoteName, exposedModule) {
    const options = normalizeOptions(optionsOrRemoteName, exposedModule);
    const { fallback } = options;
    try {
        let federation = await federationPromise;
        if (!options.remoteName && options.remoteEntry) {
            options.remoteName = await resolveRemoteNameFromEntry(options.remoteEntry);
        }
        if (options.remoteEntry) {
            federation = await federation.initRemoteEntry(options.remoteEntry, options.remoteName);
        }
        if (!options.remoteName) {
            const err = "unexpected arguments: Please pass remoteName or remoteEntry";
            if (!fallback)
                throw new Error(err);
            logClientError(err);
            return fallback;
        }
        return await federation.loadRemoteModule(options.remoteName, options.exposedModule);
    }
    catch (err) {
        if (fallback) {
            logClientError("error loading remote module: " +
                (err instanceof Error ? err.message : String(err)));
            return fallback;
        }
        throw err;
    }
}
