"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeChanges = exports.extractAddedId = exports.extractLineIds = void 0;
var ramda_1 = require("ramda");
var mdm_sdk_1 = require("@reltio/mdm-sdk");
var attributes_1 = require("./attributes");
var ATTRIBUTE_DELIMITER = '/';
var SPECIAL_ATTRIBUTES_NAMES = [
    'defaultProfilePicValue',
    mdm_sdk_1.EntityAttrTypes.tags.name,
    mdm_sdk_1.EntityAttrTypes.roles.name,
    mdm_sdk_1.EntityAttrTypes.startDate.name,
    mdm_sdk_1.EntityAttrTypes.endDate.name
];
var extractLineIds = function (value) {
    return typeof value === 'object' && 'lineIds' in value ? value.lineIds : undefined;
};
exports.extractLineIds = extractLineIds;
var extractAddedId = function (value) {
    return typeof value === 'object' && value !== null && 'addedId' in value ? value.addedId : undefined;
};
exports.extractAddedId = extractAddedId;
var prepareStartOrEndDate = function (_a) {
    var newValue = _a.newValue, oldValue = _a.oldValue;
    var actualNewValue = newValue && 'value' in newValue ? newValue.value : newValue;
    var actualOldValue = oldValue && 'value' in oldValue ? oldValue.value : oldValue;
    var parseValue = function (value) { return (isNaN(value) || (0, mdm_sdk_1.isEmptyValue)(value) ? value : parseInt(value)); };
    var isExistedValue = function (value) { return (value === null || value === void 0 ? void 0 : value.length) && !(0, mdm_sdk_1.isEmptyValue)(value) && !(0, mdm_sdk_1.isEmptyValue)(value[0]); };
    var isExistNewValue = isExistedValue(actualNewValue);
    var isExistOldValue = isExistedValue(actualOldValue);
    if (isExistNewValue && isExistOldValue) {
        return [
            {
                type: mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE,
                oldValue: {
                    value: parseValue(actualOldValue[0]),
                    lineIds: (0, exports.extractLineIds)(oldValue)
                },
                newValue: {
                    value: parseValue(actualNewValue[0]),
                    lineIds: (0, exports.extractLineIds)(newValue)
                }
            }
        ];
    }
    else if (isExistNewValue) {
        return [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: {
                    value: parseValue(actualNewValue[0]),
                    lineIds: (0, exports.extractLineIds)(newValue)
                }
            }
        ];
    }
    else if (isExistOldValue) {
        return [
            {
                type: mdm_sdk_1.DCRTypes.DELETE_ATTRIBUTE,
                oldValue: {
                    value: parseValue(actualOldValue[0]),
                    lineIds: (0, exports.extractLineIds)(oldValue)
                }
            }
        ];
    }
    var addedId = newValue === null || newValue === void 0 ? void 0 : newValue.addedId;
    if (addedId) {
        return [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: __assign({ value: undefined, lineIds: (0, exports.extractLineIds)(newValue) }, (addedId && { addedId: addedId }))
            }
        ];
    }
};
var prepareRolesOrTags = function (change) {
    var _a = change.newValue, newValue = _a === void 0 ? [] : _a, _b = change.oldValue, oldValue = _b === void 0 ? [] : _b;
    var preparedNewValue = 'value' in newValue ? newValue.value : newValue;
    var preparedOldValue = 'value' in oldValue ? oldValue.value : oldValue;
    var diffNewValue = (0, ramda_1.difference)(preparedNewValue, preparedOldValue);
    var diffOldValue = (0, ramda_1.difference)(preparedOldValue, preparedNewValue);
    var addedId = (0, exports.extractAddedId)(newValue);
    var items = [];
    if (diffNewValue.length) {
        items.push({
            type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
            newValue: __assign({ value: diffNewValue, lineIds: (0, exports.extractLineIds)(newValue) }, (addedId && { addedId: addedId }))
        });
    }
    if (diffOldValue.length) {
        items.push({
            type: mdm_sdk_1.DCRTypes.DELETE_ATTRIBUTE,
            oldValue: { value: diffOldValue, lineIds: (0, exports.extractLineIds)(oldValue) }
        });
    }
    if (items.length === 0 && addedId) {
        items.push({
            type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
            newValue: { value: [], lineIds: (0, exports.extractLineIds)(newValue), addedId: addedId }
        });
    }
    return items;
};
var getPath = function (change) {
    var type = change.type, attributePath = change.attributePath, refObjectURI = change.refObjectURI, refAttributeType = change.refAttributeType;
    var path = type === mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE ? (0, mdm_sdk_1.generateTempUri)(attributePath) : attributePath;
    if (refObjectURI) {
        var typePath = refAttributeType.split('/attributes/');
        var id = refObjectURI.split(ATTRIBUTE_DELIMITER)[1];
        return [typePath[1], id, path].join(ATTRIBUTE_DELIMITER);
    }
    return path;
};
var prepareAttribute = function (container, change) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    var changePath = getPath(change);
    var pathArray = changePath.split(ATTRIBUTE_DELIMITER);
    var holder = container;
    for (var i = 0; i < pathArray.length - 1; i = i + 2) {
        var key = pathArray[i];
        var id = pathArray[i + 1];
        var currentValue = i === pathArray.length - 2
            ? (holder[key] || []).find((0, ramda_1.both)((0, ramda_1.propEq)('id', id), (0, ramda_1.pathEq)(['value', 'type'], change === null || change === void 0 ? void 0 : change.type)))
            : (holder[key] || []).find((0, ramda_1.propEq)('id', id));
        if (!(0, ramda_1.isNil)(currentValue)) {
            var newLineIds = (0, exports.extractLineIds)(change.newValue);
            var oldLineIds = (0, exports.extractLineIds)(change.oldValue);
            var currentLineId = ((_b = (_a = currentValue.value) === null || _a === void 0 ? void 0 : _a.newValue) === null || _b === void 0 ? void 0 : _b.lineIds) || ((_d = (_c = currentValue.value) === null || _c === void 0 ? void 0 : _c.oldValue) === null || _d === void 0 ? void 0 : _d.lineIds);
            if (((_f = (_e = currentValue.value) === null || _e === void 0 ? void 0 : _e.newValue) === null || _f === void 0 ? void 0 : _f.lineIds) && newLineIds) {
                currentValue.value.newValue.lineIds = currentLineId.concat(newLineIds);
            }
            if (((_h = (_g = currentValue.value) === null || _g === void 0 ? void 0 : _g.oldValue) === null || _h === void 0 ? void 0 : _h.lineIds) && oldLineIds) {
                currentValue.value.oldValue.lineIds = currentLineId.concat(oldLineIds);
            }
        }
        var newValue = pathArray.length === i + 2 ? change : {};
        var value = currentValue ? currentValue : { id: id, value: newValue };
        var refObjectURI = ((_j = change.refObjectURI) === null || _j === void 0 ? void 0 : _j.indexOf(id)) >= 0 && change.refObjectURI;
        if (refObjectURI) {
            value.refObjectURI = refObjectURI;
        }
        if ((0, ramda_1.isNil)(currentValue)) {
            holder[key] = (holder[key] || []).concat(value);
        }
        holder = value.value;
    }
    return container;
};
var createEntityOrRelation = function (metadata, value) {
    var _a = value.attributes, attributes = _a === void 0 ? {} : _a, startDate = value.startDate, endDate = value.endDate, lineIds = value.lineIds;
    var _b = value, roles = _b.roles, tags = _b.tags, defaultProfilePicValue = _b.defaultProfilePicValue;
    var newObject = __assign({}, attributes);
    if (defaultProfilePicValue) {
        newObject['defaultProfilePicValue'] = [defaultProfilePicValue];
    }
    if (roles) {
        var addedId = (0, exports.extractAddedId)(roles);
        newObject[mdm_sdk_1.EntityAttrTypes.roles.name] = [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: __assign({ value: addedId ? [] : roles, lineIds: lineIds && ["".concat(lineIds[0], "/").concat(mdm_sdk_1.EntityAttrTypes.roles.name)] }, (addedId && { addedId: addedId }))
            }
        ];
    }
    if (tags) {
        var addedId = (0, exports.extractAddedId)(tags);
        newObject[mdm_sdk_1.EntityAttrTypes.tags.name] = [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: __assign({ value: addedId ? [] : tags, lineIds: lineIds && ["".concat(lineIds[0], "/").concat(mdm_sdk_1.EntityAttrTypes.tags.name)] }, (addedId && { addedId: addedId }))
            }
        ];
    }
    if (startDate !== undefined) {
        var addedId = (0, exports.extractAddedId)(startDate);
        newObject[mdm_sdk_1.EntityAttrTypes.startDate.name] = [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: __assign({ value: addedId ? undefined : startDate, lineIds: lineIds && ["".concat(lineIds[0], "/").concat(mdm_sdk_1.EntityAttrTypes.startDate.name)] }, (addedId && { addedId: addedId }))
            }
        ];
    }
    if (endDate !== undefined) {
        var addedId = (0, exports.extractAddedId)(endDate);
        newObject[mdm_sdk_1.EntityAttrTypes.endDate.name] = [
            {
                type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE,
                newValue: __assign({ value: addedId ? undefined : endDate, lineIds: lineIds && ["".concat(lineIds[0], "/").concat(mdm_sdk_1.EntityAttrTypes.endDate.name)] }, (addedId && { addedId: addedId }))
            }
        ];
    }
    newObject['lineIds'] = lineIds;
    return newObject;
};
var mergeAttributesInChange = function (metadata, objectInfo, change, container) {
    if (container === void 0) { container = {}; }
    var type = change.type;
    switch (type) {
        case mdm_sdk_1.DCRTypes.UPDATE_PROFILE_PIC_BY_URL:
            container['defaultProfilePicValue'] = [change.newValue];
            break;
        case mdm_sdk_1.DCRTypes.UPDATE_TAGS:
            container[mdm_sdk_1.EntityAttrTypes.tags.name] = prepareRolesOrTags(change);
            break;
        case mdm_sdk_1.DCRTypes.UPDATE_ROLES: {
            container[mdm_sdk_1.EntityAttrTypes.roles.name] = prepareRolesOrTags(change);
            break;
        }
        case mdm_sdk_1.DCRTypes.UPDATE_START_DATE:
            container[mdm_sdk_1.EntityAttrTypes.startDate.name] = prepareStartOrEndDate(change);
            break;
        case mdm_sdk_1.DCRTypes.UPDATE_END_DATE:
            container[mdm_sdk_1.EntityAttrTypes.endDate.name] = prepareStartOrEndDate(change);
            break;
        case mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP:
        case mdm_sdk_1.DCRTypes.CREATE_ENTITY: {
            return __assign(__assign({}, container), createEntityOrRelation(metadata, change.newValue));
        }
        case mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE:
        case mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE:
        case mdm_sdk_1.DCRTypes.DELETE_ATTRIBUTE:
        case mdm_sdk_1.DCRTypes.PIN_ATTRIBUTE:
        case mdm_sdk_1.DCRTypes.IGNORE_ATTRIBUTE:
            prepareAttribute(container, change);
            break;
        default:
            break;
    }
    return container;
};
var updateRelation = function (metadata, changes, relationInfo) {
    var relationChanges = (0, ramda_1.propOr)([], relationInfo.uri)(changes);
    return relationChanges.reduce(function (result, change) {
        return mergeAttributesInChange(metadata, relationInfo, change, result);
    }, {});
};
var mergeChanges = function (metadata, changes, entityInfo, relationsInfo) {
    var getAttributeChanges = function (attributeName) {
        return (0, ramda_1.pipe)((0, ramda_1.pick)([attributeName]), (0, attributes_1.getEntityChanges)(metadata, entityInfo));
    };
    var concatChanges = (0, ramda_1.curry)(function (getters, attributesTree) {
        return (0, ramda_1.reduce)(function (acc, getter) { return (0, ramda_1.concat)(acc, getter(attributesTree)); }, [], getters);
    });
    var entityInfoChanges = (0, ramda_1.propOr)([], entityInfo.uri)(changes);
    var changesTree = entityInfoChanges.reduce(function (result, change) {
        return mergeAttributesInChange(metadata, entityInfo, change, result);
    }, {});
    var relationsTrees = relationsInfo.map(function (relationInfo) { return updateRelation(metadata, changes, relationInfo); });
    var entityChanges = concatChanges([
        (0, ramda_1.pipe)((0, ramda_1.omit)(SPECIAL_ATTRIBUTES_NAMES), (0, attributes_1.getEntityChanges)(metadata, entityInfo)),
        getAttributeChanges(mdm_sdk_1.EntityAttrTypes.roles.name),
        getAttributeChanges(mdm_sdk_1.EntityAttrTypes.tags.name),
        getAttributeChanges(mdm_sdk_1.EntityAttrTypes.startDate.name),
        getAttributeChanges(mdm_sdk_1.EntityAttrTypes.endDate.name)
    ], changesTree);
    var relationsChanges = (0, ramda_1.flatten)(relationsInfo.map(function (relationInfo, index) {
        var changeType = (0, ramda_1.path)([relationInfo.uri, 0, 'type'], changes);
        var relationChangeLineIds = (0, ramda_1.path)([relationInfo.uri, 0, 'lineIds'], changes);
        return (0, attributes_1.getRelationChanges)(metadata, relationInfo, relationsTrees[index], changeType, relationChangeLineIds);
    }));
    return [entityChanges, relationsChanges];
};
exports.mergeChanges = mergeChanges;
