
import { localize } from '../../../../nls.js';
import { toAction } from '../../../../base/common/actions.js';
import { isCancellationError } from '../../../../base/common/errors.js';
import { hash } from '../../../../base/common/hash.js';
import { KeyMod as KeyMod$1, KeyCode, KeyChord } from '../../../../base/common/keyCodes.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.service.js';
import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js';
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { KeybindingsRegistry, KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IListService } from '../../../../platform/list/browser/listService.service.js';
import '../../../../platform/notification/common/notification.js';
import { INotificationService } from '../../../../platform/notification/common/notification.service.js';
import { resolveCommandsContext } from '../../../browser/parts/editor/editorCommandsContext.js';
import { EditorInputCapabilities, EditorResourceAccessor, SideBySideEditor, EditorsOrder, SaveReason } from '../../../common/editor.js';
import { SideBySideEditorInput } from '../../../common/editor/sideBySideEditorInput.js';
import { GroupsOrder } from '../../../services/editor/common/editorGroupsService.js';
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.service.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { ITextFileService } from '../../../services/textfile/common/textfiles.service.js';
import { SAVE_FILE_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_AS_COMMAND_ID, SAVE_ALL_COMMAND_ID, SAVE_ALL_IN_GROUP_COMMAND_ID, SAVE_FILES_COMMAND_ID, REVERT_FILE_COMMAND_ID } from './fileConstants.js';
import { getOpenEditorsViewMultiSelection } from './files.js';
import { isEqual } from '../../../../base/common/resources.js';
import { toErrorMessage } from '../../../../base/common/errorMessage.js';
import Severity$1 from '../../../../base/common/severity.js';

async function saveSelectedEditors(accessor, options) {
    const editorGroupService = accessor.get(IEditorGroupsService);
    const codeEditorService = accessor.get(ICodeEditorService);
    const textFileService = accessor.get(ITextFileService);
    let editors = getOpenEditorsViewMultiSelection(accessor);
    if (!editors) {
        const activeGroup = editorGroupService.activeGroup;
        if (activeGroup.activeEditor) {
            editors = [];
            if (activeGroup.activeEditor instanceof SideBySideEditorInput && !options?.saveAs && !(activeGroup.activeEditor.primary.hasCapability(EditorInputCapabilities.Untitled) || activeGroup.activeEditor.secondary.hasCapability(EditorInputCapabilities.Untitled)) && activeGroup.activeEditor.secondary.isModified()) {
                editors.push({
                    groupId: activeGroup.id,
                    editor: activeGroup.activeEditor.primary
                });
                editors.push({
                    groupId: activeGroup.id,
                    editor: activeGroup.activeEditor.secondary
                });
            } else {
                editors.push({
                    groupId: activeGroup.id,
                    editor: activeGroup.activeEditor
                });
            }
        }
    }
    if (!editors || editors.length === 0) {
        return;
    }
    await doSaveEditors(accessor, editors, options);
    const focusedCodeEditor = codeEditorService.getFocusedCodeEditor();
    if (focusedCodeEditor instanceof EmbeddedCodeEditorWidget && !focusedCodeEditor.isSimpleWidget) {
        const resource = focusedCodeEditor.getModel()?.uri;
        if (resource && !( editors.some((
            {
                editor
            }
        ) => isEqual(EditorResourceAccessor.getCanonicalUri(editor, {
            supportSideBySide: SideBySideEditor.PRIMARY
        }), resource)))) {
            const model = textFileService.files.get(resource);
            if (!model?.isReadonly()) {
                await textFileService.save(resource, options);
            }
        }
    }
}
function saveDirtyEditorsOfGroups(accessor, groups, options) {
    const dirtyEditors = [];
    for (const group of groups) {
        for (const editor of group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE)) {
            if (editor.isDirty()) {
                dirtyEditors.push({
                    groupId: group.id,
                    editor
                });
            }
        }
    }
    return doSaveEditors(accessor, dirtyEditors, options);
}
async function doSaveEditors(accessor, editors, options) {
    const editorService = accessor.get(IEditorService);
    const notificationService = accessor.get(INotificationService);
    const instantiationService = accessor.get(IInstantiationService);
    try {
        await editorService.save(editors, options);
    } catch (error) {
        if (!isCancellationError(error)) {
            const actions = [toAction({
                id: "workbench.action.files.saveEditors",
                label: ( localize(10435, "Retry")),
                run: () => instantiationService.invokeFunction(accessor => doSaveEditors(accessor, editors, options))
            })];
            const editorsToRevert = editors.filter((
                {
                    editor
                }
            ) => !editor.hasCapability(EditorInputCapabilities.Untitled) );
            if (editorsToRevert.length > 0) {
                actions.push(toAction({
                    id: "workbench.action.files.revertEditors",
                    label: editorsToRevert.length > 1 ? ( localize(10436, "Revert All")) : ( localize(10437, "Revert")),
                    run: () => editorService.revert(editorsToRevert)
                }));
            }
            notificationService.notify({
                id: ( editors.map((
                    {
                        editor
                    }
                ) => hash(editor.resource?.toString()))).join(),
                severity: Severity$1.Error,
                message: ( localize(10438, "Failed to save '{0}': {1}", ( editors.map((
                    {
                        editor
                    }
                ) => editor.getName())).join(", "), toErrorMessage(error, false))),
                actions: {
                    primary: actions
                }
            });
        }
    }
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
    when: undefined,
    weight: KeybindingWeight.WorkbenchContrib,
    primary: KeyMod$1.CtrlCmd | KeyCode.KeyS,
    id: SAVE_FILE_COMMAND_ID,
    handler: accessor => {
        return saveSelectedEditors(accessor, {
            reason: SaveReason.EXPLICIT,
            force: true
        });
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    when: undefined,
    weight: KeybindingWeight.WorkbenchContrib,
    primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyS),
    win: {
        primary: KeyChord(
            KeyMod$1.CtrlCmd | KeyCode.KeyK,
            KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyCode.KeyS
        )
    },
    id: SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID,
    handler: accessor => {
        return saveSelectedEditors(accessor, {
            reason: SaveReason.EXPLICIT,
            force: true ,
            skipSaveParticipants: true
        });
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    id: SAVE_FILE_AS_COMMAND_ID,
    weight: KeybindingWeight.WorkbenchContrib,
    when: undefined,
    primary: KeyMod$1.CtrlCmd | KeyMod$1.Shift | KeyCode.KeyS,
    handler: accessor => {
        return saveSelectedEditors(accessor, {
            reason: SaveReason.EXPLICIT,
            saveAs: true
        });
    }
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
    when: undefined,
    weight: KeybindingWeight.WorkbenchContrib,
    primary: undefined,
    mac: {
        primary: KeyMod$1.CtrlCmd | KeyMod$1.Alt | KeyCode.KeyS
    },
    win: {
        primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyS)
    },
    id: SAVE_ALL_COMMAND_ID,
    handler: accessor => {
        return saveDirtyEditorsOfGroups(
            accessor,
            accessor.get(IEditorGroupsService).getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE),
            {
                reason: SaveReason.EXPLICIT
            }
        );
    }
});
CommandsRegistry.registerCommand({
    id: SAVE_ALL_IN_GROUP_COMMAND_ID,
    handler: (accessor, _, editorContext) => {
        const editorGroupsService = accessor.get(IEditorGroupsService);
        const resolvedContext = resolveCommandsContext(
            [editorContext],
            accessor.get(IEditorService),
            editorGroupsService,
            accessor.get(IListService)
        );
        let groups = undefined;
        if (!resolvedContext.groupedEditors.length) {
            groups = editorGroupsService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE);
        } else {
            groups = ( resolvedContext.groupedEditors.map((
                {
                    group
                }
            ) => group));
        }
        return saveDirtyEditorsOfGroups(accessor, groups, {
            reason: SaveReason.EXPLICIT
        });
    }
});
CommandsRegistry.registerCommand({
    id: SAVE_FILES_COMMAND_ID,
    handler: async accessor => {
        const editorService = accessor.get(IEditorService);
        const res = await editorService.saveAll({
            includeUntitled: false,
            reason: SaveReason.EXPLICIT
        });
        return res.success;
    }
});
CommandsRegistry.registerCommand({
    id: REVERT_FILE_COMMAND_ID,
    handler: async accessor => {
        const editorGroupService = accessor.get(IEditorGroupsService);
        const editorService = accessor.get(IEditorService);
        let editors = getOpenEditorsViewMultiSelection(accessor);
        if (!editors) {
            const activeGroup = editorGroupService.activeGroup;
            if (activeGroup.activeEditor) {
                editors = [{
                    groupId: activeGroup.id,
                    editor: activeGroup.activeEditor
                }];
            }
        }
        if (!editors || editors.length === 0) {
            return;
        }
        try {
            await editorService.revert(editors.filter((
                {
                    editor
                }
            ) => !editor.hasCapability(EditorInputCapabilities.Untitled) ), {
                force: true
            });
        } catch (error) {
            const notificationService = accessor.get(INotificationService);
            notificationService.error(( localize(10439, "Failed to revert '{0}': {1}", ( editors.map((
                {
                    editor
                }
            ) => editor.getName())).join(", "), toErrorMessage(error, false))));
        }
    }
});
