"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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importStar(require("react"));
var ui_i18n_1 = __importDefault(require("ui-i18n"));
var classnames_1 = __importDefault(require("classnames"));
var ramda_1 = require("ramda");
var Button_1 = __importDefault(require("@mui/material/Button"));
var Typography_1 = __importDefault(require("@mui/material/Typography"));
var mdm_sdk_1 = require("@reltio/mdm-sdk");
var ConnectionRelationTypeSelector_1 = require("../ConnectionRelationTypeSelector");
var ErrorWrapper_1 = require("../ErrorWrapper");
var EntitySelector_1 = require("../EntitySelector");
var EditModeAttributesList_1 = require("../EditModeAttributesList");
var withContext_1 = require("../HOCs/withContext");
var ConfigPermissionsContext_1 = require("../contexts/ConfigPermissionsContext");
var ScrollToElementContext_1 = require("../contexts/ScrollToElementContext");
var MdmModuleContext_1 = require("../contexts/MdmModuleContext");
var HiddenAttributesContext_1 = require("../contexts/HiddenAttributesContext");
var AutoCompleteContext_1 = require("../contexts/AutoCompleteContext");
var useScrollToAttributeError_1 = require("../hooks/useScrollToAttributeError");
var styles_1 = require("./styles");
var areRelatedEntitiesChanged = function (initial, actual) {
    return initial.length !== actual.length || initial.some(function (_, i) { return initial[i] !== actual[i]; });
};
var emptyHiddenAttributes = {};
var RelationEditor = function (_a) {
    var _b;
    var _c, _d;
    var connection = _a.connection, config = _a.config, mode = _a.mode, metadata = _a.metadata, highlightedError = _a.highlightedError;
    var styles = (0, styles_1.useStyles)();
    var _e = connection.relation, relationType = _e.relationType, direction = _e.direction;
    var isNew = connection.isNew;
    var entityUri = (0, mdm_sdk_1.getEntityUriFromConnection)(connection);
    var relationUri = (0, mdm_sdk_1.getRelationUriFromConnection)(connection);
    var isTempEntity = (0, mdm_sdk_1.isTempUri)(entityUri);
    var mdmSetInitialInfo = (0, MdmModuleContext_1.useMdmAction)('setInitialInfo');
    var setRelationType = (0, MdmModuleContext_1.useMdmAction)('setRelationType');
    var closeRelationEditor = (0, MdmModuleContext_1.useMdmAction)('closeRelationEditor');
    var entityCreated = (0, MdmModuleContext_1.useMdmAction)('entityCreated');
    var entityDeleted = (0, MdmModuleContext_1.useMdmAction)('entityDeleted');
    var setRelationEntity = (0, MdmModuleContext_1.useMdmAction)('setRelationEntity');
    var errorDeactivated = (0, MdmModuleContext_1.useMdmAction)('errorDeactivated');
    var errorsSet = (0, MdmModuleContext_1.useMdmAction)('errorsSet');
    var addAttributes = (0, MdmModuleContext_1.useMdmAction)('addAttributes');
    var modifyAttribute = (0, MdmModuleContext_1.useMdmAction)('modifyAttribute');
    var removeAttribute = (0, MdmModuleContext_1.useMdmAction)('removeAttribute');
    var addRelation = (0, MdmModuleContext_1.useMdmAction)('addRelation');
    var editRelation = (0, MdmModuleContext_1.useMdmAction)('editRelation');
    var mainEntity = (0, MdmModuleContext_1.useMdmEntity)();
    var initialConnection = (0, MdmModuleContext_1.useMdmInitialConnection)(config.id, relationUri);
    var initialModifiedEntity = (0, MdmModuleContext_1.useMdmInitialConnectionTempEntity)(config.id, relationUri);
    var mdmModifiedEntity = (0, MdmModuleContext_1.useMdmModifiedEntity)(entityUri);
    var mdmAllModifiedEntities = (0, MdmModuleContext_1.useMdmModifiedEntities)();
    var globalSearchRequestOptions = (0, MdmModuleContext_1.useMdmGlobalSearchRequestOptions)(['ovOnly']);
    var profileErrors = (0, MdmModuleContext_1.useMdmProfileErrors)();
    var authoringItems = (0, MdmModuleContext_1.useMdmAuthoringItemsByEntityType)(mainEntity === null || mainEntity === void 0 ? void 0 : mainEntity.type);
    var mainEntityUri = (0, MdmModuleContext_1.useMdmEntityUri)();
    var showMasking = (0, MdmModuleContext_1.useMdmShowMasking)();
    var error = (0, mdm_sdk_1.getRelationEditorActiveError)(connection, profileErrors);
    var allRelationEditorErrors = (0, mdm_sdk_1.getAllRelationEditorActiveErrors)(connection, profileErrors);
    var modifiedEntity = isTempEntity ? mdmModifiedEntity : null;
    var allModifiedEntities = isTempEntity ? mdmAllModifiedEntities : null;
    var excludeUris = (0, react_1.useMemo)(function () { return config.excludeUris || []; }, [config.excludeUris]);
    var _f = (0, useScrollToAttributeError_1.useScrollToAttributeError)({ highlightedError: highlightedError, isSimple: true }), ref = _f.ref, errorClassName = _f.errorClassName;
    var _g = (0, react_1.useMemo)(function () {
        return (0, mdm_sdk_1.getInOutRelations)({
            content: connection.parentEntityUri
                ? config.contentSecondLevel
                : config.content,
            direction: direction,
            relationType: relationType,
            mode: mode,
            metadata: metadata
        });
    }, [config, direction, relationType, mode, metadata, connection.parentEntityUri]), _h = _g.inRelations, inRelationTypes = _h === void 0 ? [] : _h, _j = _g.outRelations, outRelationTypes = _j === void 0 ? [] : _j;
    var firstLevelRelationAttrTypes = (0, react_1.useMemo)(function () { return (0, mdm_sdk_1.getRelationAttributesList)(metadata, relationType).filter(function (_a) {
        var uri = _a.uri;
        return !excludeUris.includes(uri);
    }); }, [relationType, metadata, excludeUris]);
    var attributeListEntity = (0, react_1.useMemo)(function () { return (__assign({ attributes: __assign({}, (0, mdm_sdk_1.getRelationAttributesFromConnection)(connection)) }, (0, mdm_sdk_1.getActivenessAttributes)(connection.relation))); }, [connection]);
    var relatedTempEntities = (0, react_1.useMemo)(function () { return (0, mdm_sdk_1.findRelatedTemporaryEntities)(allModifiedEntities, modifiedEntity); }, [allModifiedEntities, modifiedEntity]);
    var relatedTempEntitiesUrisHistory = (0, react_1.useRef)([]);
    var setInitialInfo = (0, react_1.useCallback)(function (entity) {
        mdmSetInitialInfo(config.id, relationUri, entity);
    }, [mdmSetInitialInfo]);
    (0, react_1.useEffect)(function () {
        if (modifiedEntity && !initialModifiedEntity) {
            setInitialInfo(modifiedEntity);
        }
    }, []);
    (0, react_1.useEffect)(function () {
        relatedTempEntitiesUrisHistory.current = (0, ramda_1.pipe)((0, ramda_1.concat)(relatedTempEntities.map((0, ramda_1.prop)('uri'))), ramda_1.uniq)(relatedTempEntitiesUrisHistory.current);
    }, [relatedTempEntities]);
    var initialRelatedTempEntities = (0, react_1.useRef)(relatedTempEntities);
    var defaultRelationType = (0, mdm_sdk_1.getDefaultRelationTypeObject)(inRelationTypes, outRelationTypes);
    var initialConnectionChangeablePart = (0, ramda_1.pick)(['entity', 'relation'], initialConnection || {});
    var connectionChangeablePart = (0, ramda_1.pick)(['entity', 'relation'], connection);
    var hasChanges = !(0, mdm_sdk_1.isEmptyValue)((0, ramda_1.path)(['entity'], connection)) &&
        (!(0, ramda_1.equals)(initialConnectionChangeablePart, connectionChangeablePart) ||
            !(0, ramda_1.equals)(initialModifiedEntity, modifiedEntity) ||
            areRelatedEntitiesChanged(initialRelatedTempEntities.current, relatedTempEntities));
    var applyAction = (0, react_1.useMemo)(function () { return (0, ramda_1.curry)(isNew ? addRelation : editRelation); }, [isNew, addRelation, editRelation]);
    var canCreateNewEntity = !(0, mdm_sdk_1.isSuggestMode)(mode) || !(0, mdm_sdk_1.isTempUri)(mainEntity === null || mainEntity === void 0 ? void 0 : mainEntity.uri) || !(0, mdm_sdk_1.isEmptyValue)(authoringItems);
    var handleClose = (0, react_1.useCallback)(function () { return closeRelationEditor(config.id, relationUri); }, [config, relationUri, closeRelationEditor]);
    var updateModifiedEntityLabel = (0, react_1.useCallback)(function (connection) {
        if (modifiedEntity) {
            var entityType = (0, mdm_sdk_1.getEntityType)(metadata, modifiedEntity.type);
            return (0, mdm_sdk_1.updateConnectionEntityLabel)(entityType, modifiedEntity, connection);
        }
        return connection;
    }, [modifiedEntity, metadata]);
    var setModifiedEntity = (0, react_1.useCallback)(function (entity) { return entityCreated(entity); }, [entityCreated]);
    var deleteModifiedEntity = (0, react_1.useCallback)(function (entityUri) { return entityDeleted(entityUri); }, [entityDeleted]);
    var onRelationTypeChange = (0, react_1.useCallback)(function (newRelationType) {
        var connectionEntity = connection.entity;
        var hasConnectionEntity = connectionEntity && connectionEntity.entityUri;
        var isEntitySuitableForNewRelationType = mainEntity &&
            newRelationType &&
            hasConnectionEntity &&
            (0, mdm_sdk_1.isAvailableRelationBetweenEntities)(newRelationType.direction === mdm_sdk_1.Directions.OUT, __assign(__assign({}, connectionEntity), { type: connectionEntity.entityType }), mainEntity, metadata, newRelationType.type);
        setRelationType(config.id, relationUri, newRelationType);
        if (hasConnectionEntity && !isEntitySuitableForNewRelationType) {
            if (modifiedEntity) {
                deleteModifiedEntity(modifiedEntity.uri);
            }
            setRelationEntity(config.id, relationUri, {});
        }
    }, [
        metadata,
        connection.entity,
        mainEntity,
        setRelationType,
        config.id,
        relationUri,
        modifiedEntity,
        setRelationEntity,
        deleteModifiedEntity
    ]);
    var onChangeEntity = (0, react_1.useCallback)(function (entity) {
        if (modifiedEntity) {
            deleteModifiedEntity(modifiedEntity.uri);
        }
        setRelationEntity(config.id, relationUri, entity);
        if (error) {
            errorDeactivated((0, mdm_sdk_1.getErrorId)(error));
        }
    }, [config.id, relationUri, setRelationEntity, errorDeactivated, modifiedEntity, deleteModifiedEntity, error]);
    var validate = (0, react_1.useCallback)(function () {
        var errors = (0, mdm_sdk_1.validateConnection)(metadata, allModifiedEntities, connection).map(function (error) { return (__assign(__assign({}, error), { path: (0, ramda_1.pipe)(mdm_sdk_1.evaluateErrorPath, (0, ramda_1.map)((0, ramda_1.when)((0, ramda_1.propEq)('type', mdm_sdk_1.AttributeValuePathItemType.relationConnection), (0, ramda_1.assoc)('viewId', config.id))))({
                entityUri: mainEntityUri,
                metadata: metadata,
                connections: [connection],
                entitiesMap: allModifiedEntities || {}
            }, error.uri || error.parentUri) })); });
        errorsSet(errors);
        return errors.length === 0;
    }, [connection, metadata, allModifiedEntities, errorsSet, mainEntityUri, config]);
    var onApply = (0, react_1.useCallback)((0, ramda_1.pipe)((0, ramda_1.always)(connection), (0, ramda_1.when)(validate, (0, ramda_1.pipe)(mdm_sdk_1.omitMarks, updateModifiedEntityLabel, applyAction(config.id), (0, ramda_1.always)((0, ramda_1.differenceWith)(ramda_1.equals, relatedTempEntitiesUrisHistory.current, relatedTempEntities.map((0, ramda_1.prop)('uri')))), (0, ramda_1.forEach)(deleteModifiedEntity), handleClose))), [connection, config, updateModifiedEntityLabel, validate, relatedTempEntities]);
    var onCancel = (0, react_1.useCallback)(function () {
        if (modifiedEntity !== initialModifiedEntity) {
            if (initialModifiedEntity) {
                setModifiedEntity(initialModifiedEntity);
                if (modifiedEntity && modifiedEntity.uri !== initialModifiedEntity.uri) {
                    deleteModifiedEntity(modifiedEntity.uri);
                }
            }
            else {
                deleteModifiedEntity(modifiedEntity.uri);
            }
        }
        var initialTempEntities = initialRelatedTempEntities.current;
        var entitiesUrisToDelete = (0, ramda_1.differenceWith)(ramda_1.equals, relatedTempEntitiesUrisHistory.current, initialTempEntities.map((0, ramda_1.prop)('uri')));
        entitiesUrisToDelete.forEach(deleteModifiedEntity);
        initialTempEntities.forEach(setModifiedEntity);
        var filteredErrors = profileErrors.filter(function (profileError) { return !allRelationEditorErrors.some(function (error) { return (0, mdm_sdk_1.getErrorId)(error) === (0, mdm_sdk_1.getErrorId)(profileError); }); });
        errorsSet(filteredErrors);
        handleClose();
    }, [
        handleClose,
        setModifiedEntity,
        deleteModifiedEntity,
        modifiedEntity,
        initialModifiedEntity,
        allRelationEditorErrors,
        errorsSet,
        profileErrors
    ]);
    var onAddAttributes = (0, react_1.useCallback)(function (params) { return addAttributes(params.map(function (param) { return (__assign(__assign({}, param), { viewId: config.id })); })); }, [config.id, addAttributes]);
    var onChangeAttribute = (0, react_1.useCallback)(function (params) { return modifyAttribute(__assign(__assign({}, params), { viewId: config.id })); }, [config.id, modifyAttribute]);
    var onDeleteAttribute = (0, react_1.useCallback)(function (params) { return removeAttribute(__assign(__assign({}, params), { viewId: config.id })); }, [config.id, removeAttribute]);
    var onCreateEntity = (0, react_1.useCallback)(function (entityTypeUri, initValue) {
        var entityType = (0, mdm_sdk_1.getEntityType)(metadata, entityTypeUri);
        var newEntityAttrTypes = (0, ramda_1.pipe)(mdm_sdk_1.relationEditorAttributeTypesSelectionStrategy, (0, mdm_sdk_1.getCreatableAttributeTypes)(mode))(entityType);
        var newEntity = (0, mdm_sdk_1.createTemporaryEntity)({
            entityTypeUri: entityTypeUri,
            initValue: initValue,
            attributeTypes: newEntityAttrTypes,
            metadata: metadata,
            mode: mode
        });
        onChangeEntity(newEntity);
        setModifiedEntity(newEntity);
    }, [setModifiedEntity, onChangeEntity, mode, metadata]);
    var errorMessage = (0, mdm_sdk_1.getErrorMessage)(error);
    var entityTypesUris = (0, react_1.useMemo)(function () {
        var _a;
        var _b = config, content = _b.content, contentSecondLevel = _b.contentSecondLevel;
        var entityTypeUrisFromConfig = (_a = (contentSecondLevel && connection.parentEntityUri ? contentSecondLevel.entityTypes : content.entityTypes)) !== null && _a !== void 0 ? _a : [];
        var relationTypeObj = relationType ? (0, mdm_sdk_1.getRelationType)(metadata, relationType) : null;
        var suitableEntityTypeUrisForRelationType = relationTypeObj
            ? (0, mdm_sdk_1.getSuitableEntityTypeUrisForRelationTypes)(direction === mdm_sdk_1.Directions.OUT, metadata, [relationTypeObj])
            : [];
        return entityTypeUrisFromConfig.length > 0
            ? entityTypeUrisFromConfig.filter(function (uri) { return suitableEntityTypeUrisForRelationType.includes(uri); })
            : suitableEntityTypeUrisForRelationType;
    }, [config, connection.parentEntityUri, relationType, direction, metadata]);
    var isEntityHasMaskedAttrValue = (0, ramda_1.pipe)(ramda_1.values, ramda_1.flatten, (0, ramda_1.any)(mdm_sdk_1.isAttributeHasMaskedValue))(((_d = (_c = connection.entity) === null || _c === void 0 ? void 0 : _c.object) === null || _d === void 0 ? void 0 : _d.attributes) || {});
    var isMasked = showMasking && isEntityHasMaskedAttrValue;
    return (react_1.default.createElement(react_1.default.Fragment, null,
        react_1.default.createElement("div", { className: styles.editor },
            react_1.default.createElement(Typography_1.default, { className: styles.title }, isNew ? ui_i18n_1.default.text('Add new item') : ui_i18n_1.default.text('Edit item')),
            defaultRelationType === null && (react_1.default.createElement(ConnectionRelationTypeSelector_1.ConnectionRelationTypeSelector, { className: styles.item, relation: connection.relation, inRelationTypes: inRelationTypes, outRelationTypes: outRelationTypes, onChange: onRelationTypeChange })),
            Boolean(relationType) && (react_1.default.createElement(ConfigPermissionsContext_1.ConfigPermissionsContextProvider, null,
                react_1.default.createElement("div", { ref: ref, className: errorClassName },
                    react_1.default.createElement(ErrorWrapper_1.ErrorWrapper, { errorMessage: errorMessage },
                        react_1.default.createElement(AutoCompleteContext_1.AddressAutoCompleteProvider, { entityUri: entityUri },
                            react_1.default.createElement(EntitySelector_1.EntitySelector, { className: (0, classnames_1.default)(styles.item, (_b = {},
                                    _b[styles.dense] = errorMessage ||
                                        (connection.entity && (0, mdm_sdk_1.isTempUri)(connection.entity.entityUri)),
                                    _b)), entity: connection.entity || {}, entityTypesUris: entityTypesUris, globalSearchRequestOptions: globalSearchRequestOptions, mode: mode, onChange: onChangeEntity, onCreate: canCreateNewEntity ? onCreateEntity : undefined, metadata: metadata, attributeTypesSelectionStrategy: mdm_sdk_1.relationEditorAttributeTypesSelectionStrategy, isMasked: isMasked })))),
                react_1.default.createElement(HiddenAttributesContext_1.HiddenAttributesContext.Provider, { value: emptyHiddenAttributes },
                    react_1.default.createElement(EditModeAttributesList_1.EditModeAttributesList, { className: styles.item, attrTypes: firstLevelRelationAttrTypes, entity: attributeListEntity, showEmptyEditors: true, mode: mode, parentUri: relationUri, onAddAttributes: onAddAttributes, onChangeAttribute: onChangeAttribute, onDeleteAttribute: onDeleteAttribute }))))),
        react_1.default.createElement("div", { className: styles.actionButtons },
            react_1.default.createElement(Button_1.default, { onClick: onCancel }, ui_i18n_1.default.text('Cancel')),
            react_1.default.createElement(Button_1.default, { color: "primary", disabled: !hasChanges, onClick: onApply }, ui_i18n_1.default.text('Apply')))));
};
exports.default = (0, withContext_1.withContext)(ScrollToElementContext_1.ScrollToElementContext, function (contextValue, _a) {
    var connection = _a.connection;
    var _b = contextValue || {}, _c = _b.element, element = _c === void 0 ? {} : _c, type = _b.type;
    var _d = connection.relation, relationUri = _d.relationUri, relationType = _d.relationType;
    var isHighlighted = (0, ScrollToElementContext_1.isHighlightedErrorType)(type) && (0, mdm_sdk_1.isAttributeTypeError)(element, relationUri, relationType);
    return { highlightedError: isHighlighted ? contextValue : null };
}, RelationEditor);
