
import { __decorate, __param } from '../../../../../../../../../external/tslib/tslib.es6.js';
import { getActiveElement, getRootContainer, show, hide, append, $, clearNode, reset } from '../../../../../../base/browser/dom.js';
import { safeSetInnerHtml } from '../../../../../../base/browser/domSanitize.js';
import { renderIcon } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js';
import { raceCancellation, disposableTimeout } from '../../../../../../base/common/async.js';
import { CancellationTokenSource } from '../../../../../../base/common/cancellation.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { ThemeIcon } from '../../../../../../base/common/themables.js';
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from '../../../../../../base/common/lifecycle.js';
import { CodeEditorWidget } from '../../../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';
import { EditorContextKeys } from '../../../../../../editor/common/editorContextKeys.js';
import { ILanguageService } from '../../../../../../editor/common/languages/language.service.js';
import { tokenizeToStringSync } from '../../../../../../editor/common/languages/textToHtmlTokenizer.js';
import { localize } from '../../../../../../nls.js';
import { IAccessibilityService } from '../../../../../../platform/accessibility/common/accessibility.service.js';
import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.service.js';
import { IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.service.js';
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
import { ServiceCollection } from '../../../../../../platform/instantiation/common/serviceCollection.js';
import { IKeybindingService } from '../../../../../../platform/keybinding/common/keybinding.service.js';
import { CellEditState, CellFocusMode, EXPAND_CELL_INPUT_COMMAND_ID, CellFoldingState } from '../../notebookBrowser.js';
import { expandedIcon, collapsedIcon } from '../../notebookIcons.js';
import { CellEditorOptions } from './cellEditorOptions.js';
import { collapsedCellTTPolicy } from '../notebookRenderingCommon.js';
import { WordHighlighterContribution } from '../../../../../../editor/contrib/wordHighlighter/browser/wordHighlighter.js';

let MarkupCell = class MarkupCell extends Disposable {
    constructor(
        notebookEditor,
        viewCell,
        templateData,
        renderedEditors,
        accessibilityService,
        contextKeyService,
        instantiationService,
        languageService,
        configurationService,
        keybindingService
    ) {
        super();
        this.notebookEditor = notebookEditor;
        this.viewCell = viewCell;
        this.templateData = templateData;
        this.renderedEditors = renderedEditors;
        this.accessibilityService = accessibilityService;
        this.contextKeyService = contextKeyService;
        this.instantiationService = instantiationService;
        this.languageService = languageService;
        this.configurationService = configurationService;
        this.keybindingService = keybindingService;
        this.editor = null;
        this.localDisposables = this._register(( new DisposableStore()));
        this.focusSwitchDisposable = this._register(( new MutableDisposable()));
        this.editorDisposables = this._register(( new DisposableStore()));
        this._isDisposed = false;
        this.constructDOM();
        this.editorPart = templateData.editorPart;
        this.cellEditorOptions = this._register(( new CellEditorOptions(
            this.notebookEditor.getBaseCellEditorOptions(viewCell.language),
            this.notebookEditor.notebookOptions,
            this.configurationService
        )));
        this.cellEditorOptions.setLineNumbers(this.viewCell.lineNumbers);
        this.editorOptions = this.cellEditorOptions.getValue(this.viewCell.internalMetadata, this.viewCell.uri);
        this._register(toDisposable(() => renderedEditors.delete(this.viewCell)));
        this.registerListeners();
        this.templateData.cellParts.scheduleRenderCell(this.viewCell);
        this._register(toDisposable(() => {
            this.templateData.cellParts.unrenderCell(this.viewCell);
        }));
        this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => {
            this.viewUpdate();
        }));
        this.updateForHover();
        this.updateForFocusModeChange();
        this.foldingState = viewCell.foldingState;
        this.layoutFoldingIndicator();
        this.updateFoldingIconShowClass();
        if (this.viewCell.layoutInfo.totalHeight > 0) {
            this.relayoutCell();
        }
        this.viewUpdate();
        this.layoutCellParts();
        this._register(this.viewCell.onDidChangeLayout(() => {
            this.layoutCellParts();
        }));
    }
    layoutCellParts() {
        this.templateData.cellParts.updateInternalLayoutNow(this.viewCell);
    }
    constructDOM() {
        const id = `aria-markup-cell-${this.viewCell.id}`;
        this.markdownAccessibilityContainer = this.templateData.cellContainer;
        this.markdownAccessibilityContainer.id = id;
        this.markdownAccessibilityContainer.style.height = "1px";
        this.markdownAccessibilityContainer.style.overflow = "hidden";
        this.markdownAccessibilityContainer.style.position = "absolute";
        this.markdownAccessibilityContainer.style.top = "100000px";
        this.markdownAccessibilityContainer.style.left = "10000px";
        this.markdownAccessibilityContainer.ariaHidden = "false";
        this.templateData.rootContainer.setAttribute("aria-describedby", id);
        this.templateData.container.classList.toggle("webview-backed-markdown-cell", true);
    }
    registerListeners() {
        this._register(this.viewCell.onDidChangeState(e => {
            this.templateData.cellParts.updateState(this.viewCell, e);
        }));
        this._register(this.viewCell.model.onDidChangeMetadata(() => {
            this.viewUpdate();
        }));
        this._register(this.viewCell.onDidChangeState(e => {
            if (e.editStateChanged || e.contentChanged) {
                this.viewUpdate();
            }
            if (e.focusModeChanged) {
                this.updateForFocusModeChange();
            }
            if (e.foldingStateChanged) {
                const foldingState = this.viewCell.foldingState;
                if (foldingState !== this.foldingState) {
                    this.foldingState = foldingState;
                    this.layoutFoldingIndicator();
                }
            }
            if (e.cellIsHoveredChanged) {
                this.updateForHover();
            }
            if (e.inputCollapsedChanged) {
                this.updateCollapsedState();
                this.viewUpdate();
            }
            if (e.cellLineNumberChanged) {
                this.cellEditorOptions.setLineNumbers(this.viewCell.lineNumbers);
            }
        }));
        this._register(this.notebookEditor.notebookOptions.onDidChangeOptions(e => {
            if (e.showFoldingControls) {
                this.updateFoldingIconShowClass();
            }
        }));
        this._register(this.viewCell.onDidChangeLayout(e => {
            const layoutInfo = this.editor?.getLayoutInfo();
            if (e.outerWidth && this.viewCell.getEditState() === CellEditState.Editing && layoutInfo && layoutInfo.width !== this.viewCell.layoutInfo.editorWidth) {
                this.onCellEditorWidthChange();
            }
        }));
        this._register(this.cellEditorOptions.onDidChange(() => this.updateMarkupCellOptions()));
    }
    updateMarkupCellOptions() {
        this.updateEditorOptions(
            this.cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata, this.viewCell.uri)
        );
        if (this.editor) {
            this.editor.updateOptions(
                this.cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata, this.viewCell.uri)
            );
            const cts = ( new CancellationTokenSource());
            this._register({
                dispose() {
                    cts.dispose(true);
                }
            });
            raceCancellation(this.viewCell.resolveTextModel(), cts.token).then(model => {
                if (this._isDisposed) {
                    return;
                }
                if (model) {
                    model.updateOptions({
                        indentSize: this.cellEditorOptions.indentSize,
                        tabSize: this.cellEditorOptions.tabSize,
                        insertSpaces: this.cellEditorOptions.insertSpaces
                    });
                }
            });
        }
    }
    updateCollapsedState() {
        if (this.viewCell.isInputCollapsed) {
            this.notebookEditor.hideMarkupPreviews([this.viewCell]);
        } else {
            this.notebookEditor.unhideMarkupPreviews([this.viewCell]);
        }
    }
    updateForHover() {
        this.templateData.container.classList.toggle("markdown-cell-hover", this.viewCell.cellIsHovered);
    }
    updateForFocusModeChange() {
        if (this.viewCell.focusMode === CellFocusMode.Editor) {
            this.focusEditorIfNeeded();
        }
        this.templateData.container.classList.toggle("cell-editor-focus", this.viewCell.focusMode === CellFocusMode.Editor);
    }
    dispose() {
        this._isDisposed = true;
        if (this.notebookEditor.getActiveCell() === this.viewCell && this.viewCell.focusMode === CellFocusMode.Editor && (this.notebookEditor.hasEditorFocus() || getActiveElement(this.notebookEditor.getDomNode().ownerDocument) === getRootContainer(this.notebookEditor.getDomNode()))) {
            this.notebookEditor.focusContainer();
        }
        this.viewCell.detachTextEditor();
        super.dispose();
    }
    updateFoldingIconShowClass() {
        const showFoldingIcon = this.notebookEditor.notebookOptions.getDisplayOptions().showFoldingControls;
        this.templateData.foldingIndicator.classList.remove("mouseover", "always");
        this.templateData.foldingIndicator.classList.add(showFoldingIcon);
    }
    viewUpdate() {
        if (this.viewCell.isInputCollapsed) {
            this.viewUpdateCollapsed();
        } else if (this.viewCell.getEditState() === CellEditState.Editing) {
            this.viewUpdateEditing();
        } else {
            this.viewUpdatePreview();
        }
    }
    viewUpdateCollapsed() {
        show(this.templateData.cellInputCollapsedContainer);
        hide(this.editorPart);
        this.templateData.cellInputCollapsedContainer.innerText = "";
        const markdownIcon = append(this.templateData.cellInputCollapsedContainer, $("span"));
        markdownIcon.classList.add(...ThemeIcon.asClassNameArray(Codicon.markdown));
        const element = $("div");
        element.classList.add("cell-collapse-preview");
        const richEditorText = this.getRichText(this.viewCell.textBuffer, this.viewCell.language);
        element.innerText = richEditorText;
        element.innerHTML = (collapsedCellTTPolicy?.createHTML(richEditorText) ?? richEditorText);
        this.templateData.cellInputCollapsedContainer.appendChild(element);
        const expandIcon = append(element, $("span.expandInputIcon"));
        expandIcon.classList.add(...ThemeIcon.asClassNameArray(Codicon.more));
        const keybinding = this.keybindingService.lookupKeybinding(EXPAND_CELL_INPUT_COMMAND_ID);
        if (keybinding) {
            element.title = ( localize(11388, "Double-click to expand cell input ({0})", keybinding.getLabel()));
            expandIcon.title = ( localize(11389, "Expand Cell Input ({0})", keybinding.getLabel()));
        }
        this.markdownAccessibilityContainer.ariaHidden = "true";
        this.templateData.container.classList.toggle("input-collapsed", true);
        this.viewCell.renderedMarkdownHeight = 0;
        this.viewCell.layoutChange({});
    }
    getRichText(buffer, language) {
        return tokenizeToStringSync(this.languageService, buffer.getLineContent(1), language);
    }
    viewUpdateEditing() {
        let editorHeight;
        show(this.editorPart);
        this.markdownAccessibilityContainer.ariaHidden = "true";
        hide(this.templateData.cellInputCollapsedContainer);
        this.notebookEditor.hideMarkupPreviews([this.viewCell]);
        this.templateData.container.classList.toggle("input-collapsed", false);
        this.templateData.container.classList.toggle("markdown-cell-edit-mode", true);
        if (this.editor && this.editor.hasModel()) {
            editorHeight = this.editor.getContentHeight();
            this.viewCell.attachTextEditor(this.editor);
            this.focusEditorIfNeeded();
            this.bindEditorListeners(this.editor);
            this.editor.layout({
                width: this.viewCell.layoutInfo.editorWidth,
                height: editorHeight
            });
        } else {
            this.editorDisposables.clear();
            const width = this.notebookEditor.notebookOptions.computeMarkdownCellEditorWidth(this.notebookEditor.getLayoutInfo().width);
            const lineNum = this.viewCell.lineCount;
            const lineHeight = this.viewCell.layoutInfo.fontInfo?.lineHeight || 17;
            const editorPadding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata, this.viewCell.uri);
            editorHeight = Math.max(lineNum, 1) * lineHeight + editorPadding.top + editorPadding.bottom;
            this.templateData.editorContainer.innerText = "";
            const editorContextKeyService = this.contextKeyService.createScoped(this.templateData.editorPart);
            EditorContextKeys.inCompositeEditor.bindTo(editorContextKeyService).set(true);
            const editorInstaService = this.editorDisposables.add(this.instantiationService.createChild(( new ServiceCollection([IContextKeyService, editorContextKeyService]))));
            this.editorDisposables.add(editorContextKeyService);
            this.editor = this.editorDisposables.add(
                editorInstaService.createInstance(CodeEditorWidget, this.templateData.editorContainer, {
                    ...this.editorOptions,
                    dimension: {
                        width: width,
                        height: editorHeight
                    },
                    allowVariableLineHeights: false
                }, {
                    contributions: this.notebookEditor.creationOptions.cellEditorContributions
                })
            );
            this.templateData.currentEditor = this.editor;
            this.editorDisposables.add(this.editor.onDidBlurEditorWidget(() => {
                if (this.editor) {
                    WordHighlighterContribution.get(this.editor)?.stopHighlighting();
                }
            }));
            this.editorDisposables.add(this.editor.onDidFocusEditorWidget(() => {
                if (this.editor) {
                    WordHighlighterContribution.get(this.editor)?.restoreViewState(true);
                }
            }));
            const cts = ( new CancellationTokenSource());
            this.editorDisposables.add({
                dispose() {
                    cts.dispose(true);
                }
            });
            raceCancellation(this.viewCell.resolveTextModel(), cts.token).then(model => {
                if (!model) {
                    return;
                }
                this.editor.setModel(model);
                model.updateOptions({
                    indentSize: this.cellEditorOptions.indentSize,
                    tabSize: this.cellEditorOptions.tabSize,
                    insertSpaces: this.cellEditorOptions.insertSpaces
                });
                const realContentHeight = this.editor.getContentHeight();
                if (realContentHeight !== editorHeight) {
                    this.editor.layout({
                        width: width,
                        height: realContentHeight
                    });
                    editorHeight = realContentHeight;
                }
                this.viewCell.attachTextEditor(this.editor);
                if (this.viewCell.getEditState() === CellEditState.Editing) {
                    this.focusEditorIfNeeded();
                }
                this.bindEditorListeners(this.editor);
                this.viewCell.editorHeight = editorHeight;
            });
        }
        this.viewCell.editorHeight = editorHeight;
        this.focusEditorIfNeeded();
        this.renderedEditors.set(this.viewCell, this.editor);
    }
    viewUpdatePreview() {
        this.viewCell.detachTextEditor();
        hide(this.editorPart);
        hide(this.templateData.cellInputCollapsedContainer);
        this.markdownAccessibilityContainer.ariaHidden = "false";
        this.templateData.container.classList.toggle("input-collapsed", false);
        this.templateData.container.classList.toggle("markdown-cell-edit-mode", false);
        this.renderedEditors.delete(this.viewCell);
        this.markdownAccessibilityContainer.innerText = "";
        if (this.viewCell.renderedHtml) {
            if (this.accessibilityService.isScreenReaderOptimized()) {
                safeSetInnerHtml(this.markdownAccessibilityContainer, this.viewCell.renderedHtml);
            } else {
                clearNode(this.markdownAccessibilityContainer);
            }
        }
        this.notebookEditor.createMarkupPreview(this.viewCell);
    }
    focusEditorIfNeeded() {
        if (this.viewCell.focusMode === CellFocusMode.Editor && (this.notebookEditor.hasEditorFocus() || getActiveElement(this.notebookEditor.getDomNode().ownerDocument) === getRootContainer(this.notebookEditor.getDomNode()))) {
            if (!this.editor) {
                return;
            }
            this.editor.focus();
            const primarySelection = this.editor.getSelection();
            if (!primarySelection) {
                return;
            }
            this.notebookEditor.revealRangeInViewAsync(this.viewCell, primarySelection);
        }
    }
    layoutEditor(dimension) {
        this.editor?.layout(dimension);
    }
    onCellEditorWidthChange() {
        const realContentHeight = this.editor.getContentHeight();
        this.layoutEditor({
            width: this.viewCell.layoutInfo.editorWidth,
            height: realContentHeight
        });
    }
    relayoutCell() {
        this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
        this.layoutFoldingIndicator();
    }
    updateEditorOptions(newValue) {
        this.editorOptions = newValue;
        this.editor?.updateOptions(this.editorOptions);
    }
    layoutFoldingIndicator() {
        switch (this.foldingState) {
        case CellFoldingState.None:
            this.templateData.foldingIndicator.style.display = "none";
            this.templateData.foldingIndicator.innerText = "";
            break;
        case CellFoldingState.Collapsed:
            this.templateData.foldingIndicator.style.display = "";
            reset(this.templateData.foldingIndicator, renderIcon(collapsedIcon));
            break;
        case CellFoldingState.Expanded:
            this.templateData.foldingIndicator.style.display = "";
            reset(this.templateData.foldingIndicator, renderIcon(expandedIcon));
            break;
        }
    }
    bindEditorListeners(editor) {
        this.localDisposables.clear();
        this.focusSwitchDisposable.clear();
        this.localDisposables.add(editor.onDidContentSizeChange(e => {
            if (e.contentHeightChanged) {
                this.onCellEditorHeightChange(editor, e.contentHeight);
            }
        }));
        this.localDisposables.add(editor.onDidChangeCursorSelection(e => {
            if (e.source === "restoreState") {
                return;
            }
            const selections = editor.getSelections();
            if (selections?.length) {
                const contentHeight = editor.getContentHeight();
                const layoutContentHeight = this.viewCell.layoutInfo.editorHeight;
                if (contentHeight !== layoutContentHeight) {
                    this.onCellEditorHeightChange(editor, contentHeight);
                }
                const lastSelection = selections[selections.length - 1];
                this.notebookEditor.revealRangeInViewAsync(this.viewCell, lastSelection);
            }
        }));
        const updateFocusMode = () => this.viewCell.focusMode = editor.hasWidgetFocus() ? CellFocusMode.Editor : CellFocusMode.Container;
        this.localDisposables.add(editor.onDidFocusEditorWidget(() => {
            updateFocusMode();
        }));
        this.localDisposables.add(editor.onDidBlurEditorWidget(() => {
            if (getActiveElement(this.templateData.container.ownerDocument)?.contains(this.templateData.container)) {
                this.focusSwitchDisposable.value = disposableTimeout(() => updateFocusMode(), 300);
            } else {
                updateFocusMode();
            }
        }));
        updateFocusMode();
    }
    onCellEditorHeightChange(editor, newHeight) {
        const viewLayout = editor.getLayoutInfo();
        this.viewCell.editorHeight = newHeight;
        editor.layout({
            width: viewLayout.width,
            height: newHeight
        });
    }
};
MarkupCell = ( __decorate([( __param(4, IAccessibilityService)), ( __param(5, IContextKeyService)), ( __param(6, IInstantiationService)), ( __param(7, ILanguageService)), ( __param(8, IConfigurationService)), ( __param(9, IKeybindingService))], MarkupCell));

export { MarkupCell };
