import { __decorate, __param } from '../../../../../../../../external/tslib/tslib.es6.js';
import { Emitter, Event } from '../../../../../base/common/event.js';
import { DisposableStore, combinedDisposable, MutableDisposable } from '../../../../../base/common/lifecycle.js';
import { isEqual } from '../../../../../base/common/resources.js';
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.service.js';
import { IMarkerService } from '../../../../../platform/markers/common/markers.service.js';
import { IThemeService } from '../../../../../platform/theme/common/themeService.service.js';
import { NotebookSetting, CellKind } from '../../common/notebookCommon.js';
import { NotebookExecutionType } from '../../common/notebookExecutionStateService.js';
import { INotebookExecutionStateService } from '../../common/notebookExecutionStateService.service.js';
import { IOutlineModelService } from '../../../../../editor/contrib/documentSymbols/browser/outlineModel.js';
import { NotebookOutlineEntryFactory } from './notebookOutlineEntryFactory.js';
let NotebookCellOutlineProvider = class NotebookCellOutlineProvider {
    get entries() {
        return this._entries;
    }
    get activeElement() {
        return this._activeEntry;
    }
    constructor(_editor, _target, themeService, notebookExecutionStateService, _outlineModelService, _markerService, _configurationService) {
        this._editor = _editor;
        this._target = _target;
        this._outlineModelService = _outlineModelService;
        this._markerService = _markerService;
        this._configurationService = _configurationService;
        this._dispoables = ( new DisposableStore());
        this._onDidChange = ( new Emitter());
        this.onDidChange = this._onDidChange.event;
        this._entries = [];
        this._entriesDisposables = ( new DisposableStore());
        this.outlineKind = 'notebookCells';
        this._outlineEntryFactory = ( new NotebookOutlineEntryFactory(notebookExecutionStateService));
        const selectionListener = ( new MutableDisposable());
        this._dispoables.add(selectionListener);
        selectionListener.value = combinedDisposable(Event.debounce(_editor.onDidChangeSelection, (last, _current) => last, 200)(this._recomputeActive, this), Event.debounce(_editor.onDidChangeViewCells, (last, _current) => last ?? _current, 200)(this._recomputeState, this));
        this._dispoables.add(_configurationService.onDidChangeConfiguration(e => {
            if (e.affectsConfiguration(NotebookSetting.outlineShowMarkdownHeadersOnly) ||
                e.affectsConfiguration(NotebookSetting.outlineShowCodeCells) ||
                e.affectsConfiguration(NotebookSetting.outlineShowCodeCellSymbols) ||
                e.affectsConfiguration(NotebookSetting.breadcrumbsShowCodeCells)) {
                this._recomputeState();
            }
        }));
        this._dispoables.add(themeService.onDidFileIconThemeChange(() => {
            this._onDidChange.fire({});
        }));
        this._dispoables.add(notebookExecutionStateService.onDidChangeExecution(e => {
            if (e.type === NotebookExecutionType.cell && !!this._editor.textModel && e.affectsNotebook(this._editor.textModel?.uri)) {
                this._recomputeState();
            }
        }));
        this._recomputeState();
    }
    dispose() {
        this._entries.length = 0;
        this._activeEntry = undefined;
        this._entriesDisposables.dispose();
        this._dispoables.dispose();
    }
    init() {
        this._recomputeState();
    }
    async setFullSymbols(cancelToken) {
        const notebookEditorWidget = this._editor;
        const notebookCells = notebookEditorWidget?.getViewModel()?.viewCells.filter((cell) => cell.cellKind === CellKind.Code);
        this._entries.length = 0;
        if (notebookCells) {
            const promises = [];
            for (const cell of notebookCells.slice(0, 100)) {
                promises.push(this._outlineEntryFactory.cacheSymbols(cell, this._outlineModelService, cancelToken));
            }
            await Promise.allSettled(promises);
        }
        this._recomputeState();
    }
    _recomputeState() {
        this._entriesDisposables.clear();
        this._activeEntry = undefined;
        this._uri = undefined;
        if (!this._editor.hasModel()) {
            return;
        }
        this._uri = this._editor.textModel.uri;
        const notebookEditorWidget = this._editor;
        if (notebookEditorWidget.getLength() === 0) {
            return;
        }
        let includeCodeCells = true;
        if (this._target === 2 ) {
            includeCodeCells = this._configurationService.getValue('notebook.breadcrumbs.showCodeCells');
        }
        let notebookCells;
        if (this._target === 2 ) {
            notebookCells = notebookEditorWidget.getViewModel().viewCells.filter((cell) => cell.cellKind === CellKind.Markup || includeCodeCells);
        }
        else {
            notebookCells = notebookEditorWidget.getViewModel().viewCells;
        }
        const entries = [];
        for (const cell of notebookCells) {
            entries.push(...this._outlineEntryFactory.getOutlineEntries(cell, this._target, entries.length));
            this._entriesDisposables.add(cell.model.onDidChangeContent(() => {
                this._recomputeState();
                this._onDidChange.fire({});
            }));
        }
        if (entries.length > 0) {
            const result = [entries[0]];
            const parentStack = [entries[0]];
            for (let i = 1; i < entries.length; i++) {
                const entry = entries[i];
                while (true) {
                    const len = parentStack.length;
                    if (len === 0) {
                        result.push(entry);
                        parentStack.push(entry);
                        break;
                    }
                    else {
                        const parentCandidate = parentStack[len - 1];
                        if (parentCandidate.level < entry.level) {
                            parentCandidate.addChild(entry);
                            parentStack.push(entry);
                            break;
                        }
                        else {
                            parentStack.pop();
                        }
                    }
                }
            }
            this._entries = result;
        }
        const markerServiceListener = ( new MutableDisposable());
        this._entriesDisposables.add(markerServiceListener);
        const updateMarkerUpdater = () => {
            if (notebookEditorWidget.isDisposed) {
                return;
            }
            const doUpdateMarker = (clear) => {
                for (const entry of this._entries) {
                    if (clear) {
                        entry.clearMarkers();
                    }
                    else {
                        entry.updateMarkers(this._markerService);
                    }
                }
            };
            const problem = this._configurationService.getValue('problems.visibility');
            if (problem === undefined) {
                return;
            }
            const config = this._configurationService.getValue("outline.problems.enabled" );
            if (problem && config) {
                markerServiceListener.value = this._markerService.onMarkerChanged(e => {
                    if (notebookEditorWidget.isDisposed) {
                        console.error('notebook editor is disposed');
                        return;
                    }
                    if (( e.some(uri => ( notebookEditorWidget.getCellsInRange().some(cell => isEqual(cell.uri, uri)))))) {
                        doUpdateMarker(false);
                        this._onDidChange.fire({});
                    }
                });
                doUpdateMarker(false);
            }
            else {
                markerServiceListener.clear();
                doUpdateMarker(true);
            }
        };
        updateMarkerUpdater();
        this._entriesDisposables.add(this._configurationService.onDidChangeConfiguration(e => {
            if (e.affectsConfiguration('problems.visibility') || e.affectsConfiguration("outline.problems.enabled" )) {
                updateMarkerUpdater();
                this._onDidChange.fire({});
            }
        }));
        this._recomputeActive();
        this._onDidChange.fire({});
    }
    _recomputeActive() {
        let newActive;
        const notebookEditorWidget = this._editor;
        if (notebookEditorWidget) {
            if (notebookEditorWidget.hasModel() && notebookEditorWidget.getLength() > 0) {
                const cell = notebookEditorWidget.cellAt(notebookEditorWidget.getFocus().start);
                if (cell) {
                    for (const entry of this._entries) {
                        newActive = entry.find(cell, []);
                        if (newActive) {
                            break;
                        }
                    }
                }
            }
        }
        const showCodeCells = this._configurationService.getValue(NotebookSetting.outlineShowCodeCells);
        const showCodeCellSymbols = this._configurationService.getValue(NotebookSetting.outlineShowCodeCellSymbols);
        const showMarkdownHeadersOnly = this._configurationService.getValue(NotebookSetting.outlineShowMarkdownHeadersOnly);
        if ((newActive !== this._activeEntry) && !((
        (showMarkdownHeadersOnly && newActive?.cell.cellKind === CellKind.Markup && newActive?.level === 7) ||
            (!showCodeCells && newActive?.cell.cellKind === CellKind.Code) || (!showCodeCellSymbols && newActive?.cell.cellKind === CellKind.Code && newActive?.level > 7))
        )) {
            this._activeEntry = newActive;
            this._onDidChange.fire({ affectOnlyActiveElement: true });
        }
    }
    get isEmpty() {
        return this._entries.length === 0;
    }
    get uri() {
        return this._uri;
    }
};
NotebookCellOutlineProvider = ( __decorate([
    ( __param(2, IThemeService)),
    ( __param(3, INotebookExecutionStateService)),
    ( __param(4, IOutlineModelService)),
    ( __param(5, IMarkerService)),
    ( __param(6, IConfigurationService))
], NotebookCellOutlineProvider));
export { NotebookCellOutlineProvider };
