import { IGXE } from "@intelligentgraphics/igd.core";
import { Cancellation } from "@intelligentgraphics/ig.utilities";
export const executeConfigureArticlesOperation = async (comIds, changes, articleQuery, scheduler, productDataManager) => {
    const results = [];
    const roots = findArticleRoots(comIds, articleQuery);
    const processArticle = async (comId, context) => {
        const article = articleQuery.getArticleByComId(comId);
        if (article.categories.onlyConfigurableThroughParent) {
            if (context.parentConfigured) {
                results.push({
                    type: "configure",
                    comId,
                });
            }
            return processChildren(article, productDataManager, context);
        }
        // if (article.categories.inheritParentConfiguration) {
        // }
        results.push(await scheduler
            .queueConfigureOperation(article.comId, IGXE.normalizePropertyValueChanges(changes), changes => configureArticle(article, changes, productDataManager))
            .catch(error => Cancellation.isCancelError(error)
            ? Promise.resolve(undefined)
            : Promise.reject(error)));
        return processChildren(article, productDataManager, {
            ...context,
            parentConfigured: true,
        });
    };
    const processChildren = async (article, productDataManager, branchContext) => {
        // if (!article.categories.autoChildren) {
        // 	return Promise.all(
        // 		article.children.map(comId =>
        // 			processArticle(comId, branchContext),
        // 		),
        // 	);
        // }
        const aliveChildren = await productDataManager.getSubArticleIDs(article.comId);
        const currentChildren = article.children;
        const allChildComIds = Array.from(new Set([...aliveChildren, ...currentChildren]));
        await Promise.all(allChildComIds.map(comId => {
            const created = currentChildren.indexOf(comId) === -1;
            if (created) {
                results.push({
                    type: "create",
                    comId,
                    parent: article.comId,
                });
                return;
            }
            const deleted = aliveChildren.indexOf(comId) === -1;
            if (deleted) {
                results.push({
                    type: "delete",
                    comId,
                });
                return;
            }
            return processArticle(comId, branchContext);
        }));
    };
    await Promise.all(roots.map(comId => processArticle(comId, {})));
    return results.filter(Boolean);
};
const configureArticle = async (article, changes, productDataManager) => {
    const optimizedChanges = getPotentialChanges(article.configuration, changes);
    if (optimizedChanges === false) {
        return;
    }
    await productDataManager.setPropValues(article.comId, optimizedChanges);
    return {
        type: "configure",
        comId: article.comId,
    };
};
const findArticleRoots = (comIds, articleQuery) => {
    const result = new Set();
    for (const comId of comIds) {
        const article = articleQuery.getArticleByComId(comId);
        if (article === undefined) {
            continue;
        }
        if (article.parent === undefined) {
            result.add(comId);
            continue;
        }
        const parent = articleQuery.getFirstArticleParent(comId, article => article.parent === undefined);
        result.add(parent.comId);
    }
    return Array.from(result);
};
/**
 * Determines changes between two article configurations/property change objects
 *
 * Returns false when both are equal.
 * Omits all values which are equal between both objects.
 *
 * @param {IGXE.ArticleConfigurationValues} currentConfiguration
 * @param {IGXE.PropertyValueChanges} changes
 * @returns
 */
const getPotentialChanges = (currentConfiguration, changes) => {
    const optimizedChanges = new Map();
    const normalizedChanges = IGXE.normalizePropertyValueChanges(changes);
    for (const { key, value } of normalizedChanges) {
        if (currentConfiguration[key] !== value) {
            optimizedChanges.set(key, value);
        }
    }
    if (optimizedChanges.size === 0) {
        return false;
    }
    const resultChanges = [];
    for (const [key, value] of optimizedChanges) {
        resultChanges.push({
            key,
            value,
        });
    }
    return resultChanges;
};
