"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);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildDCRSavePlan = exports.isCreateEntityOperation = exports.getEntityUriForChangeRequest = exports.concatEntityRelationsObjects = exports.createEntityRelationsObjectByRelation = exports.createEntityRelationsObjectByEntity = exports.extractObjectsFromChangeRequest = exports.getRelationsObjects = exports.getEntitiesObjects = void 0;
var mdm_sdk_1 = require("@reltio/mdm-sdk");
var ramda_1 = require("ramda");
exports.getEntitiesObjects = (0, ramda_1.filter)((0, ramda_1.pipe)((0, ramda_1.prop)('uri'), mdm_sdk_1.isEntityUri));
exports.getRelationsObjects = (0, ramda_1.filter)((0, ramda_1.pipe)((0, ramda_1.prop)('uri'), mdm_sdk_1.isRelationUri));
var getRelations = function (objectsWithChanges, entityUri) {
    return (0, ramda_1.filter)((0, ramda_1.allPass)([(0, ramda_1.pipe)((0, ramda_1.prop)('uri'), mdm_sdk_1.isRelationUri), (0, ramda_1.pipe)((0, ramda_1.prop)('startObjectUri'), (0, ramda_1.equals)(entityUri))]))(objectsWithChanges);
};
var extractObjectsFromChangeRequest = function (changes, objectsInfo) {
    var getChange = function (key) { return (0, ramda_1.prop)([key], changes); };
    return (0, ramda_1.pipe)(ramda_1.keys, (0, ramda_1.filter)(getChange), (0, ramda_1.map)(function (key) { return (__assign(__assign({}, objectsInfo[key]), { uri: key })); }))(objectsInfo);
};
exports.extractObjectsFromChangeRequest = extractObjectsFromChangeRequest;
exports.createEntityRelationsObjectByEntity = (0, ramda_1.curry)(function (objectsWithChanges, entity) {
    return {
        entity: entity,
        relations: getRelations(objectsWithChanges, entity.uri)
    };
});
exports.createEntityRelationsObjectByRelation = (0, ramda_1.curry)(function (objectsInfo, relation) {
    var entity = objectsInfo[relation.startObjectUri];
    var relations = [relation];
    return entity ? { entity: __assign(__assign({}, entity), { uri: relation.startObjectUri }), relations: relations } : { relations: relations };
});
var concatEntityRelationsObjects = function (acc, object) {
    var entity = object.entity, relations = object.relations;
    var entityUri = entity.uri;
    var mergedRelations = (0, ramda_1.pipe)((0, ramda_1.pathOr)([], [entityUri, 'relations']), (0, ramda_1.concat)(relations), ramda_1.uniq)(acc);
    acc[entityUri] = {
        entity: entity,
        relations: mergedRelations
    };
    return acc;
};
exports.concatEntityRelationsObjects = concatEntityRelationsObjects;
var getEntityUriForChangeRequest = function (dcrUri, entityUri) {
    return "".concat(dcrUri, "/changes/").concat(entityUri);
};
exports.getEntityUriForChangeRequest = getEntityUriForChangeRequest;
var isCreateEntityOperation = function (dcr) {
    return dcr.type === mdm_sdk_1.DCRTypes.CREATE_ENTITY;
};
exports.isCreateEntityOperation = isCreateEntityOperation;
var cleanValueRecursively = function (value) {
    if (typeof value === 'string' || (0, ramda_1.isEmpty)(value)) {
        return value;
    }
    var cleanedProperties = (0, ramda_1.map)(function (propertyValues) {
        return propertyValues
            .map(function (item) {
            var itemValue = item.value;
            var cleanedItemValue = itemValue && typeof itemValue === 'object' ? cleanValueRecursively(itemValue) : itemValue;
            return __assign(__assign({}, item), { value: cleanedItemValue });
        })
            .filter(function (item) {
            var itemValue = item.value;
            return !(0, ramda_1.isEmpty)(itemValue) && !(0, ramda_1.isNil)(itemValue);
        });
    }, value);
    return (0, ramda_1.filter)(function (propertyValues) { return !(0, ramda_1.isEmpty)(propertyValues); }, cleanedProperties);
};
var cleanChange = function (change) {
    var _a, _b;
    if (Array.isArray(change.newValue)) {
        return change;
    }
    if (typeof change.newValue === 'object' && (0, ramda_1.hasPath)(['newValue', 'value'], change)) {
        var cleanedValue = cleanValueRecursively((_a = change.newValue) === null || _a === void 0 ? void 0 : _a.value);
        return (0, ramda_1.assocPath)(['newValue', 'value'], cleanedValue, change);
    }
    if (typeof change.newValue === 'object' && (0, ramda_1.hasPath)(['newValue', 'attributes'], change)) {
        var cleanedAttributes = cleanValueRecursively((_b = change.newValue) === null || _b === void 0 ? void 0 : _b.attributes);
        var changeWithCleanedAttributes = (0, ramda_1.assocPath)(['newValue', 'attributes'], cleanedAttributes, change);
        if ((0, mdm_sdk_1.isRelationTypeUri)(change.objectType) && change.type === mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP) {
            var cleanByPath = function (valuePath) {
                return (0, ramda_1.when)((0, ramda_1.allPass)([(0, ramda_1.hasPath)(valuePath), (0, ramda_1.pipe)((0, ramda_1.path)(valuePath), ramda_1.isNil)]), (0, ramda_1.dissocPath)(valuePath));
            };
            return (0, ramda_1.pipe)(cleanByPath(['newValue', 'startDate']), cleanByPath(['newValue', 'endDate']))(changeWithCleanedAttributes);
        }
        return changeWithCleanedAttributes;
    }
    return change;
};
var calculateValuePath = function (key, change) {
    var path = key
        .split('/')
        .slice(2)
        .map(function (part) { return (isNaN(Number(part)) ? part : parseInt(part)); });
    switch (change.type) {
        case mdm_sdk_1.DCRTypes.UPDATE_TAGS:
        case mdm_sdk_1.DCRTypes.UPDATE_ROLES:
            return path;
        case mdm_sdk_1.DCRTypes.UPDATE_START_DATE:
        case mdm_sdk_1.DCRTypes.UPDATE_END_DATE:
            return __spreadArray(__spreadArray([], path, true), [0], false);
        case mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP:
            if (path.length === 2) {
                if (path[1] === 'activeness.startDate') {
                    return [path[0], 'startDate'];
                }
                if (path[1] === 'activeness.endDate') {
                    return [path[0], 'endDate'];
                }
            }
            return __spreadArray(__spreadArray([], path, true), ['value'], false);
        default:
            return __spreadArray(__spreadArray([], path, true), ['value'], false);
    }
};
var valuesAreEqual = function (oldValue, newValue) {
    var sortWithLocale = function (array) { return array.slice().sort(function (a, b) { return a.localeCompare(b); }); };
    if (Array.isArray(oldValue) && Array.isArray(newValue)) {
        return oldValue.length === newValue.length && (0, ramda_1.equals)(sortWithLocale(oldValue), sortWithLocale(newValue));
    }
    if (typeof oldValue === 'string' && typeof newValue === 'number') {
        return oldValue === newValue.toString();
    }
    return oldValue === newValue;
};
var getOldValueByNewValuePath = function (valuePath, change) {
    if (valuePath.includes('newValue')) {
        return (0, ramda_1.pathOr)(null, valuePath.map(function (item) { return (item === 'newValue' ? 'oldValue' : item); }), change);
    }
    return null;
};
var buildDCRSavePlan = function (changes, getLinesByChangeId, metadata) {
    var _a, _b;
    var rejectedChangeIds = [];
    var updatedChanges = {};
    var deleteAttributes = {};
    for (var _i = 0, _c = Object.entries(changes); _i < _c.length; _i++) {
        var _d = _c[_i], objectUri = _d[0], objectChanges = _d[1];
        var rawChanges = new Map();
        var _loop_1 = function (change) {
            var _h = (0, ramda_1.pipe)((0, ramda_1.prop)('id'), getLinesByChangeId, (0, ramda_1.partition)(function (_a) {
                var _b;
                var key = _a[0], lineData = _a[1];
                return key.split('/').length === 3 &&
                    (lineData.isRejected ||
                        ((0, ramda_1.isEmpty)((_b = lineData.value) === null || _b === void 0 ? void 0 : _b.value) && change.type !== mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE));
            }))(change), rejectedRootLines = _h[0], otherLines = _h[1];
            rejectedChangeIds.push.apply(rejectedChangeIds, rejectedRootLines.map(function (_a) {
                var key = _a[0];
                return key.split('/')[1];
            }));
            var rejectedRootLinesMap = new Map(rejectedRootLines);
            for (var _j = 0, otherLines_1 = otherLines; _j < otherLines_1.length; _j++) {
                var _k = otherLines_1[_j], key = _k[0], lineData = _k[1];
                var rootId = key.split('/').slice(0, 3).join('/');
                var newValue = (_a = lineData.value) === null || _a === void 0 ? void 0 : _a.value;
                if (rootId === key && change.type === mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE && (0, ramda_1.isEmpty)(newValue)) {
                    var attributeUri = [objectUri, 'attributes', change.attributePath].join('/');
                    var entry = __assign(__assign({}, (0, mdm_sdk_1.createEntryDeleteAttribute)({ uri: attributeUri })[0]), (change.crosswalk && { crosswalk: change.crosswalk }));
                    deleteAttributes[objectUri] = (0, ramda_1.uniqBy)((0, ramda_1.prop)('uri'), (0, ramda_1.append)(entry, (0, ramda_1.propOr)([], objectUri, deleteAttributes)));
                    rejectedChangeIds.push(change.id);
                }
                else if (!rejectedRootLinesMap.has(rootId)) {
                    var valuePath = calculateValuePath(key, change);
                    var oldDCRValue = (0, ramda_1.path)(valuePath, change);
                    var oldValue = getOldValueByNewValuePath(valuePath, change);
                    var initialChange = rawChanges.has(change.id) ? rawChanges.get(change.id) : change;
                    var updatedChange = void 0;
                    if (lineData.isRejected || (0, ramda_1.isEmpty)(newValue)) {
                        updatedChange = (0, ramda_1.assocPath)(valuePath, null, initialChange);
                    }
                    else if (!valuesAreEqual(oldDCRValue, newValue)) {
                        if (oldValue && valuesAreEqual(oldValue, newValue)) {
                            rejectedChangeIds.push(change.id);
                        }
                        else {
                            var processedNewValue = typeof oldDCRValue === 'string' && typeof newValue === 'number'
                                ? newValue.toString()
                                : newValue;
                            updatedChange = (0, ramda_1.assocPath)(valuePath, processedNewValue, initialChange);
                        }
                    }
                    if (updatedChange) {
                        rawChanges.set(change.id, updatedChange);
                    }
                }
            }
        };
        for (var _e = 0, objectChanges_1 = objectChanges; _e < objectChanges_1.length; _e++) {
            var change = objectChanges_1[_e];
            _loop_1(change);
        }
        for (var _f = 0, _g = Array.from(rawChanges.values()); _f < _g.length; _f++) {
            var rawChange = _g[_f];
            var cleanedChange = cleanChange(rawChange);
            var isNestedChange = (0, ramda_1.has)('attributeType', cleanedChange) &&
                (0, mdm_sdk_1.isNested)((0, mdm_sdk_1.findAttributeTypeByUri)(metadata, cleanedChange.attributeType));
            if (isNestedChange && (0, ramda_1.isEmpty)((_b = cleanedChange.newValue) === null || _b === void 0 ? void 0 : _b.value)) {
                rejectedChangeIds.push(cleanedChange.id);
            }
            else {
                updatedChanges[objectUri] = (0, ramda_1.append)(cleanedChange, (0, ramda_1.propOr)([], objectUri, updatedChanges));
            }
        }
    }
    var rejectedBeforeUpdateIds = (0, ramda_1.pipe)(ramda_1.values, ramda_1.flatten, (0, ramda_1.pluck)('id'))(updatedChanges);
    rejectedChangeIds.push.apply(rejectedChangeIds, rejectedBeforeUpdateIds);
    var deleteAttributesGroups = (0, ramda_1.groupBy)(function (_a) {
        var uri = _a[0];
        return ((0, mdm_sdk_1.isRelationUri)(uri) ? 'relation' : 'entity');
    }, (0, ramda_1.toPairs)(deleteAttributes));
    var deleteRelationAttributes = (0, ramda_1.fromPairs)(deleteAttributesGroups.relation || []);
    var deleteEntityAttributes = (0, ramda_1.fromPairs)(deleteAttributesGroups.entity || []);
    return {
        rejectedChangeIds: rejectedChangeIds,
        updatedChanges: updatedChanges,
        deleteEntityAttributes: deleteEntityAttributes,
        deleteRelationAttributes: deleteRelationAttributes
    };
};
exports.buildDCRSavePlan = buildDCRSavePlan;
