import { __assign, __awaiter, __generator, __rest, __values } from "tslib";
var callbackCaller = function (cb) { return cb(); };
export var createOperationResultHandler = function (articleRegistry, articleQuery, notificationCenter, hooks) {
    var batchUpdates = articleRegistry.executeBatch === undefined
        ? callbackCaller
        : articleRegistry.executeBatch;
    var processOperationResults = function (results) { return __awaiter(void 0, void 0, void 0, function () {
        var processResults, processResults_1, processResults_1_1, entry, entry_1, entry_1_1, notification;
        var e_1, _a, e_2, _b;
        return __generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    if (results.length === 0) {
                        return [2 /*return*/];
                    }
                    return [4 /*yield*/, hooks.beforeOperationResultProcessing.emit(results)];
                case 1:
                    _c.sent();
                    processResults = [];
                    batchUpdates(function () {
                        var e_3, _a;
                        try {
                            for (var results_1 = __values(results), results_1_1 = results_1.next(); !results_1_1.done; results_1_1 = results_1.next()) {
                                var result = results_1_1.value;
                                var processor = resultProcessor[result.type];
                                var processedResult = processor(result, articleRegistry, articleQuery, hooks);
                                processResults.push(processedResult);
                            }
                        }
                        catch (e_3_1) { e_3 = { error: e_3_1 }; }
                        finally {
                            try {
                                if (results_1_1 && !results_1_1.done && (_a = results_1.return)) _a.call(results_1);
                            }
                            finally { if (e_3) throw e_3.error; }
                        }
                    });
                    return [4 /*yield*/, hooks.afterOperationResultProcessing.emit(results)];
                case 2:
                    _c.sent();
                    try {
                        for (processResults_1 = __values(processResults), processResults_1_1 = processResults_1.next(); !processResults_1_1.done; processResults_1_1 = processResults_1.next()) {
                            entry = processResults_1_1.value;
                            if (entry === undefined) {
                                continue;
                            }
                            if (Array.isArray(entry)) {
                                try {
                                    for (entry_1 = (e_2 = void 0, __values(entry)), entry_1_1 = entry_1.next(); !entry_1_1.done; entry_1_1 = entry_1.next()) {
                                        notification = entry_1_1.value;
                                        notificationCenter.send("OperationResultHandler", notification.name, notification.payload);
                                    }
                                }
                                catch (e_2_1) { e_2 = { error: e_2_1 }; }
                                finally {
                                    try {
                                        if (entry_1_1 && !entry_1_1.done && (_b = entry_1.return)) _b.call(entry_1);
                                    }
                                    finally { if (e_2) throw e_2.error; }
                                }
                            }
                            else {
                                notificationCenter.send("OperationResultHandler", entry.name, entry.payload);
                            }
                        }
                    }
                    catch (e_1_1) { e_1 = { error: e_1_1 }; }
                    finally {
                        try {
                            if (processResults_1_1 && !processResults_1_1.done && (_a = processResults_1.return)) _a.call(processResults_1);
                        }
                        finally { if (e_1) throw e_1.error; }
                    }
                    return [2 /*return*/];
            }
        });
    }); };
    return {
        processOperationResults: processOperationResults,
    };
};
var processCreateResult = function (_a, articleRegistry, articleQuery, hooks) {
    var articleType = _a.articleType, data = _a.data, type = _a.type, result = __rest(_a, ["articleType", "data", "type"]);
    var registerData = __assign(__assign({}, result), { data: data || {}, type: articleType });
    hooks.beforeArticleRegistration.emit(registerData);
    articleRegistry.registerArticle(registerData);
    var article = articleQuery.getArticleByComId(result.comId);
    hooks.afterArticleRegistration.emit(article);
    return {
        name: "ItemCreated",
        payload: article,
    };
};
var processChangeResult = function (_a, articleRegistry, articleQuery, hooks) {
    var type = _a.type, comId = _a.comId, updateData = __rest(_a, ["type", "comId"]);
    var oldArticle = articleQuery.getArticleByComId(comId);
    hooks.beforeArticleUpdate.emit(oldArticle, updateData);
    articleRegistry.updateArticle(comId, updateData);
    var newArticle = articleQuery.getArticleByComId(comId);
    hooks.beforeArticleUpdate.emit(newArticle, updateData);
    return [
        {
            name: "ItemConfigured",
            payload: newArticle,
        },
        {
            name: "ItemChanged",
            payload: {
                previousArticle: oldArticle,
                article: newArticle,
            },
        },
    ];
};
var processDeleteResult = function (result, articleRegistry, articleQuery, hooks) {
    var currentArticle = articleQuery.getArticleByComId(result.comId);
    hooks.beforeArticleUnregistration.emit(currentArticle);
    articleRegistry.unregisterArticle(result.comId);
    hooks.beforeArticleRegistration.emit(currentArticle);
    return {
        name: "ItemRemoved",
        payload: currentArticle,
    };
};
var resultProcessor = {
    create: processCreateResult,
    change: processChangeResult,
    delete: processDeleteResult,
};
