
import { KeyChord, KeyMod as KeyMod$1, KeyCode } from '../../../../base/common/keyCodes.js';
import { isEqual } from '../../../../base/common/resources.js';
import { URI } from '../../../../base/common/uri.js';
import { ITextResourceConfigurationService } from '../../../../editor/common/services/textResourceConfiguration.service.js';
import { localize2, localize } from '../../../../nls.js';
import { MenuRegistry, MenuId } from '../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { KeybindingsRegistry, KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { TextDiffEditor } from './textDiffEditor.js';
import { TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveCompareEditorCanSwapContext } from '../../../common/contextkeys.js';
import { DiffEditorInput } from '../../../common/editor/diffEditorInput.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
import { isDiffEditor } from '../../../../editor/browser/editorBrowser.js';

const TOGGLE_DIFF_SIDE_BY_SIDE = "toggle.diff.renderSideBySide";
const GOTO_NEXT_CHANGE = "workbench.action.compareEditor.nextChange";
const GOTO_PREVIOUS_CHANGE = "workbench.action.compareEditor.previousChange";
const DIFF_FOCUS_PRIMARY_SIDE = "workbench.action.compareEditor.focusPrimarySide";
const DIFF_FOCUS_SECONDARY_SIDE = "workbench.action.compareEditor.focusSecondarySide";
const DIFF_FOCUS_OTHER_SIDE = "workbench.action.compareEditor.focusOtherSide";
const DIFF_OPEN_SIDE = "workbench.action.compareEditor.openSide";
const TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE = "toggle.diff.ignoreTrimWhitespace";
const DIFF_SWAP_SIDES = "workbench.action.compareEditor.swapSides";
function registerDiffEditorCommands() {
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: DIFF_OPEN_SIDE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: EditorContextKeys.inDiffEditor,
        primary: KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyMod$1.Shift | KeyCode.KeyO),
        handler: async accessor => {
            const editorService = accessor.get(IEditorService);
            const activeEditor = editorService.activeEditor;
            const activeTextEditorControl = editorService.activeTextEditorControl;
            if (!isDiffEditor(activeTextEditorControl) || !(activeEditor instanceof DiffEditorInput)) {
                return;
            }
            let editor;
            const originalEditor = activeTextEditorControl.getOriginalEditor();
            if (originalEditor.hasTextFocus()) {
                editor = activeEditor.original;
            } else {
                editor = activeEditor.modified;
            }
            return editorService.openEditor(editor);
        }
    });
    MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
        command: {
            id: DIFF_OPEN_SIDE,
            title: ( localize2(3171, "Open Active Diff Side"))
        }
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: GOTO_NEXT_CHANGE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: TextCompareEditorVisibleContext,
        primary: KeyMod$1.Alt | KeyCode.F5,
        handler: (accessor, ...args) => navigateInDiffEditor(accessor, args, true)
    });
    MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
        command: {
            id: GOTO_NEXT_CHANGE,
            title: ( localize2(3172, "Go to Next Change"))
        }
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: GOTO_PREVIOUS_CHANGE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: TextCompareEditorVisibleContext,
        primary: KeyMod$1.Alt | KeyMod$1.Shift | KeyCode.F5,
        handler: (accessor, ...args) => navigateInDiffEditor(accessor, args, false)
    });
    MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
        command: {
            id: GOTO_PREVIOUS_CHANGE,
            title: ( localize2(3173, "Go to Previous Change"))
        }
    });
    function getActiveTextDiffEditor(accessor, args) {
        const editorService = accessor.get(IEditorService);
        const resource = args.length > 0 && args[0] instanceof URI ? args[0] : undefined;
        for (const editor of [editorService.activeEditorPane, ...editorService.visibleEditorPanes]) {
            if (editor instanceof TextDiffEditor && (!resource || editor.input instanceof DiffEditorInput && isEqual(editor.input.primary.resource, resource))) {
                return editor;
            }
        }
        return undefined;
    }
    function navigateInDiffEditor(accessor, args, next) {
        const activeTextDiffEditor = getActiveTextDiffEditor(accessor, args);
        if (activeTextDiffEditor) {
            activeTextDiffEditor.getControl()?.goToDiff(next ? "next" : "previous");
        }
    }
    let FocusTextDiffEditorMode;
    (function(FocusTextDiffEditorMode) {
        FocusTextDiffEditorMode[FocusTextDiffEditorMode["Original"] = 0] = "Original";
        FocusTextDiffEditorMode[FocusTextDiffEditorMode["Modified"] = 1] = "Modified";
        FocusTextDiffEditorMode[FocusTextDiffEditorMode["Toggle"] = 2] = "Toggle";
    })(FocusTextDiffEditorMode || (FocusTextDiffEditorMode = {}));
    function focusInDiffEditor(accessor, args, mode) {
        const activeTextDiffEditor = getActiveTextDiffEditor(accessor, args);
        if (activeTextDiffEditor) {
            switch (mode) {
            case FocusTextDiffEditorMode.Original:
                activeTextDiffEditor.getControl()?.getOriginalEditor().focus();
                break;
            case FocusTextDiffEditorMode.Modified:
                activeTextDiffEditor.getControl()?.getModifiedEditor().focus();
                break;
            case FocusTextDiffEditorMode.Toggle:
                if (activeTextDiffEditor.getControl()?.getModifiedEditor().hasWidgetFocus()) {
                    return focusInDiffEditor(accessor, args, FocusTextDiffEditorMode.Original);
                } else {
                    return focusInDiffEditor(accessor, args, FocusTextDiffEditorMode.Modified);
                }
            }
        }
    }
    function toggleDiffSideBySide(accessor, args) {
        const configService = accessor.get(ITextResourceConfigurationService);
        const activeTextDiffEditor = getActiveTextDiffEditor(accessor, args);
        const m = activeTextDiffEditor?.getControl()?.getModifiedEditor()?.getModel();
        if (!m) {
            return;
        }
        const key = "diffEditor.renderSideBySide";
        const val = configService.getValue(m.uri, key);
        configService.updateValue(m.uri, key, !val);
    }
    function toggleDiffIgnoreTrimWhitespace(accessor, args) {
        const configService = accessor.get(ITextResourceConfigurationService);
        const activeTextDiffEditor = getActiveTextDiffEditor(accessor, args);
        const m = activeTextDiffEditor?.getControl()?.getModifiedEditor()?.getModel();
        if (!m) {
            return;
        }
        const key = "diffEditor.ignoreTrimWhitespace";
        const val = configService.getValue(m.uri, key);
        configService.updateValue(m.uri, key, !val);
    }
    async function swapDiffSides(accessor, args) {
        const editorService = accessor.get(IEditorService);
        const diffEditor = getActiveTextDiffEditor(accessor, args);
        const activeGroup = diffEditor?.group;
        const diffInput = diffEditor?.input;
        if (!diffEditor || typeof activeGroup === "undefined" || !(diffInput instanceof DiffEditorInput) || !diffInput.modified.resource) {
            return;
        }
        const untypedDiffInput = diffInput.toUntyped({
            preserveViewState: activeGroup.id,
            preserveResource: true
        });
        if (!untypedDiffInput) {
            return;
        }
        if (diffInput.modified.isModified() && editorService.findEditors({
            resource: diffInput.modified.resource,
            typeId: diffInput.modified.typeId,
            editorId: diffInput.modified.editorId
        }).length === 0) {
            const editorToOpen = {
                ...untypedDiffInput.modified
            };
            if (!editorToOpen.options) {
                editorToOpen.options = {};
            }
            editorToOpen.options.pinned = true;
            editorToOpen.options.inactive = true;
            await editorService.openEditor(editorToOpen, activeGroup);
        }
        await editorService.replaceEditors([{
            editor: diffInput,
            replacement: {
                ...untypedDiffInput,
                original: untypedDiffInput.modified,
                modified: untypedDiffInput.original,
                options: {
                    ...untypedDiffInput.options,
                    pinned: true
                }
            }
        }], activeGroup);
    }
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: TOGGLE_DIFF_SIDE_BY_SIDE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => toggleDiffSideBySide(accessor, args)
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: DIFF_FOCUS_PRIMARY_SIDE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => focusInDiffEditor(accessor, args, FocusTextDiffEditorMode.Modified)
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: DIFF_FOCUS_SECONDARY_SIDE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => focusInDiffEditor(accessor, args, FocusTextDiffEditorMode.Original)
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: DIFF_FOCUS_OTHER_SIDE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => focusInDiffEditor(accessor, args, FocusTextDiffEditorMode.Toggle)
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => toggleDiffIgnoreTrimWhitespace(accessor, args)
    });
    KeybindingsRegistry.registerCommandAndKeybindingRule({
        id: DIFF_SWAP_SIDES,
        weight: KeybindingWeight.WorkbenchContrib,
        when: undefined,
        primary: undefined,
        handler: (accessor, ...args) => swapDiffSides(accessor, args)
    });
    MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
        command: {
            id: TOGGLE_DIFF_SIDE_BY_SIDE,
            title: ( localize2(3174, "Toggle Inline View")),
            category: ( localize(3175, "Compare"))
        },
        when: TextCompareEditorActiveContext
    });
    MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
        command: {
            id: DIFF_SWAP_SIDES,
            title: ( localize2(3176, "Swap Left and Right Editor Side")),
            category: ( localize(3175, "Compare"))
        },
        when: ( ContextKeyExpr.and(TextCompareEditorActiveContext, ActiveCompareEditorCanSwapContext))
    });
}

export { DIFF_FOCUS_OTHER_SIDE, DIFF_FOCUS_PRIMARY_SIDE, DIFF_FOCUS_SECONDARY_SIDE, DIFF_OPEN_SIDE, DIFF_SWAP_SIDES, GOTO_NEXT_CHANGE, GOTO_PREVIOUS_CHANGE, TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, TOGGLE_DIFF_SIDE_BY_SIDE, registerDiffEditorCommands };
