import { AutocompletePopupCloser } from "../../../../utils/autocomplete-popup.js";
import { ArrayCarousel } from "../../../../utils/carousel/index.js";
import { getReactRendererFromState } from "../../../behavior/index.js";
import { AutocompleteActionKind, closeAutocomplete, getAutocompleteState, } from "../../../behavior/Autocomplete/index.js";
import { EmojiConsts } from "../EmojiSpecs/index.js";
import { render } from "./EmojiSuggestComponent.js";
import { findDecoElem } from "./utils.js";
const emptyArray = new Array(0);
export class EmojiHandler {
    _emojis;
    _emojiCarousel;
    _view;
    _anchor = null;
    _popupCloser;
    _suggestProps;
    _suggestRenderItem;
    constructor({ defs, shortcuts = {} }) {
        this._emojis = Object.entries(defs).map(([name, symbol]) => {
            const def = { symbol, origName: name, name: name.toLowerCase() };
            const short = shortcuts[name];
            if (short) {
                def.origShortcuts = emptyArray.concat(short);
                def.shortcuts = def.origShortcuts.map((val) => val.startsWith(':') ? val.slice(1) : val);
            }
            return def;
        });
    }
    onOpen(action) {
        this.findAnchor();
        if (!this._anchor) {
            this.closeAutocomplete(action.view);
            return true;
        }
        this._popupCloser = new AutocompletePopupCloser(action.view);
        this.updateState(action);
        this.filterActions();
        this.render();
        return true;
    }
    onFilter(action) {
        if (action.filter?.endsWith('  ')) {
            this.closeAutocomplete(action.view);
            return true;
        }
        this.updateState(action);
        const needToClose = this.filterActions(action.filter?.trim());
        this.render();
        if (needToClose) {
            this.closeAutocomplete(action.view);
        }
        return true;
    }
    onArrow(action) {
        this.updateState(action);
        if (!this._emojiCarousel)
            return false;
        switch (action.kind) {
            case AutocompleteActionKind.up: {
                this._emojiCarousel.prev();
                break;
            }
            case AutocompleteActionKind.down: {
                this._emojiCarousel.next();
                break;
            }
            default:
                return false;
        }
        this.render();
        return true;
    }
    onEnter(action) {
        this.updateState(action);
        this.select();
        return true;
    }
    onClose(action) {
        this.updateState(action);
        this.clear();
        return true;
    }
    onDestroy() {
        this.clear();
    }
    closeAutocomplete(view) {
        setTimeout(() => {
            closeAutocomplete(view);
        });
    }
    select() {
        const { _view: view } = this;
        if (!view)
            return;
        const emojiDef = this._emojiCarousel?.currentItem;
        if (!emojiDef)
            return;
        const autocompleteState = getAutocompleteState(view.state);
        if (!autocompleteState || !autocompleteState.active)
            return;
        const { range } = autocompleteState;
        const { tr, schema } = view.state;
        view.dispatch(tr.replaceWith(range.from, range.to, createEmoji(schema, emojiDef)).scrollIntoView());
        view.focus();
    }
    filterActions(inputText) {
        const currentItem = this._emojiCarousel?.currentItem;
        let filteredEmojis = this._emojis;
        let needToClose = false;
        if (inputText) {
            filteredEmojis = filterEmojis(filteredEmojis, inputText);
            needToClose = !filteredEmojis.length && needToHide(this._emojis, inputText);
        }
        this._emojiCarousel = new ArrayCarousel(filteredEmojis);
        if (currentItem) {
            const newIndex = this._emojiCarousel.array.findIndex((item) => item === currentItem);
            if (newIndex !== -1) {
                this._emojiCarousel.currentIndex = newIndex;
            }
        }
        return needToClose;
    }
    render() {
        this.findAnchor();
        const viewItems = this._emojiCarousel?.array ?? [];
        this._suggestProps = {
            anchorElement: this._anchor,
            currentIndex: this._emojiCarousel?.currentIndex,
            items: viewItems,
            onClick: this.onItemClick,
            onOpenChange: this._popupCloser?.popupOpenChangeHandler,
        };
        this._suggestRenderItem = this._suggestRenderItem ?? this.createMenuRenderItem();
        this._suggestRenderItem.rerender();
    }
    onItemClick = (index) => {
        if (this._emojiCarousel) {
            this._emojiCarousel.currentIndex = index;
            this.select();
        }
        this._view?.focus();
    };
    updateState({ view }) {
        this._view = view;
    }
    clear() {
        this._view = undefined;
        this._anchor = null;
        this._emojiCarousel = undefined;
        this._popupCloser?.cancelTimer();
        this._popupCloser = undefined;
        this._suggestProps = undefined;
        this._suggestRenderItem?.remove();
        this._suggestRenderItem = undefined;
    }
    createMenuRenderItem() {
        return getReactRendererFromState(this._view.state).createItem('emoji_suggest', () => this._suggestProps ? render(this._suggestProps) : null);
    }
    findAnchor() {
        this._anchor = findDecoElem(this._view?.dom);
    }
}
function createEmoji(schema, def) {
    return EmojiConsts.nodeType(schema).create({ [EmojiConsts.NodeAttrs.Markup]: def.name }, schema.text(def.symbol));
}
function filterEmojis(defs, text) {
    if (!text)
        return defs;
    const textLowerCase = text.toLowerCase();
    const byShortcuts = [];
    const byName = [];
    for (const emoji of defs) {
        if (emoji.shortcuts?.some((val) => val.startsWith(text))) {
            byShortcuts.push(emoji);
        }
        else if (emoji.name.startsWith(textLowerCase)) {
            byName.push(emoji);
        }
    }
    return byShortcuts.concat(byName);
}
const CHARS_TO_HIDE = 4;
function needToHide(defs, text) {
    let iter = 1;
    do {
        const prevInput = text.slice(0, text.length - iter);
        const prevActions = filterEmojis(defs, prevInput);
        if (prevActions.length)
            break;
        iter++;
    } while (iter < text.length && iter < CHARS_TO_HIDE);
    return iter >= CHARS_TO_HIDE;
}
//# sourceMappingURL=EmojiHandler.js.map
