import { ContentType } from '../../../models/enums';
import { decoupleReference, generateUniqueId, getBlockModelById, getClosestContentElementInDocument, getSelectedRange, sanitizeBlock, sanitizeContent, setCursorPosition } from '../../../common/utils/index';
import * as constants from '../../../common/constant';
import { BlockFactory } from '../../../block-manager/services/block-factory';
import { events } from '../../../common/constant';
var InlineContentInsertionModule = /** @class */ (function () {
    function InlineContentInsertionModule(manager) {
        this.parent = manager;
        this.addEventListeners();
    }
    InlineContentInsertionModule.prototype.addEventListeners = function () {
        this.parent.observer.on('inlineContentInsertion', this.handleInlineContentInsertion, this);
        this.parent.observer.on(events.destroy, this.destroy, this);
    };
    InlineContentInsertionModule.prototype.removeEventListeners = function () {
        this.parent.observer.off('inlineContentInsertion', this.handleInlineContentInsertion);
        this.parent.observer.off(events.destroy, this.destroy);
    };
    InlineContentInsertionModule.prototype.handleInlineContentInsertion = function (args) {
        this.parent.mentionAction.cleanMentionArtifacts(this.parent.currentFocusedBlock);
        var contentType = (args.value.toString().indexOf('e-user-mention-item-template')) > 0 ? ContentType.Mention : ContentType.Label;
        var mentionChar = contentType === ContentType.Mention ? '@' : this.parent.labelSettings.triggerChar;
        this.parent.mentionAction.removeMentionQueryKeysFromModel(mentionChar);
        var options = {
            block: getBlockModelById(this.parent.currentFocusedBlock.id, this.parent.getEditorBlocks()),
            blockElement: this.parent.currentFocusedBlock,
            range: getSelectedRange().cloneRange(),
            contentType: contentType,
            itemData: args.itemData
        };
        this.processInsertion(options);
    };
    InlineContentInsertionModule.prototype.processInsertion = function (options) {
        var range = options.range, contentType = options.contentType, blockElement = options.blockElement;
        if (!range || !blockElement) {
            return;
        }
        var rangeParent = this.getRangeParent(range);
        var insertedNode = this.findInsertedNode(contentType, rangeParent);
        this.splitAndReorganizeContent(insertedNode, contentType, rangeParent, options);
    };
    InlineContentInsertionModule.prototype.getRangeParent = function (range) {
        return range.startContainer.nodeType === Node.TEXT_NODE
            ? range.startContainer.parentElement
            : range.startContainer;
    };
    InlineContentInsertionModule.prototype.findInsertedNode = function (contentType, rangeParent) {
        var _a;
        var contentClassMap = (_a = {},
            _a[ContentType.Mention] = 'e-mention-chip',
            _a[ContentType.Label] = 'e-mention-chip',
            _a);
        return rangeParent.querySelector("." + contentClassMap["" + contentType]);
    };
    InlineContentInsertionModule.prototype.splitAndReorganizeContent = function (insertedNode, contentType, rangeParent, options) {
        var _a;
        var block = options.block;
        var blockContentElement = rangeParent.closest('.' + constants.CONTENT_CLS);
        if (!blockContentElement) {
            return null;
        }
        var nodesToProcess = Array.from(rangeParent.childNodes);
        var insertionIndex = nodesToProcess.indexOf(insertedNode);
        if (insertionIndex === -1) {
            return null;
        }
        var affectingContent = block.content.find(function (content) { return content.id === getClosestContentElementInDocument(rangeParent).id; });
        if (!affectingContent) {
            return null;
        }
        var oldBlock = decoupleReference(sanitizeBlock(block));
        var beforeContents = this.processContents(nodesToProcess.slice(0, insertionIndex), affectingContent);
        var insertedContent = this.createInlineContentModel(insertedNode, contentType, options);
        var afterContents = this.processContents(nodesToProcess.slice(insertionIndex + 1), affectingContent, true);
        var affectingIndex = block.content.indexOf(affectingContent);
        var newContentModels = beforeContents.concat([insertedContent], afterContents);
        (_a = block.content).splice.apply(_a, [affectingIndex, 1].concat(newContentModels));
        // If inserted at the end, add new empty content for cursor focus
        if (block.content.findIndex(function (c) { return c.id === insertedContent.id; }) === block.content.length - 1) {
            block.content.push(BlockFactory.createTextContent());
        }
        this.parent.blockService.updateContent(block.id, block.content);
        this.parent.stateManager.updateManagerBlocks();
        this.parent.observer.notify('modelChanged', { type: 'ReRenderBlockContent', state: {
                data: [{ block: block, oldBlock: oldBlock }]
            } });
        this.parent.undoRedoAction.trackContentChangedForUndoRedo(oldBlock, decoupleReference(sanitizeBlock(block)));
        var nextSibling = blockContentElement.querySelector('#' + insertedContent.id).nextElementSibling;
        if (nextSibling) {
            setCursorPosition(nextSibling, 0);
        }
    };
    InlineContentInsertionModule.prototype.processContents = function (nodes, baseContentModel, generateNewIds) {
        if (generateNewIds === void 0) { generateNewIds = false; }
        var contentModels = [];
        nodes.forEach(function (node) {
            if (node.nodeType === Node.TEXT_NODE && node.textContent !== '') {
                var newContent = decoupleReference(sanitizeContent(baseContentModel));
                newContent.id = generateNewIds ? generateUniqueId(constants.CONTENT_ID_PREFIX) : newContent.id;
                newContent.content = node.textContent;
                contentModels.push(newContent);
            }
        });
        return contentModels;
    };
    InlineContentInsertionModule.prototype.createInlineContentModel = function (element, contentType, options) {
        var user = options.itemData;
        var labelItem = options.itemData;
        var contentValue = contentType === ContentType.Mention ? user.user : element.innerText;
        var newContent;
        if (contentType === ContentType.Mention) {
            newContent = BlockFactory.createMentionContent({ content: contentValue }, { userId: user.id });
        }
        else if (contentType === ContentType.Label) {
            newContent = BlockFactory.createLabelContent({ content: contentValue }, { labelId: labelItem.id });
        }
        return newContent;
    };
    /**
     * Destroys the inline content module.
     *
     * @returns {void}
     */
    InlineContentInsertionModule.prototype.destroy = function () {
        this.removeEventListeners();
    };
    return InlineContentInsertionModule;
}());
export { InlineContentInsertionModule };
