import { WidgetType } from '@codemirror/view';
import { Decoration, ViewPlugin, } from "../../../../cm/view.js";
import { ReactRendererFacet } from "../../../../markup/index.js";
import { WIDGET_DECO_CLASS_NAME } from "../constants.js";
import { isEmptyGptPrompts } from "../utils.js";
import { hideMarkupGpt } from "./commands.js";
import { HideMarkupGptEffect, ShowMarkupGptEffect } from "./effects.js";
import { renderPopup } from "./popup.js";
class SpanWidget extends WidgetType {
    className = '';
    textContent = '';
    constructor(className, textContent) {
        super();
        this.className = className;
        this.textContent = textContent;
    }
    toDOM() {
        const spanElem = document.createElement('span');
        spanElem.className = this.className;
        spanElem.textContent = this.textContent;
        return spanElem;
    }
}
export function mGptPlugin(gptProps) {
    return ViewPlugin.fromClass(class {
        _view;
        _renderItem;
        _anchor = null;
        decos = Decoration.none;
        disablePromptPresets = true;
        markup = null;
        selectedPosition = {
            from: 0,
            to: 0,
        };
        constructor(view) {
            this._view = view;
            this._renderItem = view.state
                .facet(ReactRendererFacet)
                .createItem('gpt-in-markup-mode', () => this.renderPopup());
        }
        update(update) {
            if (update.docChanged || update.selectionSet) {
                this.decos = Decoration.none;
                return;
            }
            this.decos = this.decos.map(update.changes);
            const { from, to } = update.state.selection.main;
            this.selectedPosition.from = from;
            this.selectedPosition.to = to;
            for (const tr of update.transactions) {
                for (const eff of tr.effects) {
                    if (eff.is(ShowMarkupGptEffect)) {
                        this._setSelectedText(this._getDecorationText(update, from, to));
                        if (from === to) {
                            this.disablePromptPresets = true;
                            if (isEmptyGptPrompts(gptProps, true))
                                return;
                            const decorationWidget = Decoration.widget({
                                widget: new SpanWidget(WIDGET_DECO_CLASS_NAME, ' '),
                            });
                            this.decos = Decoration.set([decorationWidget.range(from)]);
                            return;
                        }
                        this.disablePromptPresets = false;
                        if (isEmptyGptPrompts(gptProps, false))
                            return;
                        this.decos = Decoration.set([
                            {
                                from,
                                to,
                                value: Decoration.mark({ class: WIDGET_DECO_CLASS_NAME }),
                            },
                        ]);
                    }
                    if (eff.is(HideMarkupGptEffect)) {
                        this.decos = Decoration.none;
                    }
                }
            }
        }
        docViewUpdate() {
            this._anchor = this._view.dom
                .getElementsByClassName(WIDGET_DECO_CLASS_NAME)
                .item(0);
            this._renderItem.rerender();
        }
        destroy() {
            this._clearSelectedText();
            this._renderItem.remove();
        }
        renderPopup() {
            if (!this._anchor || this.markup === null) {
                return null;
            }
            return renderPopup(this._anchor, {
                ...gptProps,
                disablePromptPresets: this.disablePromptPresets,
                onClose: () => hideMarkupGpt(this._view),
                markup: this.markup,
                onApplyResult: (changedMarkup) => this._onApplyResult(changedMarkup),
            });
        }
        _getDecorationText(update, from, to) {
            return update.state.doc.sliceString(from, to);
        }
        _clearSelectedText() {
            this.markup = null;
        }
        _setSelectedText(str) {
            this.markup = str;
        }
        _onApplyResult(changedMarkup) {
            const { from, to } = this.selectedPosition;
            const changes = [{ from: from, to: to, insert: changedMarkup }];
            const transaction = this._view.state.update({
                changes: changes,
                effects: [HideMarkupGptEffect.of(null)],
            });
            this._view.dispatch(transaction);
        }
    }, {
        decorations: (value) => value.decos,
    });
}
//# sourceMappingURL=plugin.js.map
