import { dirname } from '../../../../base/common/resources.js';
import { localize2WithPath, localizeWithPath } from '../../../../nls.js';
import { ICommandService } from '../../../../platform/commands/common/commands.service.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { IListService } from '../../../../platform/list/browser/listService.service.js';
import { ViewContainerLocation } from '../../../common/views.js';
import { IViewsService } from '../../../services/views/common/viewsService.service.js';
import { SearchCommandIds, SearchContext } from '../common/constants.js';
import { OpenEditorCommandId } from '../../searchEditor/browser/constants.js';
import { FileMatch, Match } from './searchModel.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { registerAction2, Action2, MenuId } from '../../../../platform/actions/common/actions.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { KeyMod as KeyMod$1, KeyCode } from '../../../../base/common/keyCodes.js';
import { resolveResourcesForSearchIncludes } from '../../../services/search/common/queryBuilder.js';
import { getMultiSelectedResources } from '../../files/browser/files.js';
import { IExplorerService } from '../../files/browser/files.service.js';
import { IFileService } from '../../../../platform/files/common/files.service.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.service.js';
import { VIEWLET_ID, FilesExplorerFocusCondition, ExplorerFolderContext, ExplorerRootContext } from '../../files/common/files.js';
import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.service.js';
import { onUnexpectedError } from '../../../../base/common/errors.js';
import { category, getSearchView, openSearchView, getElementsToOperateOn } from './searchActionsBase.js';
import { IConfigurationResolverService } from '../../../services/configurationResolver/common/configurationResolver.service.js';
import { IHistoryService } from '../../../services/history/common/history.service.js';
import { Schemas } from '../../../../base/common/network.js';
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.service.js';
const _moduleId = "vs/workbench/contrib/search/browser/searchActionsFind";
registerAction2(class RestrictSearchToFolderAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.RestrictSearchToFolderId,
            title: ( localize2WithPath(_moduleId, 0, "Restrict Search to Folder")),
            category,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                when: ( (ContextKeyExpr.and(SearchContext.SearchViewVisibleKey, SearchContext.ResourceFolderFocusKey))),
                primary: KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyF,
            },
            menu: [
                {
                    id: MenuId.SearchContext,
                    group: 'search',
                    order: 3,
                    when: ( (ContextKeyExpr.and(SearchContext.ResourceFolderFocusKey)))
                }
            ]
        });
    }
    async run(accessor, folderMatch) {
        await searchWithFolderCommand(accessor, false, true, undefined, folderMatch);
    }
});
registerAction2(class ExpandSelectedTreeCommandAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ExpandRecursivelyCommandId,
            title: ( localizeWithPath(_moduleId, 1, "Expand Recursively")),
            category,
            menu: [{
                    id: MenuId.SearchContext,
                    when: ( (ContextKeyExpr.and(SearchContext.FolderFocusKey, SearchContext.HasSearchResults))),
                    group: 'search',
                    order: 4
                }]
        });
    }
    run(accessor) {
        expandSelectSubtree(accessor);
    }
});
registerAction2(class ExcludeFolderFromSearchAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ExcludeFolderFromSearchId,
            title: ( localize2WithPath(_moduleId, 2, "Exclude Folder from Search")),
            category,
            menu: [
                {
                    id: MenuId.SearchContext,
                    group: 'search',
                    order: 4,
                    when: ( (ContextKeyExpr.and(SearchContext.ResourceFolderFocusKey)))
                }
            ]
        });
    }
    async run(accessor, folderMatch) {
        await searchWithFolderCommand(accessor, false, false, undefined, folderMatch);
    }
});
registerAction2(class RevealInSideBarForSearchResultsAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.RevealInSideBarForSearchResults,
            title: ( localize2WithPath(_moduleId, 3, "Reveal in Explorer View")),
            category,
            menu: [{
                    id: MenuId.SearchContext,
                    when: ( (ContextKeyExpr.and(SearchContext.FileFocusKey, SearchContext.HasSearchResults))),
                    group: 'search_3',
                    order: 1
                }]
        });
    }
    async run(accessor, args) {
        const paneCompositeService = accessor.get(IPaneCompositePartService);
        const explorerService = accessor.get(IExplorerService);
        const contextService = accessor.get(IWorkspaceContextService);
        const searchView = getSearchView(accessor.get(IViewsService));
        if (!searchView) {
            return;
        }
        let fileMatch;
        if (!(args instanceof FileMatch)) {
            args = searchView.getControl().getFocus()[0];
        }
        if (args instanceof FileMatch) {
            fileMatch = args;
        }
        else {
            return;
        }
        paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, false).then((viewlet) => {
            if (!viewlet) {
                return;
            }
            const explorerViewContainer = viewlet.getViewPaneContainer();
            const uri = fileMatch.resource;
            if (uri && contextService.isInsideWorkspace(uri)) {
                const explorerView = explorerViewContainer.getExplorerView();
                explorerView.setExpanded(true);
                explorerService.select(uri, true).then(() => explorerView.focus(), onUnexpectedError);
            }
        });
    }
});
registerAction2(class FindInFilesAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.FindInFilesActionId,
            title: {
                ...( localize2WithPath(_moduleId, 4, "Find in Files")),
                mnemonicTitle: ( localizeWithPath(_moduleId, 5, "Find &&in Files")),
            },
            metadata: {
                description: ( localizeWithPath(_moduleId, 6, "Open a workspace search")),
                args: [
                    {
                        name: ( localizeWithPath(_moduleId, 7, "A set of options for the search")),
                        schema: {
                            type: 'object',
                            properties: {
                                query: { 'type': 'string' },
                                replace: { 'type': 'string' },
                                preserveCase: { 'type': 'boolean' },
                                triggerSearch: { 'type': 'boolean' },
                                filesToInclude: { 'type': 'string' },
                                filesToExclude: { 'type': 'string' },
                                isRegex: { 'type': 'boolean' },
                                isCaseSensitive: { 'type': 'boolean' },
                                matchWholeWord: { 'type': 'boolean' },
                                useExcludeSettingsAndIgnoreFiles: { 'type': 'boolean' },
                                onlyOpenEditors: { 'type': 'boolean' },
                                showIncludesExcludes: { 'type': 'boolean' }
                            }
                        }
                    },
                ]
            },
            category,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyCode.KeyF,
            },
            menu: [{
                    id: MenuId.MenubarEditMenu,
                    group: '4_find_global',
                    order: 1,
                }],
            f1: true
        });
    }
    async run(accessor, args = {}) {
        findInFilesCommand(accessor, args);
    }
});
registerAction2(class FindInFolderAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.FindInFolderId,
            title: ( localize2WithPath(_moduleId, 8, "Find in Folder...")),
            category,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                when: ( (ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerFolderContext))),
                primary: KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyF,
            },
            menu: [
                {
                    id: MenuId.ExplorerContext,
                    group: '4_search',
                    order: 10,
                    when: ( (ContextKeyExpr.and(ExplorerFolderContext)))
                }
            ]
        });
    }
    async run(accessor, resource) {
        await searchWithFolderCommand(accessor, true, true, resource);
    }
});
registerAction2(class FindInWorkspaceAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.FindInWorkspaceId,
            title: ( localize2WithPath(_moduleId, 9, "Find in Workspace...")),
            category,
            menu: [
                {
                    id: MenuId.ExplorerContext,
                    group: '4_search',
                    order: 10,
                    when: ( (ContextKeyExpr.and(ExplorerRootContext,  (ExplorerFolderContext.toNegated()))))
                }
            ]
        });
    }
    async run(accessor) {
        const searchConfig = accessor.get(IConfigurationService).getValue().search;
        const mode = searchConfig.mode;
        if (mode === 'view') {
            const searchView = await openSearchView(accessor.get(IViewsService), true);
            searchView?.searchInFolders();
        }
        else {
            return accessor.get(ICommandService).executeCommand(OpenEditorCommandId, {
                location: mode === 'newEditor' ? 'new' : 'reuse',
                filesToInclude: '',
            });
        }
    }
});
function expandSelectSubtree(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    if (searchView) {
        const viewer = searchView.getControl();
        const selected = viewer.getFocus()[0];
        viewer.expand(selected, true);
    }
}
async function searchWithFolderCommand(accessor, isFromExplorer, isIncludes, resource, folderMatch) {
    const listService = accessor.get(IListService);
    const fileService = accessor.get(IFileService);
    const viewsService = accessor.get(IViewsService);
    const contextService = accessor.get(IWorkspaceContextService);
    const commandService = accessor.get(ICommandService);
    const searchConfig = accessor.get(IConfigurationService).getValue().search;
    const mode = searchConfig.mode;
    let resources;
    if (isFromExplorer) {
        resources = getMultiSelectedResources(resource, listService, accessor.get(IEditorService), accessor.get(IEditorGroupsService), accessor.get(IExplorerService));
    }
    else {
        const searchView = getSearchView(accessor.get(IViewsService));
        if (!searchView) {
            return;
        }
        resources = getMultiSelectedSearchResources(searchView.getControl(), folderMatch, searchConfig);
    }
    const resolvedResources = fileService.resolveAll(( (resources.map(resource => ({ resource }))))).then(results => {
        const folders = [];
        results.forEach(result => {
            if (result.success && result.stat) {
                folders.push(result.stat.isDirectory ? result.stat.resource : dirname(result.stat.resource));
            }
        });
        return resolveResourcesForSearchIncludes(folders, contextService);
    });
    if (mode === 'view') {
        const searchView = await openSearchView(viewsService, true);
        if (resources && resources.length && searchView) {
            if (isIncludes) {
                searchView.searchInFolders(await resolvedResources);
            }
            else {
                searchView.searchOutsideOfFolders(await resolvedResources);
            }
        }
        return undefined;
    }
    else {
        if (isIncludes) {
            return commandService.executeCommand(OpenEditorCommandId, {
                filesToInclude: (await resolvedResources).join(', '),
                showIncludesExcludes: true,
                location: mode === 'newEditor' ? 'new' : 'reuse',
            });
        }
        else {
            return commandService.executeCommand(OpenEditorCommandId, {
                filesToExclude: (await resolvedResources).join(', '),
                showIncludesExcludes: true,
                location: mode === 'newEditor' ? 'new' : 'reuse',
            });
        }
    }
}
function getMultiSelectedSearchResources(viewer, currElement, sortConfig) {
    return ( (getElementsToOperateOn(viewer, currElement, sortConfig)
        .map(
        (renderableMatch) => ((renderableMatch instanceof Match) ? null : renderableMatch.resource)
    )))
        .filter((renderableMatch) => (renderableMatch !== null));
}
async function findInFilesCommand(accessor, _args = {}) {
    const searchConfig = accessor.get(IConfigurationService).getValue().search;
    const viewsService = accessor.get(IViewsService);
    const commandService = accessor.get(ICommandService);
    const args = {};
    if (( (Object.keys(_args))).length !== 0) {
        const configurationResolverService = accessor.get(IConfigurationResolverService);
        const historyService = accessor.get(IHistoryService);
        const workspaceContextService = accessor.get(IWorkspaceContextService);
        const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot();
        const filteredActiveWorkspaceRootUri = activeWorkspaceRootUri?.scheme === Schemas.file || activeWorkspaceRootUri?.scheme === Schemas.vscodeRemote ? activeWorkspaceRootUri : undefined;
        const lastActiveWorkspaceRoot = filteredActiveWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(filteredActiveWorkspaceRootUri) ?? undefined : undefined;
        for (const entry of Object.entries(_args)) {
            const name = entry[0];
            const value = entry[1];
            if (value !== undefined) {
                args[name] = (typeof value === 'string') ? await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, value) : value;
            }
        }
    }
    const mode = searchConfig.mode;
    if (mode === 'view') {
        openSearchView(viewsService, false).then(openedView => {
            if (openedView) {
                const searchAndReplaceWidget = openedView.searchAndReplaceWidget;
                searchAndReplaceWidget.toggleReplace(typeof args.replace === 'string');
                let updatedText = false;
                if (typeof args.query !== 'string') {
                    updatedText = openedView.updateTextFromFindWidgetOrSelection({ allowUnselectedWord: typeof args.replace !== 'string' });
                }
                openedView.setSearchParameters(args);
                if (typeof args.showIncludesExcludes === 'boolean') {
                    openedView.toggleQueryDetails(false, args.showIncludesExcludes);
                }
                openedView.searchAndReplaceWidget.focus(undefined, updatedText, updatedText);
            }
        });
    }
    else {
        const convertArgs = (args) => ({
            location: mode === 'newEditor' ? 'new' : 'reuse',
            query: args.query,
            filesToInclude: args.filesToInclude,
            filesToExclude: args.filesToExclude,
            matchWholeWord: args.matchWholeWord,
            isCaseSensitive: args.isCaseSensitive,
            isRegexp: args.isRegex,
            useExcludeSettingsAndIgnoreFiles: args.useExcludeSettingsAndIgnoreFiles,
            onlyOpenEditors: args.onlyOpenEditors,
            showIncludesExcludes: !!(args.filesToExclude || args.filesToExclude || !args.useExcludeSettingsAndIgnoreFiles),
        });
        commandService.executeCommand(OpenEditorCommandId, convertArgs(args));
    }
}
export { findInFilesCommand };
