
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { append, $ } from '../../../../base/browser/dom.js';
import { CountBadge } from '../../../../base/browser/ui/countBadge/countBadge.js';
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { dirname } from '../../../../base/common/path.js';
import { localize } from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { FileKind } from '../../../../platform/files/common/files.js';
import { ILabelService } from '../../../../platform/label/common/label.service.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.service.js';
import { isEqual } from '../../../../base/common/resources.js';
import { MenuId } from '../../../../platform/actions/common/actions.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { MenuWorkbenchToolBar, HiddenItemStrategy } from '../../../../platform/actions/browser/toolbar.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
import { defaultCountBadgeStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import { SearchContext } from '../common/constants.js';
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.service.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { isSearchTreeFolderMatch, isSearchTreeFileMatch, isSearchTreeMatch, isTextSearchHeading, isPlainTextSearchHeading, isSearchTreeFolderMatchWorkspaceRoot, isSearchTreeFolderMatchNoRoot } from './searchTreeModel/searchTreeCommon.js';
import { isSearchTreeAIFileMatch } from './AISearch/aiSearchModelBase.js';

var TextSearchResultRenderer_1, FolderMatchRenderer_1, FileMatchRenderer_1, MatchRenderer_1;
class SearchDelegate {
    static {
        this.ITEM_HEIGHT = 22;
    }
    getHeight(element) {
        return SearchDelegate.ITEM_HEIGHT;
    }
    getTemplateId(element) {
        if (isSearchTreeFolderMatch(element)) {
            return FolderMatchRenderer.TEMPLATE_ID;
        } else if (isSearchTreeFileMatch(element)) {
            return FileMatchRenderer.TEMPLATE_ID;
        } else if (isSearchTreeMatch(element)) {
            return MatchRenderer.TEMPLATE_ID;
        } else if (isTextSearchHeading(element)) {
            return TextSearchResultRenderer.TEMPLATE_ID;
        }
        console.error("Invalid search tree element", element);
        throw ( new Error("Invalid search tree element"));
    }
}
let TextSearchResultRenderer = class TextSearchResultRenderer extends Disposable {
    static {
        TextSearchResultRenderer_1 = this;
    }
    static {
        this.TEMPLATE_ID = "textResultMatch";
    }
    constructor(labels, contextService, instantiationService, contextKeyService) {
        super();
        this.labels = labels;
        this.contextService = contextService;
        this.instantiationService = instantiationService;
        this.contextKeyService = contextKeyService;
        this.templateId = TextSearchResultRenderer_1.TEMPLATE_ID;
    }
    renderTemplate(container) {
        const disposables = ( new DisposableStore());
        const textSearchResultElement = append(container, $(".textsearchresult"));
        const label = this.labels.create(textSearchResultElement, {
            supportDescriptionHighlights: true,
            supportHighlights: true,
            supportIcons: true
        });
        disposables.add(label);
        const actionBarContainer = append(textSearchResultElement, $(".actionBarContainer"));
        const contextKeyServiceMain = disposables.add(this.contextKeyService.createScoped(container));
        const instantiationService = disposables.add(this.instantiationService.createChild(( new ServiceCollection([IContextKeyService, contextKeyServiceMain]))));
        const actions = disposables.add(
            instantiationService.createInstance(MenuWorkbenchToolBar, actionBarContainer, MenuId.SearchActionMenu, {
                menuOptions: {
                    shouldForwardArgs: true
                },
                highlightToggledItems: true,
                hiddenItemStrategy: HiddenItemStrategy.Ignore,
                toolbarOptions: {
                    primaryGroup: g => /^inline/.test(g)
                }
            })
        );
        return {
            label,
            disposables,
            actions,
            contextKeyService: contextKeyServiceMain
        };
    }
    async renderElement(node, index, templateData) {
        if (isPlainTextSearchHeading(node.element)) {
            templateData.label.setLabel(( localize(12598, "Text Results")));
            SearchContext.AIResultsTitle.bindTo(templateData.contextKeyService).set(false);
            SearchContext.MatchFocusKey.bindTo(templateData.contextKeyService).set(false);
            SearchContext.FileFocusKey.bindTo(templateData.contextKeyService).set(false);
            SearchContext.FolderFocusKey.bindTo(templateData.contextKeyService).set(false);
        } else {
            try {
                await node.element.parent().searchModel.getAITextResultProviderName();
            } catch {}
            const localizedLabel = ( localize(12599, "AI-assisted results"));
            templateData.label.setLabel(`$(${Codicon.searchSparkle.id}) ${localizedLabel}`);
            SearchContext.AIResultsTitle.bindTo(templateData.contextKeyService).set(true);
            SearchContext.MatchFocusKey.bindTo(templateData.contextKeyService).set(false);
            SearchContext.FileFocusKey.bindTo(templateData.contextKeyService).set(false);
            SearchContext.FolderFocusKey.bindTo(templateData.contextKeyService).set(false);
        }
    }
    disposeTemplate(templateData) {
        templateData.disposables.dispose();
    }
    renderCompressedElements(node, index, templateData) {}
};
TextSearchResultRenderer = TextSearchResultRenderer_1 = ( __decorate([( __param(1, IWorkspaceContextService)), ( __param(2, IInstantiationService)), ( __param(3, IContextKeyService))], TextSearchResultRenderer));
let FolderMatchRenderer = class FolderMatchRenderer extends Disposable {
    static {
        FolderMatchRenderer_1 = this;
    }
    static {
        this.TEMPLATE_ID = "folderMatch";
    }
    constructor(
        searchView,
        labels,
        contextService,
        labelService,
        instantiationService,
        contextKeyService
    ) {
        super();
        this.searchView = searchView;
        this.labels = labels;
        this.contextService = contextService;
        this.labelService = labelService;
        this.instantiationService = instantiationService;
        this.contextKeyService = contextKeyService;
        this.templateId = FolderMatchRenderer_1.TEMPLATE_ID;
    }
    renderCompressedElements(node, index, templateData) {
        const compressed = node.element;
        const folder = compressed.elements[compressed.elements.length - 1];
        const label = ( compressed.elements.map(e => e.name()));
        if (folder.resource) {
            const fileKind = (isSearchTreeFolderMatchWorkspaceRoot(folder)) ? FileKind.ROOT_FOLDER : FileKind.FOLDER;
            templateData.label.setResource({
                resource: folder.resource,
                name: label
            }, {
                fileKind,
                separator: this.labelService.getSeparator(folder.resource.scheme)
            });
        } else {
            templateData.label.setLabel(( localize(12600, "Other files")));
        }
        this.renderFolderDetails(folder, templateData);
    }
    renderTemplate(container) {
        const disposables = ( new DisposableStore());
        const folderMatchElement = append(container, $(".foldermatch"));
        const label = this.labels.create(folderMatchElement, {
            supportDescriptionHighlights: true,
            supportHighlights: true
        });
        disposables.add(label);
        const badge = ( new CountBadge(
            append(folderMatchElement, $(".badge")),
            {},
            defaultCountBadgeStyles
        ));
        disposables.add(badge);
        const actionBarContainer = append(folderMatchElement, $(".actionBarContainer"));
        const elementDisposables = ( new DisposableStore());
        disposables.add(elementDisposables);
        const contextKeyServiceMain = disposables.add(this.contextKeyService.createScoped(container));
        SearchContext.AIResultsTitle.bindTo(contextKeyServiceMain).set(false);
        SearchContext.MatchFocusKey.bindTo(contextKeyServiceMain).set(false);
        SearchContext.FileFocusKey.bindTo(contextKeyServiceMain).set(false);
        SearchContext.FolderFocusKey.bindTo(contextKeyServiceMain).set(true);
        const instantiationService = disposables.add(this.instantiationService.createChild(( new ServiceCollection([IContextKeyService, contextKeyServiceMain]))));
        const actions = disposables.add(
            instantiationService.createInstance(MenuWorkbenchToolBar, actionBarContainer, MenuId.SearchActionMenu, {
                menuOptions: {
                    shouldForwardArgs: true
                },
                hiddenItemStrategy: HiddenItemStrategy.Ignore,
                toolbarOptions: {
                    primaryGroup: g => /^inline/.test(g)
                }
            })
        );
        return {
            label,
            badge,
            actions,
            disposables,
            elementDisposables,
            contextKeyService: contextKeyServiceMain
        };
    }
    renderElement(node, index, templateData) {
        const folderMatch = node.element;
        if (folderMatch.resource) {
            const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource);
            if (workspaceFolder && isEqual(workspaceFolder.uri, folderMatch.resource)) {
                templateData.label.setFile(folderMatch.resource, {
                    fileKind: FileKind.ROOT_FOLDER,
                    hidePath: true
                });
            } else {
                templateData.label.setFile(folderMatch.resource, {
                    fileKind: FileKind.FOLDER,
                    hidePath: this.searchView.isTreeLayoutViewVisible
                });
            }
        } else {
            templateData.label.setLabel(( localize(12600, "Other files")));
        }
        SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!folderMatch.hasOnlyReadOnlyMatches());
        templateData.elementDisposables.add(folderMatch.onChange(() => {
            SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!folderMatch.hasOnlyReadOnlyMatches());
        }));
        this.renderFolderDetails(folderMatch, templateData);
    }
    disposeElement(element, index, templateData) {
        templateData.elementDisposables.clear();
    }
    disposeCompressedElements(node, index, templateData) {
        templateData.elementDisposables.clear();
    }
    disposeTemplate(templateData) {
        templateData.disposables.dispose();
    }
    renderFolderDetails(folder, templateData) {
        const count = folder.recursiveMatchCount();
        templateData.badge.setCount(count);
        templateData.badge.setTitleFormat(count > 1 ? ( localize(12601, "{0} files found", count)) : ( localize(12602, "{0} file found", count)));
        templateData.actions.context = {
            viewer: this.searchView.getControl(),
            element: folder
        };
    }
};
FolderMatchRenderer = FolderMatchRenderer_1 = ( __decorate([( __param(2, IWorkspaceContextService)), ( __param(3, ILabelService)), ( __param(4, IInstantiationService)), ( __param(5, IContextKeyService))], FolderMatchRenderer));
let FileMatchRenderer = class FileMatchRenderer extends Disposable {
    static {
        FileMatchRenderer_1 = this;
    }
    static {
        this.TEMPLATE_ID = "fileMatch";
    }
    constructor(
        searchView,
        labels,
        contextService,
        configurationService,
        instantiationService,
        contextKeyService
    ) {
        super();
        this.searchView = searchView;
        this.labels = labels;
        this.contextService = contextService;
        this.configurationService = configurationService;
        this.instantiationService = instantiationService;
        this.contextKeyService = contextKeyService;
        this.templateId = FileMatchRenderer_1.TEMPLATE_ID;
    }
    renderCompressedElements(node, index, templateData) {
        throw ( new Error("Should never happen since node is incompressible."));
    }
    renderTemplate(container) {
        const disposables = ( new DisposableStore());
        const elementDisposables = ( new DisposableStore());
        disposables.add(elementDisposables);
        const fileMatchElement = append(container, $(".filematch"));
        const label = this.labels.create(fileMatchElement);
        disposables.add(label);
        const badge = ( new CountBadge(append(fileMatchElement, $(".badge")), {}, defaultCountBadgeStyles));
        disposables.add(badge);
        const actionBarContainer = append(fileMatchElement, $(".actionBarContainer"));
        const contextKeyServiceMain = disposables.add(this.contextKeyService.createScoped(container));
        SearchContext.AIResultsTitle.bindTo(contextKeyServiceMain).set(false);
        SearchContext.MatchFocusKey.bindTo(contextKeyServiceMain).set(false);
        SearchContext.FileFocusKey.bindTo(contextKeyServiceMain).set(true);
        SearchContext.FolderFocusKey.bindTo(contextKeyServiceMain).set(false);
        const instantiationService = disposables.add(this.instantiationService.createChild(( new ServiceCollection([IContextKeyService, contextKeyServiceMain]))));
        const actions = disposables.add(
            instantiationService.createInstance(MenuWorkbenchToolBar, actionBarContainer, MenuId.SearchActionMenu, {
                menuOptions: {
                    shouldForwardArgs: true
                },
                hiddenItemStrategy: HiddenItemStrategy.Ignore,
                toolbarOptions: {
                    primaryGroup: g => /^inline/.test(g)
                }
            })
        );
        return {
            el: fileMatchElement,
            label,
            badge,
            actions,
            disposables,
            elementDisposables,
            contextKeyService: contextKeyServiceMain
        };
    }
    renderElement(node, index, templateData) {
        const fileMatch = node.element;
        templateData.el.setAttribute("data-resource", ( fileMatch.resource.toString()));
        const decorationConfig = this.configurationService.getValue("search").decorations;
        templateData.label.setFile(fileMatch.resource, {
            range: isSearchTreeAIFileMatch(fileMatch) ? fileMatch.getFullRange() : undefined,
            hidePath: this.searchView.isTreeLayoutViewVisible && !(isSearchTreeFolderMatchNoRoot(fileMatch.parent())),
            hideIcon: false,
            fileDecorations: {
                colors: decorationConfig.colors,
                badges: decorationConfig.badges
            }
        });
        const count = fileMatch.count();
        templateData.badge.setCount(count);
        templateData.badge.setTitleFormat(count > 1 ? ( localize(12603, "{0} matches found", count)) : ( localize(12604, "{0} match found", count)));
        templateData.actions.context = {
            viewer: this.searchView.getControl(),
            element: fileMatch
        };
        SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!fileMatch.hasOnlyReadOnlyMatches());
        templateData.elementDisposables.add(fileMatch.onChange(() => {
            SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!fileMatch.hasOnlyReadOnlyMatches());
        }));
        const twistieContainer = templateData.el.parentElement?.parentElement?.querySelector(".monaco-tl-twistie");
        twistieContainer?.classList.add("force-twistie");
    }
    disposeElement(element, index, templateData) {
        templateData.elementDisposables.clear();
    }
    disposeTemplate(templateData) {
        templateData.disposables.dispose();
    }
};
FileMatchRenderer = FileMatchRenderer_1 = ( __decorate([( __param(2, IWorkspaceContextService)), ( __param(3, IConfigurationService)), ( __param(4, IInstantiationService)), ( __param(5, IContextKeyService))], FileMatchRenderer));
let MatchRenderer = class MatchRenderer extends Disposable {
    static {
        MatchRenderer_1 = this;
    }
    static {
        this.TEMPLATE_ID = "match";
    }
    constructor(
        searchView,
        contextService,
        configurationService,
        instantiationService,
        contextKeyService,
        hoverService
    ) {
        super();
        this.searchView = searchView;
        this.contextService = contextService;
        this.configurationService = configurationService;
        this.instantiationService = instantiationService;
        this.contextKeyService = contextKeyService;
        this.hoverService = hoverService;
        this.templateId = MatchRenderer_1.TEMPLATE_ID;
    }
    renderCompressedElements(node, index, templateData) {
        throw ( new Error("Should never happen since node is incompressible."));
    }
    renderTemplate(container) {
        container.classList.add("linematch");
        const lineNumber = append(container, $("span.matchLineNum"));
        const parent = append(container, $("a.plain.match"));
        const before = append(parent, $("span"));
        const match = append(parent, $("span.findInFileMatch"));
        const replace = append(parent, $("span.replaceMatch"));
        const after = append(parent, $("span"));
        const actionBarContainer = append(container, $("span.actionBarContainer"));
        const disposables = ( new DisposableStore());
        const contextKeyServiceMain = disposables.add(this.contextKeyService.createScoped(container));
        SearchContext.AIResultsTitle.bindTo(contextKeyServiceMain).set(false);
        SearchContext.MatchFocusKey.bindTo(contextKeyServiceMain).set(true);
        SearchContext.FileFocusKey.bindTo(contextKeyServiceMain).set(false);
        SearchContext.FolderFocusKey.bindTo(contextKeyServiceMain).set(false);
        const instantiationService = disposables.add(this.instantiationService.createChild(( new ServiceCollection([IContextKeyService, contextKeyServiceMain]))));
        const actions = disposables.add(
            instantiationService.createInstance(MenuWorkbenchToolBar, actionBarContainer, MenuId.SearchActionMenu, {
                menuOptions: {
                    shouldForwardArgs: true
                },
                hiddenItemStrategy: HiddenItemStrategy.Ignore,
                toolbarOptions: {
                    primaryGroup: g => /^inline/.test(g)
                }
            })
        );
        return {
            parent,
            before,
            match,
            replace,
            after,
            lineNumber,
            actions,
            disposables,
            contextKeyService: contextKeyServiceMain
        };
    }
    renderElement(node, index, templateData) {
        const match = node.element;
        const preview = match.preview();
        const replace = this.searchView.model.isReplaceActive() && !!this.searchView.model.replaceString && !match.isReadonly;
        templateData.before.textContent = preview.before;
        templateData.match.textContent = preview.inside;
        templateData.match.classList.toggle("replace", replace);
        templateData.replace.textContent = replace ? match.replaceString : "";
        templateData.after.textContent = preview.after;
        const title = (preview.fullBefore + (replace ? match.replaceString : preview.inside) + preview.after).trim().substr(0, 999);
        templateData.disposables.add(
            this.hoverService.setupManagedHover(getDefaultHoverDelegate("mouse"), templateData.parent, title)
        );
        SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!match.isReadonly);
        const numLines = match.range().endLineNumber - match.range().startLineNumber;
        const extraLinesStr = numLines > 0 ? `+${numLines}` : "";
        const showLineNumbers = this.configurationService.getValue("search").showLineNumbers;
        const lineNumberStr = showLineNumbers ? `${match.range().startLineNumber}:` : "";
        templateData.lineNumber.classList.toggle("show", (numLines > 0) || showLineNumbers);
        templateData.lineNumber.textContent = lineNumberStr + extraLinesStr;
        templateData.disposables.add(this.hoverService.setupManagedHover(
            getDefaultHoverDelegate("mouse"),
            templateData.lineNumber,
            this.getMatchTitle(match, showLineNumbers)
        ));
        templateData.actions.context = {
            viewer: this.searchView.getControl(),
            element: match
        };
    }
    disposeTemplate(templateData) {
        templateData.disposables.dispose();
    }
    getMatchTitle(match, showLineNumbers) {
        const startLine = match.range().startLineNumber;
        const numLines = match.range().endLineNumber - match.range().startLineNumber;
        const lineNumStr = showLineNumbers ? ( localize(12605, "From line {0}", startLine, numLines)) + " " : "";
        const numLinesStr = numLines > 0 ? "+ " + ( localize(12606, "{0} more lines", numLines)) : "";
        return lineNumStr + numLinesStr;
    }
};
MatchRenderer = MatchRenderer_1 = ( __decorate([( __param(1, IWorkspaceContextService)), ( __param(2, IConfigurationService)), ( __param(3, IInstantiationService)), ( __param(4, IContextKeyService)), ( __param(5, IHoverService))], MatchRenderer));
let SearchAccessibilityProvider = class SearchAccessibilityProvider {
    constructor(searchView, labelService) {
        this.searchView = searchView;
        this.labelService = labelService;
    }
    getWidgetAriaLabel() {
        return localize(12607, "Search");
    }
    getAriaLabel(element) {
        if (isSearchTreeFolderMatch(element)) {
            const count = element.allDownstreamFileMatches().reduce((total, current) => total + current.count(), 0);
            return element.resource ? ( localize(
                12608,
                "{0} matches in folder root {1}, Search result",
                count,
                element.name()
            )) : ( localize(12609, "{0} matches outside of the workspace, Search result", count));
        }
        if (isSearchTreeFileMatch(element)) {
            const path = this.labelService.getUriLabel(element.resource, {
                relative: true
            }) || element.resource.fsPath;
            return localize(
                12610,
                "{0} matches in file {1} of folder {2}, Search result",
                element.count(),
                element.name(),
                dirname(path)
            );
        }
        if (isSearchTreeMatch(element)) {
            const match = element;
            const searchModel = this.searchView.model;
            const replace = searchModel.isReplaceActive() && !!searchModel.replaceString;
            const matchString = match.getMatchString();
            const range = match.range();
            const matchText = match.text().substr(0, range.endColumn + 150);
            if (replace) {
                return localize(
                    12611,
                    "'{0}' at column {1} replace {2} with {3}",
                    matchText,
                    range.startColumn,
                    matchString,
                    match.replaceString
                );
            }
            return localize(
                12612,
                "'{0}' at column {1} found {2}",
                matchText,
                range.startColumn,
                matchString
            );
        }
        return null;
    }
};
SearchAccessibilityProvider = ( __decorate([( __param(1, ILabelService))], SearchAccessibilityProvider));

export { FileMatchRenderer, FolderMatchRenderer, MatchRenderer, SearchAccessibilityProvider, SearchDelegate, TextSearchResultRenderer };
