import { toAction } from '../../../../base/common/actions.js';
import { coalesce } from '../../../../base/common/arrays.js';
import { toErrorMessage } from '../../../../base/common/errorMessage.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 { isEqual } from '../../../../base/common/resources.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js';
import { localizeWithPath } from '../../../../nls.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 { getMultiSelectedEditorContexts } from '../../../browser/parts/editor/editorCommands.js';
import { SaveReason, EditorInputCapabilities, EditorResourceAccessor, SideBySideEditor, EditorsOrder } from '../../../common/editor.js';
import { SideBySideEditorInput } from '../../../common/editor/sideBySideEditorInput.js';
import { getOpenEditorsViewMultiSelection } from './files.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 } from './fileConstants.js';
import Severity$1 from '../../../../base/common/severity.js';
const _moduleId = "vs/workbench/contrib/files/browser/fileCommands";
async function saveSelectedEditors(accessor, options) {
    const listService = accessor.get(IListService);
    const editorGroupService = accessor.get(IEditorGroupsService);
    const codeEditorService = accessor.get(ICodeEditorService);
    const textFileService = accessor.get(ITextFileService);
    let editors = getOpenEditorsViewMultiSelection(listService);
    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)) {
            notificationService.notify({
                id: ( (editors.map(({ editor }) => hash(editor.resource?.toString())))).join(),
                severity: Severity$1.Error,
                message: ( localizeWithPath(
                    _moduleId,
                    3,
                    "Failed to save '{0}': {1}",
                    ( (editors.map(({ editor }) => editor.getName()))).join(', '),
                    toErrorMessage(error, false)
                )),
                actions: {
                    primary: [
                        toAction({ id: 'workbench.action.files.saveEditors', label: ( localizeWithPath(_moduleId, 4, "Retry")), run: () => instantiationService.invokeFunction(accessor => doSaveEditors(accessor, editors, options)) }),
                        toAction({ id: 'workbench.action.files.revertEditors', label: ( localizeWithPath(_moduleId, 5, "Discard")), run: () => editorService.revert(editors) })
                    ]
                }
            });
        }
    }
}
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 editorGroupService = accessor.get(IEditorGroupsService);
        const contexts = getMultiSelectedEditorContexts(editorContext, accessor.get(IListService), accessor.get(IEditorGroupsService));
        let groups = undefined;
        if (!contexts.length) {
            groups = editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE);
        }
        else {
            groups = coalesce(( (contexts.map(context => editorGroupService.getGroup(context.groupId)))));
        }
        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;
    }
});
