import { Disposable } from '../../../../base/common/lifecycle.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { localizeWithPath } from '../../../../nls.js';
import { accessibleViewIsShown } from './accessibilityConfiguration.js';
import { format } from '../../../../base/common/strings.js';
import { ICommandService } from '../../../../platform/commands/common/commands.service.js';
import { HoverController } from '../../../../editor/contrib/hover/browser/hover.js';
import { IContextViewService } from '../../../../platform/contextview/browser/contextView.service.js';
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
import { getNotificationFromContext } from '../../../browser/parts/notifications/notificationsCommands.js';
import { WorkbenchList } from '../../../../platform/list/browser/listService.js';
import { IListService } from '../../../../platform/list/browser/listService.service.js';
import { NotificationFocusedContext } from '../../../common/contextkeys.js';
import { IAccessibleViewService } from './accessibleView.service.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.service.js';
import { alert } from '../../../../base/browser/ui/aria/aria.js';
import { AccessibleViewAction, AccessibilityHelpAction } from './accessibleViewActions.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { InlineCompletionsController } from '../../../../editor/contrib/inlineCompletions/browser/inlineCompletionsController.js';
import '../../../../editor/contrib/inlineCompletions/browser/inlineCompletionContextKeys.js';
import '../../../../platform/contextkey/common/contextkey.js';
import { AccessibilitySignal } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js';
import { IAccessibilitySignalService } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.service.js';
const _moduleId = "vs/workbench/contrib/accessibility/browser/accessibilityContributions";
function descriptionForCommand(commandId, msg, noKbMsg, keybindingService) {
    const kb = keybindingService.lookupKeybinding(commandId);
    if (kb) {
        return format(msg, kb.getAriaLabel());
    }
    return format(noKbMsg, commandId);
}
class HoverAccessibleViewContribution extends Disposable {
    constructor() {
        super();
        this._options = { language: 'typescript', type: "view"  };
        this._register(AccessibleViewAction.addImplementation(95, 'hover', accessor => {
            const accessibleViewService = accessor.get(IAccessibleViewService);
            const codeEditorService = accessor.get(ICodeEditorService);
            const editor = codeEditorService.getActiveCodeEditor() || codeEditorService.getFocusedCodeEditor();
            const editorHoverContent = editor ? HoverController.get(editor)?.getWidgetContent() ?? undefined : undefined;
            if (!editor || !editorHoverContent) {
                return false;
            }
            this._options.language = editor?.getModel()?.getLanguageId() ?? undefined;
            accessibleViewService.show({
                id: "hover" ,
                verbositySettingKey: "accessibility.verbosity.hover" ,
                provideContent() { return editorHoverContent; },
                onClose() {
                    HoverController.get(editor)?.focus();
                },
                options: this._options
            });
            return true;
        }, EditorContextKeys.hoverFocused));
        this._register(AccessibleViewAction.addImplementation(90, 'extension-hover', accessor => {
            const accessibleViewService = accessor.get(IAccessibleViewService);
            const contextViewService = accessor.get(IContextViewService);
            const contextViewElement = contextViewService.getContextViewElement();
            const extensionHoverContent = contextViewElement?.textContent ?? undefined;
            const hoverService = accessor.get(IHoverService);
            if (contextViewElement.classList.contains('accessible-view-container') || !extensionHoverContent) {
                return false;
            }
            accessibleViewService.show({
                id: "hover" ,
                verbositySettingKey: "accessibility.verbosity.hover" ,
                provideContent() { return extensionHoverContent; },
                onClose() {
                    hoverService.showAndFocusLastHover();
                },
                options: this._options
            });
            return true;
        }));
        this._register(AccessibilityHelpAction.addImplementation(115, 'accessible-view', accessor => {
            accessor.get(IAccessibleViewService).showAccessibleViewHelp();
            return true;
        }, accessibleViewIsShown));
    }
}
class NotificationAccessibleViewContribution extends Disposable {
    constructor() {
        super();
        this._register(AccessibleViewAction.addImplementation(90, 'notifications', accessor => {
            const accessibleViewService = accessor.get(IAccessibleViewService);
            const listService = accessor.get(IListService);
            const commandService = accessor.get(ICommandService);
            const accessibilitySignalService = accessor.get(IAccessibilitySignalService);
            function renderAccessibleView() {
                const notification = getNotificationFromContext(listService);
                if (!notification) {
                    return false;
                }
                commandService.executeCommand('notifications.showList');
                let notificationIndex;
                let length;
                const list = listService.lastFocusedList;
                if (list instanceof WorkbenchList) {
                    notificationIndex = list.indexOf(notification);
                    length = list.length;
                }
                if (notificationIndex === undefined) {
                    return false;
                }
                function focusList() {
                    commandService.executeCommand('notifications.showList');
                    if (list && notificationIndex !== undefined) {
                        list.domFocus();
                        try {
                            list.setFocus([notificationIndex]);
                        }
                        catch { }
                    }
                }
                const message = ( (notification.message.original.toString()));
                if (!message) {
                    return false;
                }
                notification.onDidClose(() => accessibleViewService.next());
                accessibleViewService.show({
                    id: "notification" ,
                    provideContent: () => {
                        return notification.source ? ( localizeWithPath(_moduleId, 0, '{0} Source: {1}', message, notification.source)) : ( localizeWithPath(_moduleId, 1, '{0}', message));
                    },
                    onClose() {
                        focusList();
                    },
                    next() {
                        if (!list) {
                            return;
                        }
                        focusList();
                        list.focusNext();
                        alertFocusChange(notificationIndex, length, 'next');
                        renderAccessibleView();
                    },
                    previous() {
                        if (!list) {
                            return;
                        }
                        focusList();
                        list.focusPrevious();
                        alertFocusChange(notificationIndex, length, 'previous');
                        renderAccessibleView();
                    },
                    verbositySettingKey: "accessibility.verbosity.notification" ,
                    options: { type: "view"  },
                    actions: getActionsFromNotification(notification, accessibilitySignalService)
                });
                return true;
            }
            return renderAccessibleView();
        }, NotificationFocusedContext));
    }
}
function getActionsFromNotification(notification, accessibilitySignalService) {
    let actions = undefined;
    if (notification.actions) {
        actions = [];
        if (notification.actions.primary) {
            actions.push(...notification.actions.primary);
        }
        if (notification.actions.secondary) {
            actions.push(...notification.actions.secondary);
        }
    }
    if (actions) {
        for (const action of actions) {
            action.class = ThemeIcon.asClassName(Codicon.bell);
            const initialAction = action.run;
            action.run = () => {
                initialAction();
                notification.close();
            };
        }
    }
    const manageExtension = actions?.find(a => a.label.includes('Manage Extension'));
    if (manageExtension) {
        manageExtension.class = ThemeIcon.asClassName(Codicon.gear);
    }
    if (actions) {
        actions.push({
            id: 'clearNotification', label: ( localizeWithPath(_moduleId, 2, "Clear Notification")), tooltip: ( localizeWithPath(_moduleId, 2, "Clear Notification")), run: () => {
                notification.close();
                accessibilitySignalService.playSignal(AccessibilitySignal.clear);
            }, enabled: true, class: ThemeIcon.asClassName(Codicon.clearAll)
        });
    }
    return actions;
}
function alertFocusChange(index, length, type) {
    if (index === undefined || length === undefined) {
        return;
    }
    const number = index + 1;
    if (type === 'next' && number + 1 <= length) {
        alert(`Focused ${number + 1} of ${length}`);
    }
    else if (type === 'previous' && number - 1 > 0) {
        alert(`Focused ${number - 1} of ${length}`);
    }
    return;
}
class InlineCompletionsAccessibleViewContribution extends Disposable {
    constructor() {
        super();
        this._options = { type: "view"  };
        this._register(AccessibleViewAction.addImplementation(95, 'inline-completions', accessor => {
            const accessibleViewService = accessor.get(IAccessibleViewService);
            const codeEditorService = accessor.get(ICodeEditorService);
            const show = () => {
                const editor = codeEditorService.getActiveCodeEditor() || codeEditorService.getFocusedCodeEditor();
                if (!editor) {
                    return false;
                }
                const model = InlineCompletionsController.get(editor)?.model.get();
                const state = model?.state.get();
                if (!model || !state) {
                    return false;
                }
                const lineText = model.textModel.getLineContent(state.primaryGhostText.lineNumber);
                const ghostText = state.primaryGhostText.renderForScreenReader(lineText);
                if (!ghostText) {
                    return false;
                }
                this._options.language = editor.getModel()?.getLanguageId() ?? undefined;
                accessibleViewService.show({
                    id: "inlineCompletions" ,
                    verbositySettingKey: "accessibility.verbosity.inlineCompletions" ,
                    provideContent() { return lineText + ghostText; },
                    onClose() {
                        model.stop();
                        editor.focus();
                    },
                    next() {
                        model.next();
                        setTimeout(() => show(), 50);
                    },
                    previous() {
                        model.previous();
                        setTimeout(() => show(), 50);
                    },
                    options: this._options
                });
                return true;
            };
            return show();
        }));
    }
}
export { HoverAccessibleViewContribution, InlineCompletionsAccessibleViewContribution, NotificationAccessibleViewContribution, alertFocusChange, descriptionForCommand };
