
import { localize2 } from '../../../../nls.js';
import { WorkbenchListFocusContextKey } from '../../../../platform/list/browser/listService.js';
import { IViewsService } from '../../../services/views/common/viewsService.service.js';
import { searchStopIcon, searchRefreshIcon, searchCollapseAllIcon, searchExpandAllIcon, searchClearIcon, searchShowAsList, searchShowAsTree } from './searchIcons.js';
import { SearchCommandIds, SearchContext } from '../common/constants.js';
import { ISearchHistoryService } from '../common/searchHistoryService.service.js';
import { VIEW_ID } from '../../../services/search/common/search.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 { KeyCode, KeyMod as KeyMod$1 } from '../../../../base/common/keyCodes.js';
import { SearchStateKey, SearchUIState } from '../common/search.js';
import { category, getSearchView } from './searchActionsBase.js';
import { isSearchResult, isTextSearchHeading, isSearchTreeFolderMatchWorkspaceRoot, isSearchTreeMatch, isSearchTreeFolderMatch, isSearchTreeFolderMatchNoRoot, isSearchTreeFileMatch } from './searchTreeModel/searchTreeCommon.js';

registerAction2(class ClearSearchHistoryCommandAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ClearSearchHistoryCommandId,
            title: ( localize2(12561, "Clear Search History")),
            category,
            f1: true
        });
    }
    async run(accessor) {
        clearHistoryCommand(accessor);
    }
});
registerAction2(class CancelSearchAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.CancelSearchActionId,
            title: ( localize2(12562, "Cancel Search")),
            icon: searchStopIcon,
            category,
            f1: true,
            precondition: ( ( SearchStateKey.isEqualTo(SearchUIState.Idle)).negate()),
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                when: ( ContextKeyExpr.and(SearchContext.SearchViewVisibleKey, WorkbenchListFocusContextKey)),
                primary: KeyCode.Escape
            },
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 0,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), ( SearchStateKey.isEqualTo(SearchUIState.SlowSearch))))
            }]
        });
    }
    run(accessor) {
        return cancelSearch(accessor);
    }
});
registerAction2(class RefreshAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.RefreshSearchResultsActionId,
            title: ( localize2(12563, "Refresh")),
            icon: searchRefreshIcon,
            precondition: SearchContext.ViewHasSearchPatternKey,
            category,
            f1: true,
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 0,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), ( ( SearchStateKey.isEqualTo(SearchUIState.SlowSearch)).negate())))
            }]
        });
    }
    run(accessor, ...args) {
        return refreshSearch(accessor);
    }
});
registerAction2(class CollapseDeepestExpandedLevelAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.CollapseSearchResultsActionId,
            title: ( localize2(12564, "Collapse All")),
            category,
            icon: searchCollapseAllIcon,
            f1: true,
            precondition: ( ContextKeyExpr.and(
                SearchContext.HasSearchResults,
                SearchContext.ViewHasSomeCollapsibleKey
            )),
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 4,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), ( ContextKeyExpr.or(( SearchContext.HasSearchResults.negate()), SearchContext.ViewHasSomeCollapsibleKey))))
            }]
        });
    }
    run(accessor, ...args) {
        return collapseDeepestExpandedLevel(accessor);
    }
});
registerAction2(class ExpandAllAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ExpandSearchResultsActionId,
            title: ( localize2(12565, "Expand All")),
            category,
            icon: searchExpandAllIcon,
            f1: true,
            precondition: ( ContextKeyExpr.and(SearchContext.HasSearchResults, ( SearchContext.ViewHasSomeCollapsibleKey.toNegated()))),
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 4,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), SearchContext.HasSearchResults, ( SearchContext.ViewHasSomeCollapsibleKey.toNegated())))
            }]
        });
    }
    async run(accessor, ...args) {
        return expandAll(accessor);
    }
});
registerAction2(class ClearSearchResultsAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ClearSearchResultsActionId,
            title: ( localize2(12566, "Clear Search Results")),
            category,
            icon: searchClearIcon,
            f1: true,
            precondition: ( ContextKeyExpr.or(
                SearchContext.HasSearchResults,
                SearchContext.ViewHasSearchPatternKey,
                SearchContext.ViewHasReplacePatternKey,
                SearchContext.ViewHasFilePatternKey
            )),
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 1,
                when: ( ContextKeyExpr.equals("view", VIEW_ID))
            }]
        });
    }
    run(accessor, ...args) {
        return clearSearchResults(accessor);
    }
});
registerAction2(class ViewAsTreeAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ViewAsTreeActionId,
            title: ( localize2(12567, "View as Tree")),
            category,
            icon: searchShowAsList,
            f1: true,
            precondition: ( ContextKeyExpr.and(SearchContext.HasSearchResults, ( SearchContext.InTreeViewKey.toNegated()))),
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 2,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), ( SearchContext.InTreeViewKey.toNegated())))
            }]
        });
    }
    async run(accessor, ...args) {
        const searchView = getSearchView(accessor.get(IViewsService));
        if (searchView) {
            await searchView.setTreeView(true);
        }
    }
});
registerAction2(class ViewAsListAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.ViewAsListActionId,
            title: ( localize2(12568, "View as List")),
            category,
            icon: searchShowAsTree,
            f1: true,
            precondition: ( ContextKeyExpr.and(
                SearchContext.HasSearchResults,
                SearchContext.InTreeViewKey
            )),
            menu: [{
                id: MenuId.ViewTitle,
                group: "navigation",
                order: 2,
                when: ( ContextKeyExpr.and(( ContextKeyExpr.equals("view", VIEW_ID)), SearchContext.InTreeViewKey))
            }]
        });
    }
    async run(accessor, ...args) {
        const searchView = getSearchView(accessor.get(IViewsService));
        if (searchView) {
            await searchView.setTreeView(false);
        }
    }
});
registerAction2(class SearchWithAIAction extends Action2 {
    constructor() {
        super({
            id: SearchCommandIds.SearchWithAIActionId,
            title: ( localize2(12569, "Search with AI")),
            category,
            f1: true,
            precondition: SearchContext.hasAIResultProvider,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                when: ( ContextKeyExpr.and(
                    SearchContext.hasAIResultProvider,
                    SearchContext.SearchViewFocusedKey
                )),
                primary: KeyMod$1.CtrlCmd | KeyCode.KeyI
            }
        });
    }
    async run(accessor, ...args) {
        const searchView = getSearchView(accessor.get(IViewsService));
        if (searchView) {
            searchView.requestAIResults();
        }
    }
});
const clearHistoryCommand = accessor => {
    const searchHistoryService = accessor.get(ISearchHistoryService);
    searchHistoryService.clearHistory();
};
async function expandAll(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    if (searchView) {
        const viewer = searchView.getControl();
        await forcedExpandRecursively(viewer, undefined);
    }
}
async function forcedExpandRecursively(viewer, element) {
    if (element) {
        if (!viewer.hasNode(element)) {
            return;
        }
        await viewer.expand(element, true);
    }
    const children = viewer.getNode(element)?.children;
    if (children) {
        for (const child of children) {
            if (isSearchResult(child.element)) {
                throw Error("SearchResult should not be a child of a RenderableMatch");
            }
            forcedExpandRecursively(viewer, child.element);
        }
    }
}
function clearSearchResults(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    searchView?.clearSearchResults();
}
function cancelSearch(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    searchView?.cancelSearch();
}
function refreshSearch(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    searchView?.triggerQueryChange({
        preserveFocus: false,
        shouldUpdateAISearch: !searchView.model.searchResult.aiTextSearchResult.hidden
    });
}
function collapseDeepestExpandedLevel(accessor) {
    const viewsService = accessor.get(IViewsService);
    const searchView = getSearchView(viewsService);
    if (searchView) {
        const viewer = searchView.getControl();
        const navigator = viewer.navigate();
        let node = navigator.first();
        let canCollapseFileMatchLevel = false;
        let canCollapseFirstLevel = false;
        do {
            node = navigator.next();
        } while (isTextSearchHeading(node));
        if (isSearchTreeFolderMatchWorkspaceRoot(node) || searchView.isTreeLayoutViewVisible) {
            while (node = navigator.next()) {
                if (isTextSearchHeading(node)) {
                    continue;
                }
                if (isSearchTreeMatch(node)) {
                    canCollapseFileMatchLevel = true;
                    break;
                }
                if (searchView.isTreeLayoutViewVisible && !canCollapseFirstLevel) {
                    let nodeToTest = node;
                    if (isSearchTreeFolderMatch(node)) {
                        const compressionStartNode = viewer.getCompressedTreeNode(node)?.elements[0].element;
                        nodeToTest = compressionStartNode && !(isSearchTreeMatch(compressionStartNode)) && !isTextSearchHeading(compressionStartNode) && !(isSearchResult(compressionStartNode)) ? compressionStartNode : node;
                    }
                    const immediateParent = nodeToTest.parent();
                    if (!(isTextSearchHeading(immediateParent) || isSearchTreeFolderMatchWorkspaceRoot(immediateParent) || isSearchTreeFolderMatchNoRoot(immediateParent) || isSearchResult(immediateParent))) {
                        canCollapseFirstLevel = true;
                    }
                }
            }
        }
        if (canCollapseFileMatchLevel) {
            node = navigator.first();
            do {
                if (isSearchTreeFileMatch(node)) {
                    viewer.collapse(node);
                }
            } while (node = navigator.next());
        } else if (canCollapseFirstLevel) {
            node = navigator.first();
            if (node) {
                do {
                    let nodeToTest = node;
                    if (isSearchTreeFolderMatch(node)) {
                        const compressionStartNode = viewer.getCompressedTreeNode(node)?.elements[0].element;
                        nodeToTest = (compressionStartNode && !(isSearchTreeMatch(compressionStartNode)) && !(isSearchResult(compressionStartNode)) ? compressionStartNode : node);
                    }
                    const immediateParent = nodeToTest.parent();
                    if (isSearchTreeFolderMatchWorkspaceRoot(immediateParent) || isSearchTreeFolderMatchNoRoot(immediateParent)) {
                        if (viewer.hasNode(node)) {
                            viewer.collapse(node, true);
                        } else {
                            viewer.collapseAll();
                        }
                    }
                } while (node = navigator.next());
            }
        } else if (isTextSearchHeading(navigator.first())) {
            node = navigator.first();
            do {
                if (!node) {
                    break;
                }
                if (isTextSearchHeading(viewer.getParentElement(node))) {
                    viewer.collapse(node);
                }
            } while (node = navigator.next());
        } else {
            viewer.collapseAll();
        }
        const firstFocusParent = viewer.getFocus()[0]?.parent();
        if (firstFocusParent && (isSearchTreeFolderMatch(firstFocusParent) || isSearchTreeFileMatch(firstFocusParent)) && viewer.hasNode(firstFocusParent) && viewer.isCollapsed(firstFocusParent)) {
            viewer.domFocus();
            viewer.focusFirst();
            viewer.setSelection(viewer.getFocus());
        }
    }
}

export { forcedExpandRecursively };
