"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.linkTooltipPlugin = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const uikit_1 = require("@gravity-ui/uikit");
const prosemirror_keymap_1 = require("prosemirror-keymap");
const prosemirror_state_1 = require("prosemirror-state");
// @ts-ignore // TODO: fix cjs build
const prosemirror_utils_1 = require("prosemirror-utils");
const prosemirror_view_1 = require("prosemirror-view");
const ErrorBoundary_1 = require("../../../../../react-utils/ErrorBoundary.js");
const marks_1 = require("../../../../../utils/marks.js");
const ReactRenderer_1 = require("../../../../behavior/ReactRenderer/index.js");
const index_1 = require("../../../index.js");
const TooltipView_1 = require("./TooltipView.js");
const className = 'pm-link-focus-deco';
const placement = ['bottom-start', 'bottom-end', 'top-start', 'top-end'];
function getTextNode(state) {
    if (!(state.selection instanceof prosemirror_state_1.TextSelection) ||
        !state.selection.empty ||
        !(0, marks_1.isMarkActive)(state, (0, index_1.linkType)(state.schema)))
        return null;
    const parent = (0, prosemirror_utils_1.findParentNode)(Boolean)(state.selection);
    if (!parent) {
        return null;
    }
    const textNodes = (0, prosemirror_utils_1.findChildrenByMark)(parent?.node, (0, index_1.linkType)(state.schema));
    const textNode = textNodes.find((n) => {
        const start = n.pos + parent.pos;
        const end = start + n.node.nodeSize;
        return start <= state.selection.from && end >= state.selection.from;
    });
    if (!textNode)
        return null;
    const absolutePos = textNode.pos + parent.pos + 1;
    return {
        ...textNode,
        absolutePos,
        parent,
        from: absolutePos,
        to: absolutePos + textNode.node.nodeSize,
    };
}
const linkTooltipPlugin = (deps) => {
    let viewTooltip = null;
    return new prosemirror_state_1.Plugin({
        view(view) {
            viewTooltip = new SelectionTooltip(view, deps);
            return viewTooltip;
        },
        props: {
            handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
                Escape: () => viewTooltip?.onEscapeDown() ?? false,
            }),
            decorations(state) {
                const textNode = getTextNode(state);
                if (!textNode)
                    return prosemirror_view_1.DecorationSet.empty;
                const { from, to } = textNode;
                return prosemirror_view_1.DecorationSet.create(state.doc, [
                    prosemirror_view_1.Decoration.inline(from, to, {
                        class: `pm-node-selected ${className}`,
                    }),
                ]);
            },
        },
    });
};
exports.linkTooltipPlugin = linkTooltipPlugin;
class SelectionTooltip {
    normalizeUrl;
    view;
    textNode;
    textNodeRef;
    isTooltipOpen = false;
    manualHidden = false;
    renderItem;
    selectionTooltipProps = { show: false };
    constructor(view, deps) {
        this.normalizeUrl = (0, index_1.normalizeUrlFactory)(deps);
        this.view = view;
        this.update(view, null);
    }
    update(view, prevState) {
        if (!view.dom.parentNode) {
            this.hideTooltip();
            return;
        }
        const { state } = view;
        if (prevState && prevState.doc.eq(state.doc) && prevState.selection.eq(state.selection))
            return;
        const prevTextNode = this.textNode;
        this.textNode = getTextNode(view.state);
        const prevRef = this.textNodeRef;
        this.updateTextNodeRef();
        if (!this.textNode || !this.textNodeRef) {
            this.removePlaceholderLink(prevTextNode);
            this.hideTooltip();
            return;
        }
        if (prevRef !== this.textNodeRef) {
            this.manualHidden = false;
        }
        if (this.manualHidden) {
            this.hideTooltip();
        }
        else {
            this.renderTooltip({
                show: true,
                domElem: this.textNodeRef,
                onCancel: () => this.cancelPopup(),
                attrs: this.getMarkAttrs(),
                onChange: this.changeAttrs.bind(this),
                onOpenChange: this.onOpenChange,
            });
        }
    }
    destroy() {
        this.isTooltipOpen = false;
        this.selectionTooltipProps = { show: false };
        this.renderItem?.remove();
        this.renderItem = undefined;
    }
    onEscapeDown() {
        if (this.isTooltipOpen) {
            this.removePlaceholderLink(this.textNode);
            this.manualHidden = true;
            this.hideTooltip();
            return true;
        }
        return false;
    }
    updateTextNodeRef() {
        const decoElem = this.view.dom.getElementsByClassName(className)[0];
        this.textNodeRef = decoElem;
    }
    getMarkAttrs() {
        const { textNode } = this;
        const linkMark = textNode && (0, marks_1.findMark)(textNode.node, (0, index_1.linkType)(this.view.state.schema));
        return linkMark?.attrs;
    }
    hideTooltip() {
        this.renderTooltip({ show: false });
    }
    renderTooltip(props) {
        this.isTooltipOpen = props.show;
        this.selectionTooltipProps = props;
        this.renderItem = this.renderItem ?? this.createRenderItem();
        this.renderItem.rerender();
    }
    onOpenChange = (open, _e, reason) => {
        if (open)
            return;
        if (reason === 'escape-key') {
            this.cancelPopup();
        }
        else {
            this.onOutisdeClick();
        }
    };
    onOutisdeClick = () => {
        // after all updates of the editor state
        setTimeout(() => {
            if (!this.view.hasFocus()) {
                this.removePlaceholderLink(this.textNode);
                this.hideTooltip();
                this.manualHidden = false;
            }
        });
    };
    cancelPopup() {
        this.removePlaceholderLink(this.textNode, { returnSelection: true });
        this.manualHidden = true;
        this.hideTooltip();
        this.view.focus();
    }
    removePlaceholderLink(textNode, opts) {
        if (textNode) {
            const { view } = this;
            const { state } = view;
            const attrs = (0, marks_1.findMark)(textNode.node, (0, index_1.linkType)(state.schema))?.attrs;
            if (attrs?.[index_1.LinkAttr.IsPlaceholder]) {
                const { from, to } = textNode;
                let tr = state.tr.removeMark(from, to, (0, index_1.linkType)(state.schema));
                if (opts?.returnSelection) {
                    tr = tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, from, to));
                }
                view.dispatch(tr);
            }
        }
    }
    changeAttrs({ href }) {
        const { view, textNode } = this;
        if (!textNode)
            return;
        const normalizeResult = this.normalizeUrl(href);
        if (normalizeResult) {
            const { url } = normalizeResult;
            const { from, to } = textNode;
            view.dispatch(view.state.tr.addMark(from, to, (0, index_1.linkType)(view.state.schema).create({ href: url })));
            setTimeout(this.cancelPopup.bind(this));
        }
    }
    createRenderItem() {
        return (0, ReactRenderer_1.getReactRendererFromState)(this.view.state).createItem('link-tooltip', () => ((0, jsx_runtime_1.jsx)(ErrorBoundary_1.ErrorLoggerBoundary, { children: (0, jsx_runtime_1.jsx)(SelectionTooltipView, { ...this.selectionTooltipProps }) })));
    }
}
const SelectionTooltipView = (props) => {
    const { show } = props;
    if (!show)
        return null;
    const { domElem, onChange, onCancel, onOpenChange, attrs = {} } = props;
    const href = attrs[index_1.LinkAttr.Href];
    const autoFocus = attrs[index_1.LinkAttr.IsPlaceholder];
    return ((0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: true, anchorElement: domElem, placement: placement, onOpenChange: onOpenChange, children: (0, jsx_runtime_1.jsx)(TooltipView_1.LinkForm, { href: href ?? '', autoFocus: autoFocus, onChange: onChange, onCancel: onCancel }) }, href));
};
//# sourceMappingURL=index.js.map
