import { IGXA } from "@intelligentgraphics/igd.core";
export const createCatalogFetcher = (session, igxrLoader, language) => {
    const cache = new Map();
    const createOperation = (createIdentifier, fetch) => (...args) => executeOperation(createIdentifier, fetch, args);
    const executeOperation = (createIdentifier, executeOperation, args) => {
        const identifier = createIdentifier(...args);
        const cachedValued = cache.get(identifier);
        if (cachedValued !== undefined) {
            return Promise.resolve(cachedValued);
        }
        const fetchResult = executeOperation(...args);
        cache.set(identifier, fetchResult);
        if (typeof fetchResult === "object" && "then" in fetchResult) {
            const fetchResultPromise = fetchResult;
            return fetchResultPromise
                .then(result => {
                cache.set(identifier, result);
                return result;
            })
                .catch(err => {
                cache.delete(identifier);
                return Promise.reject(err);
            });
        }
        return Promise.resolve(fetchResult);
    };
    const getCatalogManager = async (catalogId) => {
        let catalogManager = session.getCatalogManagerForSourceId(catalogId);
        if (catalogManager !== undefined) {
            return catalogManager;
        }
        if (igxrLoader === undefined) {
            throw new Error(`The catalog "${catalogId}" is not yet registered, and no igxr loader was provided. The catalog can not be automatically registered.`);
        }
        await igxrLoader.addCatalogToSession(catalogId, session);
        catalogManager = session.getCatalogManagerForSourceId(catalogId);
        if (catalogManager === undefined) {
            throw new Error(`No catalogmanager is available for source "${catalogId}" even after registering the catalog`);
        }
        return catalogManager;
    };
    const getFolder = createOperation((path) => "folder_" + path.join(":"), async ([catalogId, ...path]) => {
        const catalogManager = await getCatalogManager(catalogId);
        const folder = await catalogManager.getFolder(path[path.length - 1]);
        if (folder === undefined) {
            throw new Error(`Could not get folder for folder id "${path[path.length - 1]}" inside "${catalogId}"`);
        }
        return folder;
    });
    // const getArticle = createOperation(
    // 	(path: string[]) => "article_" + path.join(":"),
    // 	async ([catalogId, ...path]: string[]) => {
    // 		const catalogManager = await getCatalogManager(catalogId);
    // 		const article = await catalogManager.getArticle(
    // 			path[path.length - 1],
    // 		);
    // 		if (article === undefined) {
    // 			throw new Error(
    // 				`Could not get article for article id "${
    // 					path[path.length - 1]
    // 				}" inside "${catalogId}"`,
    // 			);
    // 		}
    // 		return article;
    // 	},
    // );
    // const getSet = createOperation(
    // 	(path: string[]) => "set" + path.join(":"),
    // 	async ([catalogId, ...path]: string[]) => {
    // 		const catalogManager = await getCatalogManager(catalogId);
    // 		const set = await catalogManager.getSet(path[path.length - 1]);
    // 		if (set === undefined) {
    // 			throw new Error(
    // 				`Could not get set for set id "${
    // 					path[path.length - 1]
    // 				}" inside "${catalogId}"`,
    // 			);
    // 		}
    // 		return set;
    // 	},
    // );
    const getAddables = createOperation((path, baseArticleNumber) => "addables_" + path.join(":") + "_" + baseArticleNumber, async ([catalogId], baseArticleNumber) => {
        const catalogManager = await getCatalogManager(catalogId);
        const addables = await catalogManager.getAddables(baseArticleNumber);
        return addables;
    });
    const getCatalog = ([catalogId]) => {
        if (igxrLoader === undefined) {
            return Promise.reject(new Error(`Could not retrieve informations for catalog "${catalogId}", because no igxr loader was provided.`));
        }
        const catalog = igxrLoader.getCatalogInfo(catalogId, language);
        if (catalog === undefined) {
            return Promise.reject(new Error(`Could not find informations for catalog "${catalogId}"`));
        }
        return Promise.resolve({
            ID: catalogId,
            ManufacturerName: catalog.ManufacturerName,
            CatalogName: catalog.CatalogName,
            Type: IGXA.EItemType.Catalog,
            Caption: catalog.CatalogName,
        });
    };
    const getPathContent = createOperation((path) => `path_content_` + path.join(":"), async (path) => {
        if (path.length === 0) {
            if (igxrLoader === undefined) {
                throw new Error(`Can not retrieve a list of catalogs, because no igxr loader was provided`);
            }
            return igxrLoader
                .getCatalogList(language)
                .filter(catalog => !catalog.Hidden)
                .map(catalog => ({
                Type: IGXA.EItemType.Catalog,
                ID: catalog.SourceId,
                ManufacturerName: catalog.ManufacturerName,
                CatalogName: catalog.CatalogName,
                Image: catalog.Image,
                Caption: catalog.CatalogName,
            }));
        }
        const [catalogId, ...inCatalogPath] = path;
        const catalogManager = await getCatalogManager(catalogId);
        const items = [];
        const content = await catalogManager.getFolderContent(inCatalogPath[inCatalogPath.length - 1]);
        return [...items, ...content];
    });
    const getPathEntries = (path) => {
        if (path.length === 0) {
            return Promise.resolve([]);
        }
        return Promise.all(path.map((pathEntry, index) => {
            const itemPath = path.slice(0, index + 1);
            if (itemPath.length === 1) {
                return getCatalog(itemPath);
            }
            return getFolder(itemPath);
        }));
    };
    const getReadablePath = (path) => getPathEntries(path).then(entries => entries.map(entry => {
        if (entry.Type === IGXA.EItemType.Catalog) {
            return entry.CatalogName;
        }
        return IGXA.extractLocalizedText(entry.Caption, language).join(" ");
    }));
    const getCatalogWizard = (path) => {
        if (igxrLoader === undefined) {
            throw new Error(`Can not retrieve a wizard for catalog "${path[0]}", because no igxr loader was provided.`);
        }
        const wizard = igxrLoader.getWizard(path[0], language);
        if (wizard === undefined) {
            return Promise.resolve(undefined);
        }
        return Promise.resolve({
            Type: IGXA.EItemType.Wizard,
            ID: path[0],
            Image: wizard.Image,
            Caption: wizard.Name || "Wizard",
        });
    };
    return {
        getFolder,
        // getArticle,
        // getSet,
        getAddables,
        getCatalog,
        getPathContent,
        getPathEntries,
        getReadablePath,
        getCatalogWizard,
    };
};
