'use strict';

var runtime = require('@module-federation/runtime');
var sdk = require('@module-federation/sdk');
var runtimeUtils = require('./runtime-utils.cjs.js');

var // @ts-ignore init global variable for test
_globalThis, _globalThis___FEDERATION__;
var ___FEDERATION__;
(___FEDERATION__ = (_globalThis = globalThis).__FEDERATION__) != null ? ___FEDERATION__ : _globalThis.__FEDERATION__ = {};
var ___PREFETCH__;
(___PREFETCH__ = (_globalThis___FEDERATION__ = globalThis.__FEDERATION__).__PREFETCH__) != null ? ___PREFETCH__ : _globalThis___FEDERATION__.__PREFETCH__ = {
    entryLoading: {},
    instance: new Map(),
    __PREFETCH_EXPORTS__: {}
};
class MFDataPrefetch {
    get global() {
        return globalThis.__FEDERATION__.__PREFETCH__;
    }
    static getInstance(id) {
        return globalThis.__FEDERATION__.__PREFETCH__.instance.get(id);
    }
    async loadEntry(entry) {
        const { name, remoteSnapshot, remote, origin } = this._options;
        if (entry) {
            const { buildVersion, globalName } = remoteSnapshot;
            const uniqueKey = globalName || `${name}:${buildVersion}`;
            if (!this.global.entryLoading[uniqueKey]) {
                this.global.entryLoading[uniqueKey] = sdk.loadScript(entry, {});
            }
            return this.global.entryLoading[uniqueKey];
        } else {
            const remoteInfo = runtime.getRemoteInfo(remote);
            const module = origin.moduleCache.get(remoteInfo.name);
            return runtime.getRemoteEntry({
                origin: origin,
                remoteInfo,
                remoteEntryExports: module ? module.remoteEntryExports : undefined
            });
        }
    }
    getProjectExports() {
        var _globalThis___FEDERATION_____PREFETCH_____PREFETCH_EXPORTS__;
        if (Object.keys(this._exports).length > 0) {
            return this._exports;
        }
        const { name } = this._options;
        const exportsPromiseFn = (_globalThis___FEDERATION_____PREFETCH_____PREFETCH_EXPORTS__ = globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__) == null ? void 0 : _globalThis___FEDERATION_____PREFETCH_____PREFETCH_EXPORTS__[name];
        const exportsPromise = typeof exportsPromiseFn === 'function' ? exportsPromiseFn() : exportsPromiseFn;
        const resolve = exportsPromise.then((exports = {})=>{
            // Match prefetch based on the function name suffix so that other capabilities can be expanded later.
            // Not all functions should be directly identified as prefetch functions
            const memory = {};
            Object.keys(exports).forEach((key)=>{
                memory[key] = {};
                const exportVal = exports[key];
                Object.keys(exportVal).reduce((memo, current)=>{
                    if (current.toLocaleLowerCase().endsWith('prefetch') || current.toLocaleLowerCase() === 'default') {
                        memo[current] = exportVal[current];
                    }
                    return memo;
                }, memory[key]);
            });
            this.memorizeExports(memory);
        });
        return resolve;
    }
    memorizeExports(exports) {
        this._exports = exports;
    }
    getExposeExports(id) {
        const prefetchId = runtimeUtils.getPrefetchId(id);
        const compatId = runtimeUtils.compatGetPrefetchId(id);
        const prefetchExports = this._exports[prefetchId] || this._exports[compatId];
        return prefetchExports || {};
    }
    prefetch(prefetchOptions) {
        const { id, functionId = 'default', refetchParams } = prefetchOptions;
        let prefetchResult;
        const prefetchId = runtimeUtils.getPrefetchId(id);
        const compatId = runtimeUtils.compatGetPrefetchId(id);
        const memorizeId = id + functionId;
        const memory = this.prefetchMemory.get(memorizeId);
        if (!this.checkOutdate(prefetchOptions) && memory) {
            return memory;
        }
        const prefetchExports = this._exports[prefetchId] || this._exports[compatId];
        if (!prefetchExports) {
            return;
        }
        const executePrefetch = prefetchExports[functionId];
        if (typeof executePrefetch === 'function') {
            if (refetchParams) {
                prefetchResult = executePrefetch(refetchParams);
            } else {
                prefetchResult = executePrefetch();
            }
        } else {
            throw new Error(`[Module Federation Data Prefetch]: No prefetch function called ${functionId} export in prefetch file`);
        }
        this.memorize(memorizeId, prefetchResult);
        return prefetchResult;
    }
    memorize(id, value) {
        this.prefetchMemory.set(id, value);
    }
    markOutdate(markOptions, isOutdate) {
        const { id, functionId = 'default' } = markOptions;
        if (!this.recordOutdate[id]) {
            this.recordOutdate[id] = {};
        }
        this.recordOutdate[id][functionId] = isOutdate;
    }
    checkOutdate(outdateOptions) {
        const { id, functionId = 'default', cacheStrategy } = outdateOptions;
        if (typeof cacheStrategy === 'function') {
            return cacheStrategy();
        }
        if (!this.recordOutdate[id]) {
            this.recordOutdate[id] = {};
        }
        if (this.recordOutdate[id][functionId]) {
            this.markOutdate({
                id,
                functionId
            }, false);
            return true;
        } else {
            return false;
        }
    }
    constructor(options){
        this.prefetchMemory = new Map();
        this.recordOutdate = {};
        this._exports = {};
        this._options = options;
        this.global.instance.set(options.name, this);
    }
}

exports.MFDataPrefetch = MFDataPrefetch;
