import { createCategories } from "../ArticleCategories";
import { executeCloneArticleOperation } from "./Cloning";
import { executeConfigureArticlesOperation } from "./Configuration";
import { executeDeleteOperation } from "./Deletion";
import { executeCreateArticleOperation } from "./Creation";
import { executeRestoreOperation, executeRestoreSessionProviderOperation, } from "./Restoring";
import { fetchArticleData, fetchArticleInfo } from "./Util";
export const createPDMOperator = (sourceId, productDataManager, articleQuery, scheduler) => {
    const sessionOperator = productDataManager.is("SessionProvider")
        ? createSessionOperator(sourceId, productDataManager, articleQuery)
        : undefined;
    const is = (name) => {
        if (name === "sessionOperator") {
            return sessionOperator !== undefined;
        }
        return false;
    };
    const addArticle = (params) => executeCreateArticleOperation(params, articleQuery, productDataManager).then(buildOperationResults);
    const configureArticles = (comIds, changes) => executeConfigureArticlesOperation(comIds, changes, articleQuery, scheduler, productDataManager).then(buildOperationResults);
    const deleteArticle = (comId) => executeDeleteOperation(comId, articleQuery, scheduler, productDataManager).then(buildOperationResults);
    const cloneArticle = (params) => executeCloneArticleOperation(params, articleQuery, scheduler, productDataManager).then(buildOperationResults);
    const restoreArticle = (article) => executeRestoreOperation(article, articleQuery, productDataManager).then(buildOperationResults);
    const buildOperationResults = (results) => createPDMOperationResults(articleQuery, productDataManager, sourceId, results);
    const executeArticlesOperation = (operation) => operation().then(operationResults => createPDMOperationResults(articleQuery, productDataManager, sourceId, operationResults));
    const getGfxRepresentation = (comId, options) => productDataManager.getGfxRepresentation(comId, options);
    return {
        is,
        addArticle,
        configureArticles,
        deleteArticle,
        cloneArticle,
        restoreArticle,
        getGfxRepresentation,
        executeArticlesOperation,
        ...sessionOperator,
    };
};
const createSessionOperator = (sourceId, productDataManager, articleQuery) => {
    const save = () => productDataManager.save();
    const restore = (data) => executeRestoreSessionProviderOperation(data, productDataManager).then(results => createPDMOperationResults(articleQuery, productDataManager, sourceId, results));
    return {
        save,
        restore,
    };
};
export const createPDMOperationResults = (articleQuery, productDataManager, sourceId, results) => Promise.all(results.map(result => createOperationResult(articleQuery, productDataManager, sourceId, result))).then(results => results.filter(result => result !== false));
const createOperationResult = async (articleQuery, productDataManager, sourceId, operationResult) => {
    if (operationResult.type === "delete") {
        return {
            comId: operationResult.comId,
            type: "delete",
        };
    }
    if (operationResult.type === "configure") {
        return createConfigureOperationResult(articleQuery, productDataManager, operationResult);
    }
    return createCreateOperationResult(articleQuery, productDataManager, sourceId, operationResult);
};
const createCreateOperationResult = async (articleQuery, productDataManager, sourceId, result) => {
    const [configuration, articleId, dataCategories, properties, articleType, sourceData, info, children, sourcePlacement,] = await Promise.all([
        productDataManager.getArticleConfiguration(result.comId),
        productDataManager.getArticleID(result.comId),
        result.categories !== undefined
            ? Promise.resolve(result.categories)
            : productDataManager.getArticleCategories(result.comId),
        productDataManager.getArticlePropertyList(result.comId),
        result.articleType !== undefined
            ? Promise.resolve(result.articleType)
            : productDataManager.getArticleType(result.comId),
        productDataManager.getArticleCustomData === undefined
            ? Promise.resolve(undefined)
            : productDataManager.getArticleCustomData(result.comId),
        fetchArticleInfo(productDataManager, result.comId, undefined),
        result.children !== undefined
            ? Promise.resolve(result.children)
            : productDataManager.getSubArticleIDs(result.comId),
        productDataManager.getArticlePlacement(result.comId),
    ]);
    return {
        type: "create",
        articleType,
        comId: result.comId,
        source: sourceId,
        categories: {
            ...createCategories(),
            ...dataCategories,
        },
        properties,
        sourceData: sourceData || {},
        articleNumber: result.articleNumber !== undefined
            ? result.articleNumber
            : {
                baseArticleNumber: articleId,
            },
        placement: result.placement,
        sourcePlacement: result.placement === undefined ? sourcePlacement : undefined,
        parent: result.parent,
        children,
        info,
        configuration,
        articleId,
        data: result.data,
        gfxId: result.gfxId,
    };
};
const createConfigureOperationResult = async (articleQuery, productDataManager, operation) => {
    const article = articleQuery.getArticleByComId(operation.comId);
    const configuration = await productDataManager.getArticleConfiguration(operation.comId);
    const changes = Object.getOwnPropertyNames(configuration).filter(prop => article.configuration[prop] !== configuration[prop]);
    if (changes.length === 0) {
        return false;
    }
    const [articleData, info] = await Promise.all([
        fetchArticleData(productDataManager, operation.comId),
        fetchArticleInfo(productDataManager, operation.comId, article.info),
    ]);
    return {
        type: "change",
        comId: operation.comId,
        configuration,
        categories: {
            ...createCategories(),
            ...articleData.categories,
        },
        sourceData: articleData.sourceData,
        properties: articleData.properties,
        info,
        articleId: articleData.articleId,
        children: articleData.subArticles,
    };
};
