
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { localize } from '../../../../nls.js';
import { PickerQuickAccessProvider, TriggerAction } from '../../../../platform/quickinput/browser/pickerQuickAccess.js';
import { ThrottledDelayer } from '../../../../base/common/async.js';
import { getWorkspaceSymbols } from '../common/search.js';
import { SymbolKind, SymbolTag, SymbolKinds } from '../../../../editor/common/languages.js';
import { ILabelService } from '../../../../platform/label/common/label.service.js';
import { Schemas } from '../../../../base/common/network.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.service.js';
import { SIDE_GROUP, ACTIVE_GROUP } from '../../../services/editor/common/editorService.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { Range } from '../../../../editor/common/core/range.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.service.js';
import { getSelectionSearchString } from '../../../../editor/contrib/find/browser/findController.js';
import { prepareQuery, pieceToQuery, scoreFuzzy2 } from '../../../../base/common/fuzzyScorer.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { IChatWidgetService } from '../../chat/browser/chat.service.js';

var SymbolsQuickAccessProvider_1;
let SymbolsQuickAccessProvider = class SymbolsQuickAccessProvider extends PickerQuickAccessProvider {
    static {
        SymbolsQuickAccessProvider_1 = this;
    }
    static {
        this.PREFIX = "#";
    }
    static {
        this.TYPING_SEARCH_DELAY = 200;
    }
    static {
        this.TREAT_AS_GLOBAL_SYMBOL_TYPES = ( new Set([
            SymbolKind.Class,
            SymbolKind.Enum,
            SymbolKind.File,
            SymbolKind.Interface,
            SymbolKind.Namespace,
            SymbolKind.Package,
            SymbolKind.Module
        ]));
    }
    get defaultFilterValue() {
        const editor = this.codeEditorService.getFocusedCodeEditor();
        if (editor) {
            return getSelectionSearchString(editor) ?? undefined;
        }
        return undefined;
    }
    constructor(
        labelService,
        openerService,
        editorService,
        configurationService,
        codeEditorService,
        chatWidgetService
    ) {
        super(SymbolsQuickAccessProvider_1.PREFIX, {
            canAcceptInBackground: true,
            noResultsPick: {
                label: ( localize(13500, "No matching workspace symbols"))
            }
        });
        this.labelService = labelService;
        this.openerService = openerService;
        this.editorService = editorService;
        this.configurationService = configurationService;
        this.codeEditorService = codeEditorService;
        this.chatWidgetService = chatWidgetService;
        this.delayer = this._register(( new ThrottledDelayer(SymbolsQuickAccessProvider_1.TYPING_SEARCH_DELAY)));
    }
    get configuration() {
        const editorConfig = this.configurationService.getValue().workbench?.editor;
        return {
            openEditorPinned: !editorConfig?.enablePreviewFromQuickOpen || !editorConfig?.enablePreview,
            openSideBySideDirection: editorConfig?.openSideBySideDirection
        };
    }
    _getPicks(filter, disposables, token) {
        return this.getSymbolPicks(filter, undefined, token);
    }
    async getSymbolPicks(filter, options, token) {
        return this.delayer.trigger(async () => {
            if (token.isCancellationRequested) {
                return [];
            }
            return this.doGetSymbolPicks(prepareQuery(filter), options, token);
        }, options?.delay);
    }
    async doGetSymbolPicks(query, options, token) {
        let symbolQuery;
        let containerQuery;
        if (query.values && query.values.length > 1) {
            symbolQuery = pieceToQuery(query.values[0]);
            containerQuery = pieceToQuery(query.values.slice(1));
        } else {
            symbolQuery = query;
        }
        const workspaceSymbols = await getWorkspaceSymbols(symbolQuery.original, token);
        if (token.isCancellationRequested) {
            return [];
        }
        const symbolPicks = [];
        const openSideBySideDirection = this.configuration.openSideBySideDirection;
        for (const {
            symbol,
            provider
        } of workspaceSymbols) {
            if (options?.skipLocal && !( SymbolsQuickAccessProvider_1.TREAT_AS_GLOBAL_SYMBOL_TYPES.has(symbol.kind)) && !!symbol.containerName) {
                continue;
            }
            const symbolLabel = symbol.name;
            let symbolScore = undefined;
            let symbolMatches = undefined;
            let skipContainerQuery = false;
            if (symbolQuery.original.length > 0) {
                if (symbolQuery !== query) {
                    [symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, {
                        ...query,
                        values: undefined
                    }, 0, 0);
                    if (typeof symbolScore === "number") {
                        skipContainerQuery = true;
                    }
                }
                if (typeof symbolScore !== "number") {
                    [symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, 0, 0);
                    if (typeof symbolScore !== "number") {
                        continue;
                    }
                }
            }
            const symbolUri = symbol.location.uri;
            let containerLabel = undefined;
            if (symbolUri) {
                const containerPath = this.labelService.getUriLabel(symbolUri, {
                    relative: true
                });
                if (symbol.containerName) {
                    containerLabel = `${symbol.containerName} • ${containerPath}`;
                } else {
                    containerLabel = containerPath;
                }
            }
            let containerScore = undefined;
            let containerMatches = undefined;
            if (!skipContainerQuery && containerQuery && containerQuery.original.length > 0) {
                if (containerLabel) {
                    [containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);
                }
                if (typeof containerScore !== "number") {
                    continue;
                }
                if (typeof symbolScore === "number") {
                    symbolScore += containerScore;
                }
            }
            const deprecated = symbol.tags ? symbol.tags.indexOf(SymbolTag.Deprecated) >= 0 : false;
            symbolPicks.push({
                symbol,
                resource: symbolUri,
                score: symbolScore,
                iconClass: ThemeIcon.asClassName(SymbolKinds.toIcon(symbol.kind)),
                label: symbolLabel,
                ariaLabel: symbolLabel,
                highlights: deprecated ? undefined : {
                    label: symbolMatches,
                    description: containerMatches
                },
                description: containerLabel,
                strikethrough: deprecated,
                buttons: [{
                    iconClass: openSideBySideDirection === "right" ? ThemeIcon.asClassName(Codicon.splitHorizontal) : ThemeIcon.asClassName(Codicon.splitVertical),
                    tooltip: openSideBySideDirection === "right" ? ( localize(13501, "Open to the Side")) : ( localize(13502, "Open to the Bottom"))
                }],
                trigger: (buttonIndex, keyMods) => {
                    this.openSymbol(provider, symbol, token, {
                        keyMods,
                        forceOpenSideBySide: true
                    });
                    return TriggerAction.CLOSE_PICKER;
                },
                accept: async (keyMods, event) => this.openSymbol(provider, symbol, token, {
                    keyMods,
                    preserveFocus: event.inBackground,
                    forcePinned: event.inBackground
                }),
                attach: (keyMods, event) => {
                    if (keyMods.shift) {
                        const widget = this.chatWidgetService.lastFocusedWidget;
                        if (widget) {
                            const entry = {
                                kind: "symbol",
                                id: JSON.stringify({
                                    uri: ( symbolUri.toString()),
                                    range: symbol.location.range
                                }),
                                name: symbol.name,
                                value: symbol.location,
                                symbolKind: symbol.kind
                            };
                            widget.attachmentModel.addContext(entry);
                        }
                        return;
                    }
                    this.openSymbol(provider, symbol, token, {
                        keyMods,
                        preserveFocus: event.inBackground,
                        forcePinned: event.inBackground
                    });
                }
            });
        }
        if (!options?.skipSorting) {
            symbolPicks.sort((symbolA, symbolB) => this.compareSymbols(symbolA, symbolB));
        }
        return symbolPicks;
    }
    async openSymbol(provider, symbol, token, options) {
        let symbolToOpen = symbol;
        if (typeof provider.resolveWorkspaceSymbol === "function") {
            symbolToOpen = (await provider.resolveWorkspaceSymbol(symbol, token)) || symbol;
            if (token.isCancellationRequested) {
                return;
            }
        }
        if (symbolToOpen.location.uri.scheme === Schemas.http || symbolToOpen.location.uri.scheme === Schemas.https) {
            await this.openerService.open(symbolToOpen.location.uri, {
                fromUserGesture: true,
                allowContributedOpeners: true
            });
        }
        else {
            await this.editorService.openEditor({
                resource: symbolToOpen.location.uri,
                options: {
                    preserveFocus: options?.preserveFocus,
                    pinned: options.keyMods.ctrlCmd || options.forcePinned || this.configuration.openEditorPinned,
                    selection: symbolToOpen.location.range ? Range.collapseToStart(symbolToOpen.location.range) : undefined
                }
            }, options.keyMods.alt || (this.configuration.openEditorPinned && options.keyMods.ctrlCmd) || options?.forceOpenSideBySide ? SIDE_GROUP : ACTIVE_GROUP);
        }
    }
    compareSymbols(symbolA, symbolB) {
        if (typeof symbolA.score === "number" && typeof symbolB.score === "number") {
            if (symbolA.score > symbolB.score) {
                return -1;
            }
            if (symbolA.score < symbolB.score) {
                return 1;
            }
        }
        if (symbolA.symbol && symbolB.symbol) {
            const symbolAName = symbolA.symbol.name.toLowerCase();
            const symbolBName = symbolB.symbol.name.toLowerCase();
            const res = symbolAName.localeCompare(symbolBName);
            if (res !== 0) {
                return res;
            }
        }
        if (symbolA.symbol && symbolB.symbol) {
            const symbolAKind = SymbolKinds.toIcon(symbolA.symbol.kind).id;
            const symbolBKind = SymbolKinds.toIcon(symbolB.symbol.kind).id;
            return symbolAKind.localeCompare(symbolBKind);
        }
        return 0;
    }
};
SymbolsQuickAccessProvider = SymbolsQuickAccessProvider_1 = ( __decorate([( __param(0, ILabelService)), ( __param(1, IOpenerService)), ( __param(2, IEditorService)), ( __param(3, IConfigurationService)), ( __param(4, ICodeEditorService)), ( __param(5, IChatWidgetService))], SymbolsQuickAccessProvider));

export { SymbolsQuickAccessProvider };
