import { isFunction } from "../../../lodash.js";
import { globalLogger } from "../../../logger.js";
import { AutocompletePopupCloser } from "../../../utils/autocomplete-popup.js";
import { ArrayCarousel } from "../../../utils/carousel/index.js";
import { AutocompleteActionKind, closeAutocomplete, getAutocompleteState, } from "../Autocomplete/index.js";
import { getReactRendererFromState } from "../ReactRenderer/index.js";
import { render } from "./component.js";
import { findDecoElem } from "./utils.js";
export class CommandHandler {
    #logger;
    #actions;
    #actionStorage;
    #nodesIgnoreList;
    #filteredActionsCarousel;
    #view;
    #anchor = null;
    #filterText;
    #popupCloser;
    #menuProps;
    #menuRenderItem;
    constructor({ logger, actions, storage, nodesIgnoreList = [] }) {
        this.#logger = logger;
        this.#actions = actions;
        this.#actionStorage = storage;
        this.#nodesIgnoreList = nodesIgnoreList;
    }
    onOpen(action) {
        this.findAnchor();
        if (!this.#anchor || this.shouldIgnore(action)) {
            this.closeAutocomplete(action.view);
            return true;
        }
        this.#popupCloser = new AutocompletePopupCloser(action.view);
        this.updateState(action);
        this.filterActions();
        this.render();
        return true;
    }
    onFilter(action) {
        if (this.shouldIgnore(action) || action.filter?.endsWith('  ')) {
            this.closeAutocomplete(action.view);
            return true;
        }
        this.updateState(action);
        this.#filterText = action.filter?.trim().toLowerCase();
        const needToClose = this.filterActions();
        this.render();
        if (needToClose) {
            this.closeAutocomplete(action.view);
        }
        return true;
    }
    onArrow(action) {
        if (this.shouldIgnore(action)) {
            closeAutocomplete(action.view);
            return true;
        }
        this.updateState(action);
        if (!this.#filteredActionsCarousel)
            return false;
        switch (action.kind) {
            case AutocompleteActionKind.up: {
                this.#filteredActionsCarousel.prev();
                break;
            }
            case AutocompleteActionKind.down: {
                this.#filteredActionsCarousel.next();
                break;
            }
            default:
                return false;
        }
        this.render();
        return true;
    }
    onEnter(action) {
        if (this.shouldIgnore(action)) {
            closeAutocomplete(action.view);
            return true;
        }
        this.updateState(action);
        this.select();
        return true;
    }
    onClose(action) {
        this.updateState(action);
        this.clear();
        return true;
    }
    onDestroy() {
        this.clear();
    }
    closeAutocomplete(view) {
        setTimeout(() => {
            closeAutocomplete(view);
        });
    }
    shouldIgnore(action) {
        const parentType = action.view.state.doc.resolve(action.range.from).parent.type;
        return (parentType.spec.commandMenu === false || this.#nodesIgnoreList.includes(parentType.name));
    }
    select() {
        if (!this.#view)
            return;
        const action = this.#filteredActionsCarousel?.currentItem;
        if (!action)
            return;
        const autocompleteState = getAutocompleteState(this.#view.state);
        if (!autocompleteState || !autocompleteState.active)
            return;
        const view = this.#view;
        const { range } = autocompleteState;
        view.dispatch(view.state.tr.deleteRange(range.from, range.to).scrollIntoView());
        action.exec(this.#actionStorage);
        view.focus();
        globalLogger.action({ mode: 'wysiwyg', source: 'command-menu', action: action.id });
        this.#logger.action({ source: 'command-menu', action: action.id });
    }
    filterActions() {
        const currentItem = this.#filteredActionsCarousel?.currentItem;
        const inputText = this.#filterText;
        const enabledActions = this.#actions.filter((action) => action.isEnable(this.#actionStorage));
        let filteredActions = enabledActions;
        let needToClose = false;
        if (inputText) {
            filteredActions = filterActions(enabledActions, inputText);
            needToClose = !filteredActions.length && needToHide(enabledActions, inputText);
        }
        this.#filteredActionsCarousel = new ArrayCarousel(filteredActions);
        if (currentItem) {
            const newIndex = this.#filteredActionsCarousel.array.findIndex((item) => item === currentItem);
            if (newIndex !== -1) {
                this.#filteredActionsCarousel.currentIndex = newIndex;
            }
        }
        return needToClose;
    }
    render() {
        this.findAnchor();
        const viewItems = this.#filteredActionsCarousel?.array ?? [];
        this.#menuProps = {
            anchorElement: this.#anchor,
            currentIndex: this.#filteredActionsCarousel?.currentIndex,
            items: viewItems,
            onItemClick: this.onItemClick,
            onOpenChange: this.#popupCloser?.popupOpenChangeHandler,
        };
        this.#menuRenderItem = this.#menuRenderItem ?? this.createMenuRenderItem();
        this.#menuRenderItem.rerender();
    }
    onItemClick = (index) => {
        if (this.#filteredActionsCarousel) {
            this.#filteredActionsCarousel.currentIndex = index;
            this.select();
        }
        this.#view?.focus();
    };
    updateState({ view }) {
        this.#view = view;
    }
    clear() {
        this.#view = undefined;
        this.#anchor = null;
        this.#filterText = undefined;
        this.#filteredActionsCarousel = undefined;
        this.#popupCloser?.cancelTimer();
        this.#popupCloser = undefined;
        this.#menuProps = undefined;
        this.#menuRenderItem?.remove();
        this.#menuRenderItem = undefined;
    }
    createMenuRenderItem() {
        return getReactRendererFromState(this.#view.state).createItem('command_menu', () => this.#menuProps ? render(this.#menuProps) : null);
    }
    findAnchor() {
        this.#anchor = findDecoElem(this.#view?.dom);
    }
}
function filterActions(actions, text) {
    return actions.filter((action) => action.id.toLowerCase().includes(text) ||
        (isFunction(action.title) ? action.title() : action.title).toLowerCase().includes(text));
}
const CHARS_TO_HIDE = 4;
function needToHide(actions, text) {
    let iter = 1;
    do {
        const prevInput = text.slice(0, text.length - iter);
        const prevActions = filterActions(actions, prevInput);
        if (prevActions.length)
            break;
        iter++;
    } while (iter < text.length && iter < CHARS_TO_HIDE);
    return iter >= CHARS_TO_HIDE;
}
//# sourceMappingURL=handler.js.map
