"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.mergeAddedAttributesWithDCRChanges = void 0;
var ramda_1 = require("ramda");
var mdm_sdk_1 = require("@reltio/mdm-sdk");
var helpers_1 = require("./helpers");
var findNodeByLineId = function (changes, objectUri, lineId) {
    var _a;
    var changeList = changes[objectUri];
    if (!Array.isArray(changeList))
        return null;
    var lineIdParts = lineId.split('/');
    if (lineIdParts.length < 3)
        return null;
    var changeId = lineIdParts[1];
    var change = changeList.find(function (c) { return c.id === changeId; });
    if (!(change === null || change === void 0 ? void 0 : change.newValue))
        return null;
    return (_a = (0, ramda_1.path)(lineIdParts.slice(2), change)) !== null && _a !== void 0 ? _a : null;
};
var addChildToNode = function (parentNode, attrName, addedId, attributeType, initialValue) {
    var containerKey = 'attributes' in parentNode && typeof parentNode.attributes === 'object' ? 'attributes' : 'value';
    if (!parentNode[containerKey] ||
        typeof parentNode[containerKey] !== 'object' ||
        Array.isArray(parentNode[containerKey])) {
        parentNode[containerKey] = {};
    }
    var container = parentNode[containerKey];
    if (!Array.isArray(container[attrName])) {
        container[attrName] = [];
    }
    var isComplex = attributeType && ((0, mdm_sdk_1.isComplexAttribute)(attributeType) || (0, mdm_sdk_1.isImage)(attributeType));
    var value = isComplex ? {} : initialValue === null || initialValue === void 0 ? void 0 : initialValue.value;
    var childNode = __assign(__assign({ value: value }, ((initialValue === null || initialValue === void 0 ? void 0 : initialValue.lookupCode) && { lookupCode: initialValue.lookupCode })), (addedId && { addedId: addedId }));
    container[attrName].push(childNode);
    return childNode;
};
var createNewValue = function (attributeType, enrich, id, refEntityUri, initialValue) {
    var isComplex = (0, mdm_sdk_1.isComplexAttribute)(attributeType) || (0, mdm_sdk_1.isImage)(attributeType);
    var value = isComplex ? {} : initialValue === null || initialValue === void 0 ? void 0 : initialValue.value;
    var base = __assign(__assign({ value: value }, ((initialValue === null || initialValue === void 0 ? void 0 : initialValue.lookupCode) && { lookupCode: initialValue.lookupCode })), (enrich && id && { addedId: id }));
    if ((0, mdm_sdk_1.isReference)(attributeType)) {
        base.refEntity = { objectURI: refEntityUri || '' };
    }
    return base;
};
var createFakeInsertAttributeChange = function (id, attributeType, newValue, changeOverrides) {
    return __assign({ id: id, type: mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE, attributePath: attributeType.name, attributeType: attributeType.uri, newValue: newValue }, changeOverrides);
};
var createFakeRolesOrTagsChange = function (id, attributeType, enrich) { return ({
    id: id,
    type: (0, mdm_sdk_1.isTagAttrType)(attributeType) ? mdm_sdk_1.DCRTypes.UPDATE_TAGS : mdm_sdk_1.DCRTypes.UPDATE_ROLES,
    newValue: (enrich ? { value: [], addedId: id } : [])
}); };
var createFakeActivenessDateChange = function (id, attributeType, enrich) { return ({
    id: id,
    type: attributeType.uri === mdm_sdk_1.EntityAttrTypes.startDate.uri ? mdm_sdk_1.DCRTypes.UPDATE_START_DATE : mdm_sdk_1.DCRTypes.UPDATE_END_DATE,
    objectType: (0, mdm_sdk_1.getBaseUri)(attributeType.uri),
    newValue: (enrich ? { value: undefined, addedId: id } : [])
}); };
var createEmptyChangeValue = function (enrich, id) {
    return (enrich ? { value: undefined, addedId: id } : []);
};
var upsertSpecialAttributeChange = function (_a) {
    var changesList = _a.changesList, changeType = _a.changeType, change = _a.change, enrich = _a.enrich, id = _a.id;
    var existingChange = changesList.find(function (c) { return c.type === changeType; });
    if (existingChange && !existingChange.newValue) {
        existingChange.newValue = createEmptyChangeValue(enrich, id);
    }
    else if (!existingChange) {
        changesList.push(change);
    }
};
var resolveObjectUri = function (objectUriOrId, changes) {
    if (!objectUriOrId)
        return undefined;
    if (changes[objectUriOrId])
        return objectUriOrId;
    return Object.keys(changes).find(function (uri) { return uri.endsWith("/".concat(objectUriOrId)); }) || objectUriOrId;
};
var getObjectUriFromLineId = function (lineId, changes) {
    var objectId = lineId.split('/')[0];
    return resolveObjectUri(objectId, changes);
};
var mergeAddedAttributesWithDCRChanges = function (changes, addedAttributes, enrich) {
    var _a, _b, _c, _d;
    if (enrich === void 0) { enrich = true; }
    var merged = (0, ramda_1.clone)(changes);
    if (addedAttributes.length === 0) {
        return enrich ? (0, helpers_1.addLineIdToValue)(merged) : merged;
    }
    var nodeById = new Map();
    for (var _i = 0, addedAttributes_1 = addedAttributes; _i < addedAttributes_1.length; _i++) {
        var addedAttribute = addedAttributes_1[_i];
        var id = addedAttribute.id, objectUriFromAddedAttribute = addedAttribute.objectUri, parentLineId = addedAttribute.parentLineId, parentId = addedAttribute.parentId, changeOverrides = addedAttribute.changeOverrides, attributeType = addedAttribute.attributeType;
        var objectUri = resolveObjectUri(objectUriFromAddedAttribute, merged) ||
            (parentLineId ? getObjectUriFromLineId(parentLineId, merged) : undefined);
        var attrName = (_a = attributeType === null || attributeType === void 0 ? void 0 : attributeType.name) !== null && _a !== void 0 ? _a : '';
        if (parentId && !objectUri) {
            var parentNode = (_b = nodeById.get(parentId)) !== null && _b !== void 0 ? _b : null;
            if (!parentNode)
                continue;
            var childNode = addChildToNode(parentNode, attrName, enrich ? id : undefined, attributeType, addedAttribute.initialValue);
            nodeById.set(id, childNode);
            continue;
        }
        if (!objectUri)
            continue;
        if (!merged[objectUri]) {
            merged[objectUri] = [];
        }
        var createChange = !parentLineId && !parentId
            ? merged[objectUri].find(function (c) { return c.type === mdm_sdk_1.DCRTypes.CREATE_ENTITY || c.type === mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP; })
            : undefined;
        if ((createChange === null || createChange === void 0 ? void 0 : createChange.newValue) && ((0, mdm_sdk_1.isRoleAttrType)(attributeType) || (0, mdm_sdk_1.isTagAttrType)(attributeType))) {
            var parentNode = createChange.newValue;
            parentNode[attrName] = enrich ? { value: [], addedId: id } : [];
        }
        else if ((createChange === null || createChange === void 0 ? void 0 : createChange.newValue) && (0, mdm_sdk_1.isActivenessAttrType)(attributeType)) {
            var parentNode = createChange.newValue;
            parentNode[attributeType.uri] = enrich ? { addedId: id } : null;
        }
        else if (createChange === null || createChange === void 0 ? void 0 : createChange.newValue) {
            var parentNode = createChange.newValue;
            var childNode = addChildToNode(parentNode, attrName, enrich ? id : undefined, attributeType, addedAttribute.initialValue);
            nodeById.set(id, childNode);
        }
        else if ((0, mdm_sdk_1.isActivenessAttrType)(attributeType)) {
            var createRelOrEntityChange = merged[objectUri].find(function (c) { return c.type === mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP || c.type === mdm_sdk_1.DCRTypes.CREATE_ENTITY; });
            if (createRelOrEntityChange === null || createRelOrEntityChange === void 0 ? void 0 : createRelOrEntityChange.newValue) {
                var parentNode = createRelOrEntityChange.newValue;
                parentNode[attributeType.uri] = enrich ? { addedId: id } : null;
            }
            else {
                var changeType = attributeType.uri === mdm_sdk_1.EntityAttrTypes.startDate.uri
                    ? mdm_sdk_1.DCRTypes.UPDATE_START_DATE
                    : mdm_sdk_1.DCRTypes.UPDATE_END_DATE;
                upsertSpecialAttributeChange({
                    changesList: merged[objectUri],
                    changeType: changeType,
                    change: createFakeActivenessDateChange(id, attributeType, enrich),
                    enrich: enrich,
                    id: id
                });
            }
        }
        else if ((0, mdm_sdk_1.isTagAttrType)(attributeType) || (0, mdm_sdk_1.isRoleAttrType)(attributeType)) {
            var changeType = (0, mdm_sdk_1.isTagAttrType)(attributeType) ? mdm_sdk_1.DCRTypes.UPDATE_TAGS : mdm_sdk_1.DCRTypes.UPDATE_ROLES;
            upsertSpecialAttributeChange({
                changesList: merged[objectUri],
                changeType: changeType,
                change: createFakeRolesOrTagsChange(id, attributeType, enrich),
                enrich: enrich,
                id: id
            });
        }
        else if (!parentLineId && !parentId) {
            var newValue = createNewValue(attributeType, enrich, id, (_c = addedAttribute.refEntity) === null || _c === void 0 ? void 0 : _c.entityUri, addedAttribute.initialValue);
            nodeById.set(id, newValue);
            var newChange = createFakeInsertAttributeChange(id, attributeType, newValue, changeOverrides);
            merged[objectUri].push(newChange);
        }
        else {
            var parentNode = null;
            if (parentLineId) {
                parentNode = findNodeByLineId(merged, objectUri, parentLineId);
            }
            else if (parentId) {
                parentNode = (_d = nodeById.get(parentId)) !== null && _d !== void 0 ? _d : null;
            }
            if (!parentNode)
                continue;
            var childNode = addChildToNode(parentNode, attrName, enrich ? id : undefined, attributeType, addedAttribute.initialValue);
            nodeById.set(id, childNode);
        }
    }
    return enrich ? (0, helpers_1.addLineIdToValue)(merged) : merged;
};
exports.mergeAddedAttributesWithDCRChanges = mergeAddedAttributesWithDCRChanges;
