import { Codicon } from '../../../../base/common/codicons.js';
import { KeyMod as KeyMod$1, KeyCode, KeyChord } from '../../../../base/common/keyCodes.js';
import { isCodeEditor, isDiffEditor } from '../../../../editor/browser/editorBrowser.js';
import { EditorAction2 } from '../../../../editor/browser/editorExtensions.js';
import { EmbeddedDiffEditorWidget } from '../../../../editor/browser/widget/diffEditor/embeddedDiffEditorWidget.js';
import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js';
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
import { InlineChatController, InlineChatRunOptions } from './inlineChatController.js';
import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, MENU_INLINE_CHAT_CONTENT_STATUS, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF } from '../common/inlineChat.js';
import { localize2WithPath, localizeWithPath } from '../../../../nls.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.service.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import '../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.service.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { fromNow } from '../../../../base/common/date.js';
import { IInlineChatSessionService } from './inlineChatSessionService.service.js';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../platform/accessibility/common/accessibility.js';
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';
import { IPreferencesService } from '../../../services/preferences/common/preferences.service.js';
import { ILogService } from '../../../../platform/log/common/log.service.js';
import { IChatService } from '../../chat/common/chatService.service.js';
const _moduleId = "vs/workbench/contrib/inlineChat/browser/inlineChatActions";
CommandsRegistry.registerCommandAlias('interactiveEditor.start', 'inlineChat.start');
CommandsRegistry.registerCommandAlias('interactive.acceptChanges', ACTION_ACCEPT_CHANGES);
const LOCALIZED_START_INLINE_CHAT_STRING = ( localize2WithPath(_moduleId, 0, 'Start in Editor'));
const START_INLINE_CHAT = registerIcon('start-inline-chat', Codicon.sparkle, ( localizeWithPath(_moduleId, 1, 'Icon which spawns the inline chat from the editor toolbar.')));
class StartSessionAction extends EditorAction2 {
    constructor() {
        super({
            id: 'inlineChat.start',
            title: LOCALIZED_START_INLINE_CHAT_STRING,
            category: AbstractInlineChatAction.category,
            f1: true,
            precondition: ( (ContextKeyExpr.and(CTX_INLINE_CHAT_HAS_AGENT, EditorContextKeys.writable))),
            keybinding: {
                when: EditorContextKeys.focus,
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.CtrlCmd | KeyCode.KeyI,
                secondary: [KeyChord(KeyMod$1.CtrlCmd | KeyCode.KeyK, KeyCode.KeyI)],
            },
            icon: START_INLINE_CHAT
        });
    }
    runEditorCommand(accessor, editor, ..._args) {
        const ctrl = InlineChatController.get(editor);
        if (!ctrl) {
            return;
        }
        let options;
        const arg = _args[0];
        if (arg && InlineChatRunOptions.isInlineChatRunOptions(arg)) {
            options = arg;
        }
        InlineChatController.get(editor)?.run({ ...options });
    }
}
class UnstashSessionAction extends EditorAction2 {
    constructor() {
        super({
            id: 'inlineChat.unstash',
            title: ( localize2WithPath(_moduleId, 2, "Resume Last Dismissed Inline Chat")),
            category: AbstractInlineChatAction.category,
            precondition: ( (ContextKeyExpr.and(CTX_INLINE_CHAT_HAS_STASHED_SESSION, EditorContextKeys.writable))),
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.CtrlCmd | KeyCode.KeyZ,
            }
        });
    }
    async runEditorCommand(_accessor, editor, ..._args) {
        const ctrl = InlineChatController.get(editor);
        if (ctrl) {
            const session = ctrl.unstashLastSession();
            if (session) {
                ctrl.run({
                    existingSession: session,
                    isUnstashed: true
                });
            }
        }
    }
}
class AbstractInlineChatAction extends EditorAction2 {
    static { this.category = ( localize2WithPath(_moduleId, 3, "Inline Chat")); }
    constructor(desc) {
        super({
            ...desc,
            category: AbstractInlineChatAction.category,
            precondition: ( (ContextKeyExpr.and(CTX_INLINE_CHAT_HAS_AGENT, desc.precondition)))
        });
    }
    runEditorCommand(accessor, editor, ..._args) {
        const editorService = accessor.get(IEditorService);
        const logService = accessor.get(ILogService);
        let ctrl = InlineChatController.get(editor);
        if (!ctrl) {
            const { activeTextEditorControl } = editorService;
            if (isCodeEditor(activeTextEditorControl)) {
                editor = activeTextEditorControl;
            }
            else if (isDiffEditor(activeTextEditorControl)) {
                editor = activeTextEditorControl.getModifiedEditor();
            }
            ctrl = InlineChatController.get(editor);
        }
        if (!ctrl) {
            logService.warn('[IE] NO controller found for action', this.desc.id, editor.getModel()?.uri);
            return;
        }
        if (editor instanceof EmbeddedCodeEditorWidget) {
            editor = editor.getParentEditor();
        }
        if (!ctrl) {
            for (const diffEditor of accessor.get(ICodeEditorService).listDiffEditors()) {
                if (diffEditor.getOriginalEditor() === editor || diffEditor.getModifiedEditor() === editor) {
                    if (diffEditor instanceof EmbeddedDiffEditorWidget) {
                        this.runEditorCommand(accessor, diffEditor.getParentEditor(), ..._args);
                    }
                }
            }
            return;
        }
        this.runInlineChatCommand(accessor, ctrl, editor, ..._args);
    }
}
class ArrowOutUpAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.arrowOutUp',
            title: ( localizeWithPath(_moduleId, 4, 'Cursor Up')),
            precondition: ( (ContextKeyExpr.and(
                CTX_INLINE_CHAT_FOCUSED,
                CTX_INLINE_CHAT_INNER_CURSOR_FIRST,
                 (EditorContextKeys.isEmbeddedDiffEditor.negate()),
                 (CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate())
            ))),
            keybinding: {
                weight: KeybindingWeight.EditorCore,
                primary: KeyMod$1.CtrlCmd | KeyCode.UpArrow
            }
        });
    }
    runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        ctrl.arrowOut(true);
    }
}
class ArrowOutDownAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.arrowOutDown',
            title: ( localizeWithPath(_moduleId, 5, 'Cursor Down')),
            precondition: ( (ContextKeyExpr.and(
                CTX_INLINE_CHAT_FOCUSED,
                CTX_INLINE_CHAT_INNER_CURSOR_LAST,
                 (EditorContextKeys.isEmbeddedDiffEditor.negate()),
                 (CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate())
            ))),
            keybinding: {
                weight: KeybindingWeight.EditorCore,
                primary: KeyMod$1.CtrlCmd | KeyCode.DownArrow
            }
        });
    }
    runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        ctrl.arrowOut(false);
    }
}
class FocusInlineChat extends EditorAction2 {
    constructor() {
        super({
            id: 'inlineChat.focus',
            title: ( localize2WithPath(_moduleId, 6, "Focus Input")),
            f1: true,
            category: AbstractInlineChatAction.category,
            precondition: ( (ContextKeyExpr.and(
                EditorContextKeys.editorTextFocus,
                CTX_INLINE_CHAT_VISIBLE,
                 (CTX_INLINE_CHAT_FOCUSED.negate()),
                 (CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate())
            ))),
            keybinding: [{
                    weight: KeybindingWeight.EditorCore + 10,
                    when: ( (ContextKeyExpr.and(
                         (CTX_INLINE_CHAT_OUTER_CURSOR_POSITION.isEqualTo('above')),
                         (EditorContextKeys.isEmbeddedDiffEditor.negate())
                    ))),
                    primary: KeyMod$1.CtrlCmd | KeyCode.DownArrow,
                }, {
                    weight: KeybindingWeight.EditorCore + 10,
                    when: ( (ContextKeyExpr.and(
                         (CTX_INLINE_CHAT_OUTER_CURSOR_POSITION.isEqualTo('below')),
                         (EditorContextKeys.isEmbeddedDiffEditor.negate())
                    ))),
                    primary: KeyMod$1.CtrlCmd | KeyCode.UpArrow,
                }]
        });
    }
    runEditorCommand(_accessor, editor, ..._args) {
        InlineChatController.get(editor)?.focus();
    }
}
class DiscardAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.discard',
            title: ( localizeWithPath(_moduleId, 7, 'Discard')),
            icon: Codicon.discard,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            keybinding: {
                weight: KeybindingWeight.EditorContrib - 1,
                primary: KeyCode.Escape,
                when: ( (CTX_INLINE_CHAT_USER_DID_EDIT.negate()))
            }
        });
    }
    async runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        await ctrl.cancelSession();
    }
}
class AcceptChanges extends AbstractInlineChatAction {
    constructor() {
        super({
            id: ACTION_ACCEPT_CHANGES,
            title: ( localize2WithPath(_moduleId, 8, "Accept Changes")),
            shortTitle: ( localizeWithPath(_moduleId, 9, 'Accept')),
            icon: Codicon.check,
            f1: true,
            precondition: ( (ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE,  (ContextKeyExpr.or(
                 (CTX_INLINE_CHAT_DOCUMENT_CHANGED.toNegated()),
                 (CTX_INLINE_CHAT_EDIT_MODE.notEqualsTo(EditMode.Preview))
            ))))),
            keybinding: [{
                    weight: KeybindingWeight.WorkbenchContrib + 10,
                    primary: KeyMod$1.CtrlCmd | KeyCode.Enter,
                }],
            menu: {
                id: MENU_INLINE_CHAT_WIDGET_STATUS,
                group: '0_main',
                order: 1,
                when: ( (ContextKeyExpr.and(
                     (CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.toNegated()),
                     (CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.MessagesAndEdits))
                ))),
            }
        });
    }
    async runInlineChatCommand(_accessor, ctrl) {
        ctrl.acceptHunk();
    }
}
class DiscardHunkAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.discardHunkChange',
            title: ( localizeWithPath(_moduleId, 7, 'Discard')),
            icon: Codicon.clearAll,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            menu: {
                id: MENU_INLINE_CHAT_WIDGET_STATUS,
                group: '0_main',
                order: 2,
                when: ( (ContextKeyExpr.and(
                     (CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate()),
                     (CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.MessagesAndEdits)),
                     (CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Live))
                ))),
            },
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyCode.Escape,
                when: ( (CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.MessagesAndEdits)))
            }
        });
    }
    async runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        return ctrl.discardHunk();
    }
}
class RerunAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: ACTION_REGENERATE_RESPONSE,
            title: ( localize2WithPath(_moduleId, 10, "Rerun Request")),
            shortTitle: ( localizeWithPath(_moduleId, 11, 'Rerun')),
            f1: false,
            icon: Codicon.refresh,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            menu: {
                id: MENU_INLINE_CHAT_WIDGET_STATUS,
                group: '0_main',
                order: 5,
                when: ( (ContextKeyExpr.and(
                     (CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate()),
                     (CTX_INLINE_CHAT_RESPONSE_TYPE.notEqualsTo(InlineChatResponseType.None))
                )))
            },
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.CtrlCmd | KeyCode.KeyR
            }
        });
    }
    async runInlineChatCommand(accessor, ctrl, _editor, ..._args) {
        const chatService = accessor.get(IChatService);
        const model = ctrl.chatWidget.viewModel?.model;
        const lastRequest = model?.getRequests().at(-1);
        if (lastRequest) {
            await chatService.resendRequest(lastRequest, { noCommandDetection: false, attempt: lastRequest.attempt + 1, location: ctrl.chatWidget.location });
        }
    }
}
class CloseAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.close',
            title: ( localizeWithPath(_moduleId, 12, 'Close')),
            icon: Codicon.close,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyCode.Escape,
            },
            menu: [{
                    id: MENU_INLINE_CHAT_CONTENT_STATUS,
                    group: '0_main',
                    order: 10,
                }, {
                    id: MENU_INLINE_CHAT_WIDGET_STATUS,
                    group: '0_main',
                    order: 1,
                    when: ( (ContextKeyExpr.and(
                         (CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate()),
                         (ContextKeyExpr.or(
                             (CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.Messages)),
                             (CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Preview))
                        ))
                    ))),
                }]
        });
    }
    async runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        ctrl.cancelSession();
    }
}
class ConfigureInlineChatAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.configure',
            title: ( localize2WithPath(_moduleId, 13, 'Configure Inline Chat')),
            icon: Codicon.settingsGear,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            f1: true,
            menu: {
                id: MENU_INLINE_CHAT_WIDGET_STATUS,
                group: 'zzz',
                order: 5
            }
        });
    }
    async runInlineChatCommand(accessor, ctrl, _editor, ..._args) {
        accessor.get(IPreferencesService).openSettings({ query: 'inlineChat' });
    }
}
class MoveToNextHunk extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.moveToNextHunk',
            title: ( localize2WithPath(_moduleId, 14, 'Move to Next Change')),
            precondition: CTX_INLINE_CHAT_VISIBLE,
            f1: true,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyCode.F7
            }
        });
    }
    runInlineChatCommand(accessor, ctrl, editor, ...args) {
        ctrl.moveHunk(true);
    }
}
class MoveToPreviousHunk extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.moveToPreviousHunk',
            title: ( localize2WithPath(_moduleId, 15, 'Move to Previous Change')),
            f1: true,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.Shift | KeyCode.F7
            }
        });
    }
    runInlineChatCommand(accessor, ctrl, editor, ...args) {
        ctrl.moveHunk(false);
    }
}
class CopyRecordings extends AbstractInlineChatAction {
    constructor() {
        super({
            id: 'inlineChat.copyRecordings',
            f1: true,
            title: ( localize2WithPath(_moduleId, 16, "(Developer) Write Exchange to Clipboard"))
        });
    }
    async runInlineChatCommand(accessor) {
        const clipboardService = accessor.get(IClipboardService);
        const quickPickService = accessor.get(IQuickInputService);
        const ieSessionService = accessor.get(IInlineChatSessionService);
        const recordings = ieSessionService.recordings().filter(r => r.exchanges.length > 0);
        if (recordings.length === 0) {
            return;
        }
        const picks = ( (recordings.map(rec => {
            return {
                rec,
                label: ( localizeWithPath(
                    _moduleId,
                    17,
                    "'{0}' and {1} follow ups ({2})",
                    rec.exchanges[0].prompt,
                    rec.exchanges.length - 1,
                    fromNow(rec.when, true)
                )),
                tooltip: ( (rec.exchanges.map(ex => ex.prompt))).join('\n'),
            };
        })));
        const pick = await quickPickService.pick(picks, { canPickMany: false });
        if (pick) {
            clipboardService.writeText(JSON.stringify(pick.rec, undefined, 2));
        }
    }
}
class ViewInChatAction extends AbstractInlineChatAction {
    constructor() {
        super({
            id: ACTION_VIEW_IN_CHAT,
            title: ( localizeWithPath(_moduleId, 18, 'View in Chat')),
            icon: Codicon.commentDiscussion,
            precondition: CTX_INLINE_CHAT_VISIBLE,
            menu: [{
                    id: MENU_INLINE_CHAT_WIDGET_STATUS,
                    group: 'more',
                    order: 1,
                    when: ( (CTX_INLINE_CHAT_RESPONSE_TYPE.notEqualsTo(InlineChatResponseType.Messages)))
                }, {
                    id: MENU_INLINE_CHAT_WIDGET_STATUS,
                    group: '0_main',
                    order: 1,
                    when: ( (ContextKeyExpr.and(
                         (CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.Messages)),
                         (CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate())
                    )))
                }],
            keybinding: {
                weight: KeybindingWeight.WorkbenchContrib,
                primary: KeyMod$1.CtrlCmd | KeyCode.DownArrow,
            }
        });
    }
    runInlineChatCommand(_accessor, ctrl, _editor, ..._args) {
        return ctrl.viewInChat();
    }
}
class ToggleDiffForChange extends AbstractInlineChatAction {
    constructor() {
        super({
            id: ACTION_TOGGLE_DIFF,
            precondition: ( (ContextKeyExpr.and(
                CTX_INLINE_CHAT_VISIBLE,
                 (CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Live)),
                CTX_INLINE_CHAT_CHANGE_HAS_DIFF
            ))),
            title: ( localize2WithPath(_moduleId, 19, 'Toggle Changes')),
            icon: Codicon.diffSingle,
            toggled: {
                condition: CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF,
            },
            menu: {
                id: MENU_INLINE_CHAT_WIDGET_STATUS,
                group: 'zzz',
                when: ( (ContextKeyExpr.and( (CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Live))))),
                order: 1,
            }
        });
    }
    runInlineChatCommand(accessor, ctrl) {
        ctrl.toggleDiff();
    }
}
export { AbstractInlineChatAction, AcceptChanges, ArrowOutDownAction, ArrowOutUpAction, CloseAction, ConfigureInlineChatAction, CopyRecordings, DiscardAction, DiscardHunkAction, FocusInlineChat, LOCALIZED_START_INLINE_CHAT_STRING, MoveToNextHunk, MoveToPreviousHunk, RerunAction, START_INLINE_CHAT, StartSessionAction, ToggleDiffForChange, UnstashSessionAction, ViewInChatAction };
