
import { localize } from '../../../../nls.js';
import { EditorResourceAccessor, SideBySideEditor } from '../../../common/editor.js';
import { isWorkspaceToOpen } from '../../../../platform/window/common/window.js';
import { IHostService } from '../../../services/host/browser/host.service.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { UNTITLED_WORKSPACE_NAME } from '../../../../platform/workspace/common/workspace.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.service.js';
import { ExplorerFocusCondition, FilesExplorerFocusCondition, ExplorerFolderContext, TextFileContentProvider, VIEW_ID, VIEWLET_ID, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext } from '../common/files.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.service.js';
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
import { ICommandService } from '../../../../platform/commands/common/commands.service.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { IFileService } from '../../../../platform/files/common/files.service.js';
import { KeybindingsRegistry, KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { KeyMod as KeyMod$1, KeyCode, KeyChord } from '../../../../base/common/keyCodes.js';
import { isWindows, isWeb } from '../../../../base/common/platform.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.service.js';
import { getMultiSelectedResources, getResourceForCommand } from './files.js';
import { IExplorerService } from './files.service.js';
import { IWorkspaceEditingService } from '../../../services/workspaces/common/workspaceEditing.service.js';
import { Schemas } from '../../../../base/common/network.js';
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
import { SIDE_GROUP } from '../../../services/editor/common/editorService.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.service.js';
import { ILabelService } from '../../../../platform/label/common/label.service.js';
import { joinPath, basename } from '../../../../base/common/resources.js';
import { dispose } from '../../../../base/common/lifecycle.js';
import { IEnvironmentService } from '../../../../platform/environment/common/environment.service.js';
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.service.js';
import { EditorOpenSource, EditorResolution } from '../../../../platform/editor/common/editor.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.service.js';
import { ViewContainerLocation } from '../../../common/views.js';
import { IViewsService } from '../../../services/views/common/viewsService.service.js';
import { OPEN_TO_SIDE_COMMAND_ID, COMPARE_WITH_SAVED_COMMAND_ID, ResourceSelectedForCompareContext, SELECT_FOR_COMPARE_COMMAND_ID, COMPARE_SELECTED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, COPY_PATH_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_WITH_EXPLORER_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, PREVIOUS_COMPRESSED_FOLDER, NEXT_COMPRESSED_FOLDER, FIRST_COMPRESSED_FOLDER, LAST_COMPRESSED_FOLDER, NEW_UNTITLED_FILE_LABEL, NEW_UNTITLED_FILE_COMMAND_ID, NEW_FILE_COMMAND_ID } from './fileConstants.js';
import { IFileDialogService } from '../../../../platform/dialogs/common/dialogs.service.js';
import { RemoveRootFolderAction } from '../../../browser/actions/workspaceActions.js';
import { OpenEditorsView } from './views/openEditorsView.js';
import { IListService } from '../../../../platform/list/browser/listService.service.js';
import './fileCommands._save.js';

const openWindowCommand = (accessor, toOpen, options) => {
    if (Array.isArray(toOpen)) {
        const hostService = accessor.get(IHostService);
        const environmentService = accessor.get(IEnvironmentService);
        toOpen = ( toOpen.map(openable => {
            if (isWorkspaceToOpen(openable) && openable.workspaceUri.scheme === Schemas.untitled) {
                return {
                    workspaceUri: joinPath(
                        environmentService.untitledWorkspacesHome,
                        openable.workspaceUri.path,
                        UNTITLED_WORKSPACE_NAME
                    )
                };
            }
            return openable;
        }));
        hostService.openWindow(toOpen, options);
    }
};
const newWindowCommand = (accessor, options) => {
    const hostService = accessor.get(IHostService);
    hostService.openWindow(options);
};
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: ExplorerFocusCondition,
    primary: KeyMod$1.CtrlCmd | KeyCode.Enter,
    mac: {
        primary: KeyMod$1.WinCtrl | KeyCode.Enter
    },
    id: OPEN_TO_SIDE_COMMAND_ID,
    handler: async (accessor, resource) => {
        const editorService = accessor.get(IEditorService);
        const fileService = accessor.get(IFileService);
        const explorerService = accessor.get(IExplorerService);
        const resources = getMultiSelectedResources(
            resource,
            accessor.get(IListService),
            editorService,
            accessor.get(IEditorGroupsService),
            explorerService
        );
        if (resources.length) {
            const untitledResources = resources.filter(resource => resource.scheme === Schemas.untitled);
            const fileResources = resources.filter(resource => resource.scheme !== Schemas.untitled);
            const items = await Promise.all(( fileResources.map(async resource => {
                const item = explorerService.findClosest(resource);
                if (item) {
                    return item;
                }
                return await fileService.stat(resource);
            })));
            const files = items.filter(i => !i.isDirectory);
            const editors = ( files.map(f => ({
                resource: f.resource,
                options: {
                    pinned: true
                }
            }))).concat(...( untitledResources.map(untitledResource => ({
                resource: untitledResource,
                options: {
                    pinned: true
                }
            }))));
            await editorService.openEditors(editors, SIDE_GROUP);
        }
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib + 10,
    when: ( ContextKeyExpr.and(FilesExplorerFocusCondition, ( ExplorerFolderContext.toNegated()))),
    primary: KeyCode.Enter,
    mac: {
        primary: KeyMod$1.CtrlCmd | KeyCode.DownArrow
    },
    id: "explorer.openAndPassFocus",
    handler: async (accessor, _resource) => {
        const editorService = accessor.get(IEditorService);
        const explorerService = accessor.get(IExplorerService);
        const resources = explorerService.getContext(true);
        if (resources.length) {
            await editorService.openEditors(( resources.map(r => ({
                resource: r.resource,
                options: {
                    preserveFocus: false,
                    pinned: true
                }
            }))));
        }
    }
});
const COMPARE_WITH_SAVED_SCHEMA = "showModifications";
let providerDisposables = [];
KeybindingsRegistry.registerCommandAndKeybindingRule({
    id: COMPARE_WITH_SAVED_COMMAND_ID,
    when: undefined,
    weight: KeybindingWeight.WorkbenchContrib,
    primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyD),
    handler: async (accessor, resource) => {
        const instantiationService = accessor.get(IInstantiationService);
        const textModelService = accessor.get(ITextModelService);
        const editorService = accessor.get(IEditorService);
        const fileService = accessor.get(IFileService);
        const listService = accessor.get(IListService);
        let registerEditorListener = false;
        if (providerDisposables.length === 0) {
            registerEditorListener = true;
            const provider = instantiationService.createInstance(TextFileContentProvider);
            providerDisposables.push(provider);
            providerDisposables.push(
                textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider)
            );
        }
        const uri = getResourceForCommand(resource, editorService, listService);
        if (uri && fileService.hasProvider(uri)) {
            const name = basename(uri);
            const editorLabel = ( localize(10440, "{0} (in file) ↔ {1}", name, name));
            try {
                await TextFileContentProvider.open(uri, COMPARE_WITH_SAVED_SCHEMA, editorLabel, editorService, {
                    pinned: true
                });
                if (registerEditorListener) {
                    providerDisposables.push(editorService.onDidVisibleEditorsChange(() => {
                        if (!( editorService.editors.some(editor => !!EditorResourceAccessor.getCanonicalUri(editor, {
                            supportSideBySide: SideBySideEditor.SECONDARY,
                            filterByScheme: COMPARE_WITH_SAVED_SCHEMA
                        })))) {
                            providerDisposables = dispose(providerDisposables);
                        }
                    }));
                }
            } catch {
                providerDisposables = dispose(providerDisposables);
            }
        }
    }
});
let globalResourceToCompare;
let resourceSelectedForCompareContext;
CommandsRegistry.registerCommand({
    id: SELECT_FOR_COMPARE_COMMAND_ID,
    handler: (accessor, resource) => {
        globalResourceToCompare = getResourceForCommand(resource, accessor.get(IEditorService), accessor.get(IListService));
        if (!resourceSelectedForCompareContext) {
            resourceSelectedForCompareContext = ResourceSelectedForCompareContext.bindTo(accessor.get(IContextKeyService));
        }
        resourceSelectedForCompareContext.set(true);
    }
});
CommandsRegistry.registerCommand({
    id: COMPARE_SELECTED_COMMAND_ID,
    handler: async (accessor, resource) => {
        const editorService = accessor.get(IEditorService);
        const resources = getMultiSelectedResources(
            resource,
            accessor.get(IListService),
            editorService,
            accessor.get(IEditorGroupsService),
            accessor.get(IExplorerService)
        );
        if (resources.length === 2) {
            return editorService.openEditor({
                original: {
                    resource: resources[0]
                },
                modified: {
                    resource: resources[1]
                },
                options: {
                    pinned: true
                }
            });
        }
        return true;
    }
});
CommandsRegistry.registerCommand({
    id: COMPARE_RESOURCE_COMMAND_ID,
    handler: (accessor, resource) => {
        const editorService = accessor.get(IEditorService);
        const rightResource = getResourceForCommand(resource, editorService, accessor.get(IListService));
        if (globalResourceToCompare && rightResource) {
            editorService.openEditor({
                original: {
                    resource: globalResourceToCompare
                },
                modified: {
                    resource: rightResource
                },
                options: {
                    pinned: true
                }
            });
        }
    }
});
async function resourcesToClipboard(resources, relative, clipboardService, labelService, configurationService) {
    if (resources.length) {
        const lineDelimiter = isWindows ? "\r\n" : "\n";
        let separator = undefined;
        const copyRelativeOrFullPathSeparatorSection = relative ? "explorer.copyRelativePathSeparator" : "explorer.copyPathSeparator";
        const copyRelativeOrFullPathSeparator = configurationService.getValue(copyRelativeOrFullPathSeparatorSection);
        if (copyRelativeOrFullPathSeparator === "/" || copyRelativeOrFullPathSeparator === "\\") {
            separator = copyRelativeOrFullPathSeparator;
        }
        const text = ( resources.map(resource => labelService.getUriLabel(resource, {
            relative,
            noPrefix: true,
            separator
        }))).join(lineDelimiter);
        await clipboardService.writeText(text);
    }
}
const copyPathCommandHandler = async (accessor, resource) => {
    const resources = getMultiSelectedResources(
        resource,
        accessor.get(IListService),
        accessor.get(IEditorService),
        accessor.get(IEditorGroupsService),
        accessor.get(IExplorerService)
    );
    await resourcesToClipboard(
        resources,
        false,
        accessor.get(IClipboardService),
        accessor.get(ILabelService),
        accessor.get(IConfigurationService)
    );
};
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: ( EditorContextKeys.focus.toNegated()),
    primary: KeyMod$1.CtrlCmd | KeyMod$1.Alt | KeyCode.KeyC,
    win: {
        primary: KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyC
    },
    id: COPY_PATH_COMMAND_ID,
    handler: copyPathCommandHandler
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: EditorContextKeys.focus,
    primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyMod$1.CtrlCmd | KeyMod$1.Alt | KeyCode.KeyC),
    win: {
        primary: KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyC
    },
    id: COPY_PATH_COMMAND_ID,
    handler: copyPathCommandHandler
});
const copyRelativePathCommandHandler = async (accessor, resource) => {
    const resources = getMultiSelectedResources(
        resource,
        accessor.get(IListService),
        accessor.get(IEditorService),
        accessor.get(IEditorGroupsService),
        accessor.get(IExplorerService)
    );
    await resourcesToClipboard(
        resources,
        true,
        accessor.get(IClipboardService),
        accessor.get(ILabelService),
        accessor.get(IConfigurationService)
    );
};
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: ( EditorContextKeys.focus.toNegated()),
    primary: KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyC,
    win: {
        primary: KeyChord(
            KeyMod$1.CtrlCmd | KeyCode.KeyK,
            KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyCode.KeyC
        )
    },
    id: COPY_RELATIVE_PATH_COMMAND_ID,
    handler: copyRelativePathCommandHandler
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: EditorContextKeys.focus,
    primary: KeyChord(
        KeyMod$1.CtrlCmd | KeyCode.KeyK,
        KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyMod$1.Alt | KeyCode.KeyC
    ),
    win: {
        primary: KeyChord(
            KeyMod$1.CtrlCmd | KeyCode.KeyK,
            KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyCode.KeyC
        )
    },
    id: COPY_RELATIVE_PATH_COMMAND_ID,
    handler: copyRelativePathCommandHandler
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: undefined,
    primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyP),
    id: "workbench.action.files.copyPathOfActiveFile",
    handler: async accessor => {
        const editorService = accessor.get(IEditorService);
        const activeInput = editorService.activeEditor;
        const resource = EditorResourceAccessor.getOriginalUri(activeInput, {
            supportSideBySide: SideBySideEditor.PRIMARY
        });
        const resources = resource ? [resource] : [];
        await resourcesToClipboard(
            resources,
            false,
            accessor.get(IClipboardService),
            accessor.get(ILabelService),
            accessor.get(IConfigurationService)
        );
    }
});
CommandsRegistry.registerCommand({
    id: REVEAL_IN_EXPLORER_COMMAND_ID,
    handler: async (accessor, resource) => {
        const viewService = accessor.get(IViewsService);
        const contextService = accessor.get(IWorkspaceContextService);
        const explorerService = accessor.get(IExplorerService);
        const editorService = accessor.get(IEditorService);
        const listService = accessor.get(IListService);
        const uri = getResourceForCommand(resource, editorService, listService);
        if (uri && contextService.isInsideWorkspace(uri)) {
            const explorerView = await viewService.openView(VIEW_ID, false);
            if (explorerView) {
                const oldAutoReveal = explorerView.autoReveal;
                explorerView.autoReveal = false;
                explorerView.setExpanded(true);
                await explorerService.select(uri, "force");
                explorerView.focus();
                explorerView.autoReveal = oldAutoReveal;
            }
        } else {
            const openEditorsView = viewService.getViewWithId(OpenEditorsView.ID);
            if (openEditorsView) {
                openEditorsView.setExpanded(true);
                openEditorsView.focus();
            }
        }
    }
});
CommandsRegistry.registerCommand({
    id: OPEN_WITH_EXPLORER_COMMAND_ID,
    handler: async (accessor, resource) => {
        const editorService = accessor.get(IEditorService);
        const listService = accessor.get(IListService);
        const uri = getResourceForCommand(resource, editorService, listService);
        if (uri) {
            return editorService.openEditor({
                resource: uri,
                options: {
                    override: EditorResolution.PICK,
                    source: EditorOpenSource.USER
                }
            });
        }
        return undefined;
    }
});
CommandsRegistry.registerCommand({
    id: REMOVE_ROOT_FOLDER_COMMAND_ID,
    handler: (accessor, resource) => {
        const contextService = accessor.get(IWorkspaceContextService);
        const uriIdentityService = accessor.get(IUriIdentityService);
        const workspace = contextService.getWorkspace();
        const resources = getMultiSelectedResources(
            resource,
            accessor.get(IListService),
            accessor.get(IEditorService),
            accessor.get(IEditorGroupsService),
            accessor.get(IExplorerService)
        ).filter(
            resource => ( workspace.folders.some(folder => uriIdentityService.extUri.isEqual(folder.uri, resource)))
        );
        if (resources.length === 0) {
            const commandService = accessor.get(ICommandService);
            return commandService.executeCommand(RemoveRootFolderAction.ID);
        }
        const workspaceEditingService = accessor.get(IWorkspaceEditingService);
        return workspaceEditingService.removeFolders(resources);
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib + 10,
    when: ( ContextKeyExpr.and(
        FilesExplorerFocusCondition,
        ExplorerCompressedFocusContext,
        ( ExplorerCompressedFirstFocusContext.negate())
    )),
    primary: KeyCode.LeftArrow,
    id: PREVIOUS_COMPRESSED_FOLDER,
    handler: accessor => {
        const paneCompositeService = accessor.get(IPaneCompositePartService);
        const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);
        if (viewlet?.getId() !== VIEWLET_ID) {
            return;
        }
        const explorer = viewlet.getViewPaneContainer();
        const view = explorer.getExplorerView();
        view.previousCompressedStat();
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib + 10,
    when: ( ContextKeyExpr.and(
        FilesExplorerFocusCondition,
        ExplorerCompressedFocusContext,
        ( ExplorerCompressedLastFocusContext.negate())
    )),
    primary: KeyCode.RightArrow,
    id: NEXT_COMPRESSED_FOLDER,
    handler: accessor => {
        const paneCompositeService = accessor.get(IPaneCompositePartService);
        const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);
        if (viewlet?.getId() !== VIEWLET_ID) {
            return;
        }
        const explorer = viewlet.getViewPaneContainer();
        const view = explorer.getExplorerView();
        view.nextCompressedStat();
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib + 10,
    when: ( ContextKeyExpr.and(
        FilesExplorerFocusCondition,
        ExplorerCompressedFocusContext,
        ( ExplorerCompressedFirstFocusContext.negate())
    )),
    primary: KeyCode.Home,
    id: FIRST_COMPRESSED_FOLDER,
    handler: accessor => {
        const paneCompositeService = accessor.get(IPaneCompositePartService);
        const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);
        if (viewlet?.getId() !== VIEWLET_ID) {
            return;
        }
        const explorer = viewlet.getViewPaneContainer();
        const view = explorer.getExplorerView();
        view.firstCompressedStat();
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib + 10,
    when: ( ContextKeyExpr.and(
        FilesExplorerFocusCondition,
        ExplorerCompressedFocusContext,
        ( ExplorerCompressedLastFocusContext.negate())
    )),
    primary: KeyCode.End,
    id: LAST_COMPRESSED_FOLDER,
    handler: accessor => {
        const paneCompositeService = accessor.get(IPaneCompositePartService);
        const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);
        if (viewlet?.getId() !== VIEWLET_ID) {
            return;
        }
        const explorer = viewlet.getViewPaneContainer();
        const view = explorer.getExplorerView();
        view.lastCompressedStat();
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    weight: KeybindingWeight.WorkbenchContrib,
    when: null,
    primary: isWeb ? (isWindows ? KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyN) : KeyMod$1.CtrlCmd | KeyMod$1.Alt | KeyCode.KeyN) : KeyMod$1.CtrlCmd | KeyCode.KeyN,
    secondary: isWeb ? [KeyMod$1.CtrlCmd | KeyCode.KeyN] : undefined,
    id: NEW_UNTITLED_FILE_COMMAND_ID,
    metadata: {
        description: NEW_UNTITLED_FILE_LABEL,
        args: [{
            isOptional: true,
            name: "New Untitled Text File arguments",
            description: "The editor view type or language ID if known",
            schema: {
                "type": "object",
                "properties": {
                    "viewType": {
                        "type": "string"
                    },
                    "languageId": {
                        "type": "string"
                    }
                }
            }
        }]
    },
    handler: async (accessor, args) => {
        const editorService = accessor.get(IEditorService);
        await editorService.openEditor({
            resource: undefined,
            options: {
                override: args?.viewType,
                pinned: true
            },
            languageId: args?.languageId
        });
    }
});
CommandsRegistry.registerCommand({
    id: NEW_FILE_COMMAND_ID,
    handler: async (accessor, args) => {
        const editorService = accessor.get(IEditorService);
        const dialogService = accessor.get(IFileDialogService);
        const fileService = accessor.get(IFileService);
        const createFileLocalized = ( localize(10441, "Create File"));
        const defaultFileUri = joinPath(await dialogService.defaultFilePath(), args?.fileName ?? "Untitled.txt");
        const saveUri = await dialogService.showSaveDialog({
            saveLabel: createFileLocalized,
            title: createFileLocalized,
            defaultUri: defaultFileUri
        });
        if (!saveUri) {
            return;
        }
        await fileService.createFile(saveUri, undefined, {
            overwrite: true
        });
        await editorService.openEditor({
            resource: saveUri,
            options: {
                override: args?.viewType,
                pinned: true
            },
            languageId: args?.languageId
        });
    }
});

export { newWindowCommand, openWindowCommand };
