"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.mergeExistingRolesAndTags = 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");
var AddedAttributesContext_1 = require("../contexts/AddedAttributesContext");
var common_1 = require("./common");
var isAddedChange = function (changeId) { return changeId === null || changeId === void 0 ? void 0 : changeId.startsWith(AddedAttributesContext_1.ADDED_CHANGE_ID_PREFIX); };
var normalizeReferenceValueForApi = function (val, change, metadata) {
    var attrType = (0, mdm_sdk_1.findAttributeTypeByUri)(metadata, change.attributeType);
    return __assign(__assign(__assign({}, val), { refEntity: {
            objectURI: val.refEntity.objectURI,
            type: (0, mdm_sdk_1.getReferencedEntityTypeUriFromAttrType)(attrType)
        } }), (change.crosswalk && {
        refRelation: {
            type: change.crosswalk.type
        }
    }));
};
var dcrChangeToInsertDiffEntry = function (change, objectUri, metadata) {
    var _a, _b;
    switch (change.type) {
        case mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE: {
            var newVal = change.newValue;
            var normalized = newVal.refEntity !== undefined ? normalizeReferenceValueForApi(newVal, change, metadata) : newVal;
            var attributePath = change.attributePath;
            if (change.refObjectURI && change.refAttributeType) {
                var refAttrName = change.refAttributeType.split('/attributes/')[1];
                var refInstanceId = change.refObjectURI.split('/')[1];
                attributePath = "".concat(refAttrName, "/").concat(refInstanceId, "/").concat(attributePath);
            }
            return {
                type: mdm_sdk_1.EventType.INSERT_ATTRIBUTE,
                uri: "".concat(objectUri, "/attributes/").concat(attributePath),
                newValue: [normalized]
            };
        }
        case mdm_sdk_1.DCRTypes.UPDATE_TAGS:
            return { type: mdm_sdk_1.EventType.UPDATE_TAGS, newValue: change.newValue };
        case mdm_sdk_1.DCRTypes.UPDATE_ROLES:
            return { type: mdm_sdk_1.EventType.UPDATE_ROLES, newValue: change.newValue };
        case mdm_sdk_1.DCRTypes.UPDATE_START_DATE:
            return { type: mdm_sdk_1.EventType.UPDATE_START_DATE, newValue: { value: (_a = change.newValue) === null || _a === void 0 ? void 0 : _a[0] } };
        case mdm_sdk_1.DCRTypes.UPDATE_END_DATE:
            return { type: mdm_sdk_1.EventType.UPDATE_END_DATE, newValue: { value: (_b = change.newValue) === null || _b === void 0 ? void 0 : _b[0] } };
        default:
            return null;
    }
};
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 _a, _b;
    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: (_b = (_a = acc[entityUri]) === null || _a === void 0 ? void 0 : _a.entity) !== null && _b !== void 0 ? _b : 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 ((0, ramda_1.isNil)(value) || (0, common_1.isPrimitiveValue)(value) || (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)) || 'lookupCode' in item;
        });
    }, 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:
        case mdm_sdk_1.DCRTypes.CREATE_ENTITY:
            if (path.length === 2) {
                switch (path[1]) {
                    case 'roles':
                    case 'tags':
                        return path;
                    case 'activeness.startDate':
                        return [path[0], 'startDate'];
                    case '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) {
    if (typeof oldValue === 'object' &&
        typeof newValue === 'object' &&
        !Array.isArray(oldValue) &&
        !Array.isArray(newValue)) {
        return (0, ramda_1.equals)(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, _c;
    var rejectedChangeIds = [];
    var updatedChanges = {};
    var deleteAttributes = {};
    var insertAttributes = {};
    for (var _i = 0, _d = Object.entries(changes); _i < _d.length; _i++) {
        var _e = _d[_i], objectUri = _e[0], objectChanges = _e[1];
        var rawChanges = new Map();
        var _loop_1 = function (change) {
            var _j = (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, mdm_sdk_1.isEmptyValue)((_b = lineData.value) === null || _b === void 0 ? void 0 : _b.value) && change.type !== mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE));
            }))(change), rejectedRootLines = _j[0], otherLines = _j[1];
            var isNew = isAddedChange(change.id);
            if (!isNew) {
                rejectedChangeIds.push.apply(rejectedChangeIds, rejectedRootLines.map(function (_a) {
                    var key = _a[0];
                    return key.split('/')[1];
                }));
            }
            var newValueObj = change.newValue;
            var hasNonEmptyNewValue = Array.isArray(change.newValue) ||
                !(0, mdm_sdk_1.isEmptyValue)(newValueObj === null || newValueObj === void 0 ? void 0 : newValueObj.value) ||
                'lookupCode' in (newValueObj !== null && newValueObj !== void 0 ? newValueObj : {}) ||
                !(0, mdm_sdk_1.isEmptyValue)((_a = newValueObj === null || newValueObj === void 0 ? void 0 : newValueObj.refEntity) === null || _a === void 0 ? void 0 : _a.objectURI);
            if (isNew && otherLines.length === 0 && rejectedRootLines.length === 0 && hasNonEmptyNewValue) {
                rawChanges.set(change.id, change);
            }
            var rejectedRootLinesMap = new Map(rejectedRootLines);
            for (var _k = 0, otherLines_1 = otherLines; _k < otherLines_1.length; _k++) {
                var _l = otherLines_1[_k], key = _l[0], lineData = _l[1];
                var rootId = key.split('/').slice(0, 3).join('/');
                var newValue = (_b = lineData.value) === null || _b === void 0 ? void 0 : _b.value;
                if (!isNew && rootId === key && change.type === mdm_sdk_1.DCRTypes.UPDATE_ATTRIBUTE && (0, mdm_sdk_1.isEmptyValue)(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, mdm_sdk_1.isEmptyValue)(newValue)) {
                        updatedChange = (0, ramda_1.assocPath)(valuePath, null, initialChange);
                    }
                    else if (!valuesAreEqual(oldDCRValue, newValue)) {
                        if (oldValue && valuesAreEqual(oldValue, newValue)) {
                            if (!isNew) {
                                rejectedChangeIds.push(change.id);
                            }
                        }
                        else {
                            var processedNewValue = typeof oldDCRValue === 'string' && typeof newValue === 'number'
                                ? newValue.toString()
                                : newValue;
                            updatedChange = (0, ramda_1.assocPath)(valuePath, processedNewValue, initialChange);
                            var lineValue = lineData.value;
                            if (lineValue && typeof lineValue === 'object' && 'lookupCode' in lineValue) {
                                var parentPath = valuePath.slice(0, -1);
                                updatedChange = (0, ramda_1.assocPath)(__spreadArray(__spreadArray([], parentPath, true), ['lookupCode'], false), lineValue.lookupCode, updatedChange);
                                updatedChange = (0, ramda_1.dissocPath)(__spreadArray(__spreadArray([], parentPath, true), ['lookupRawValue'], false), updatedChange);
                            }
                        }
                    }
                    if (updatedChange) {
                        rawChanges.set(change.id, updatedChange);
                    }
                }
            }
        };
        for (var _f = 0, objectChanges_1 = objectChanges; _f < objectChanges_1.length; _f++) {
            var change = objectChanges_1[_f];
            _loop_1(change);
        }
        for (var _g = 0, _h = Array.from(rawChanges.values()); _g < _h.length; _g++) {
            var rawChange = _h[_g];
            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)((_c = cleanedChange.newValue) === null || _c === void 0 ? void 0 : _c.value)) {
                if (!isAddedChange(cleanedChange.id)) {
                    rejectedChangeIds.push(cleanedChange.id);
                }
            }
            else if (isAddedChange(cleanedChange.id)) {
                var diffEntry = dcrChangeToInsertDiffEntry(cleanedChange, objectUri, metadata);
                if (diffEntry) {
                    insertAttributes[objectUri] = (0, ramda_1.append)(diffEntry, (0, ramda_1.propOr)([], objectUri, insertAttributes));
                }
            }
            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 || []);
    var insertAttributesGroups = (0, ramda_1.groupBy)(function (_a) {
        var uri = _a[0];
        return ((0, mdm_sdk_1.isRelationUri)(uri) ? 'relation' : 'entity');
    }, (0, ramda_1.toPairs)(insertAttributes));
    var insertRelationAttributes = (0, ramda_1.fromPairs)(insertAttributesGroups.relation || []);
    var insertEntityAttributes = (0, ramda_1.fromPairs)(insertAttributesGroups.entity || []);
    return {
        rejectedChangeIds: rejectedChangeIds,
        updatedChanges: updatedChanges,
        deleteEntityAttributes: deleteEntityAttributes,
        deleteRelationAttributes: deleteRelationAttributes,
        insertEntityAttributes: insertEntityAttributes,
        insertRelationAttributes: insertRelationAttributes
    };
};
exports.buildDCRSavePlan = buildDCRSavePlan;
var mergeExistingRolesAndTags = function (diff, entity) {
    return diff.map(function (entry) {
        var _a, _b;
        if (entry.type === mdm_sdk_1.EventType.UPDATE_TAGS && ((_a = entity.tags) === null || _a === void 0 ? void 0 : _a.length)) {
            return __assign(__assign({}, entry), { newValue: (0, ramda_1.uniq)(__spreadArray(__spreadArray([], entity.tags, true), entry.newValue, true)) });
        }
        if (entry.type === mdm_sdk_1.EventType.UPDATE_ROLES && ((_b = entity.roles) === null || _b === void 0 ? void 0 : _b.length)) {
            return __assign(__assign({}, entry), { newValue: (0, ramda_1.uniq)(__spreadArray(__spreadArray([], entity.roles, true), entry.newValue, true)) });
        }
        return entry;
    });
};
exports.mergeExistingRolesAndTags = mergeExistingRolesAndTags;
