
import { registerCss } from '../../../../../../../css.js';
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { clearNode, $, append } from '../../../../base/browser/dom.js';
import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js';
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js';
import { Action, Separator } from '../../../../base/common/actions.js';
import { isNonEmptyArray } from '../../../../base/common/arrays.js';
import { RunOnceScheduler } from '../../../../base/common/async.js';
import { fromNow } from '../../../../base/common/date.js';
import { dispose } from '../../../../base/common/lifecycle.js';
import { Schemas } from '../../../../base/common/network.js';
import { localize, localize2 } from '../../../../nls.js';
import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';
import { getContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { MenuId, Action2 } from '../../../../platform/actions/common/actions.js';
import { IMenuService } from '../../../../platform/actions/common/actions.service.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.service.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.service.js';
import { ExtensionIdentifierMap } from '../../../../platform/extensions/common/extensions.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.service.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ILabelService } from '../../../../platform/label/common/label.service.js';
import { WorkbenchList } from '../../../../platform/list/browser/listService.js';
import '../../../../platform/notification/common/notification.js';
import { INotificationService } from '../../../../platform/notification/common/notification.service.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { IStorageService } from '../../../../platform/storage/common/storage.service.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.service.js';
import '../../../../platform/theme/common/colorUtils.js';
import '../../../../platform/theme/common/colors/baseColors.js';
import '../../../../platform/theme/common/colors/chartsColors.js';
import { editorBackground } from '../../../../platform/theme/common/colors/editorColors.js';
import '../../../../platform/theme/common/colors/inputColors.js';
import '../../../../platform/theme/common/colors/listColors.js';
import '../../../../platform/theme/common/colors/menuColors.js';
import '../../../../platform/theme/common/colors/minimapColors.js';
import '../../../../platform/theme/common/colors/miscColors.js';
import '../../../../platform/theme/common/colors/quickpickColors.js';
import '../../../../platform/theme/common/colors/searchColors.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.service.js';
import { EditorPane } from '../../../browser/parts/editor/editorPane.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.service.js';
import { Extensions } from '../../../services/extensionManagement/common/extensionFeatures.js';
import { IExtensionFeaturesManagementService } from '../../../services/extensionManagement/common/extensionFeatures.service.js';
import { EnablementState } from '../../../services/extensionManagement/common/extensionManagement.js';
import { LocalWebWorkerRunningLocation } from '../../../services/extensions/common/extensionRunningLocation.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.service.js';
import { IExtensionsWorkbenchService } from '../common/extensions.service.js';
import { RuntimeExtensionsInput } from '../common/runtimeExtensionsInput.js';
import { errorIcon, warningIcon } from './extensionsIcons.js';
import { ExtensionIconWidget } from './extensionsWidgets.js';
import * as runtimeExtensionsEditor from './media/runtimeExtensionsEditor.css';
import Severity$1 from '../../../../base/common/severity.js';

var AbstractRuntimeExtensionsEditor_1;
registerCss(runtimeExtensionsEditor);
let AbstractRuntimeExtensionsEditor = class AbstractRuntimeExtensionsEditor extends EditorPane {
    static {
        AbstractRuntimeExtensionsEditor_1 = this;
    }
    static {
        this.ID = "workbench.editor.runtimeExtensions";
    }
    constructor(
        group,
        telemetryService,
        themeService,
        contextKeyService,
        _extensionsWorkbenchService,
        _extensionService,
        _notificationService,
        _contextMenuService,
        _instantiationService,
        storageService,
        _labelService,
        _environmentService,
        _clipboardService,
        _extensionFeaturesManagementService,
        _hoverService,
        _menuService
    ) {
        super(
            AbstractRuntimeExtensionsEditor_1.ID,
            group,
            telemetryService,
            themeService,
            storageService
        );
        this.contextKeyService = contextKeyService;
        this._extensionsWorkbenchService = _extensionsWorkbenchService;
        this._extensionService = _extensionService;
        this._notificationService = _notificationService;
        this._contextMenuService = _contextMenuService;
        this._instantiationService = _instantiationService;
        this._labelService = _labelService;
        this._environmentService = _environmentService;
        this._clipboardService = _clipboardService;
        this._extensionFeaturesManagementService = _extensionFeaturesManagementService;
        this._hoverService = _hoverService;
        this._menuService = _menuService;
        this._list = null;
        this._elements = null;
        this._updateSoon = this._register(( new RunOnceScheduler(() => this._updateExtensions(), 200)));
        this._register(
            this._extensionService.onDidChangeExtensionsStatus(() => this._updateSoon.schedule())
        );
        this._register(
            this._extensionFeaturesManagementService.onDidChangeAccessData(() => this._updateSoon.schedule())
        );
        this._updateExtensions();
    }
    async _updateExtensions() {
        this._elements = await this._resolveExtensions();
        this._list?.splice(0, this._list.length, this._elements);
    }
    async _resolveExtensions() {
        await this._extensionService.whenInstalledExtensionsRegistered();
        const extensionsDescriptions = this._extensionService.extensions.filter(extension => {
            return Boolean(extension.main) || Boolean(extension.browser);
        });
        const marketplaceMap = ( new ExtensionIdentifierMap());
        const marketPlaceExtensions = await this._extensionsWorkbenchService.queryLocal();
        for (const extension of marketPlaceExtensions) {
            marketplaceMap.set(extension.identifier.id, extension);
        }
        const statusMap = this._extensionService.getExtensionsStatus();
        const segments = ( new ExtensionIdentifierMap());
        const profileInfo = this._getProfileInfo();
        if (profileInfo) {
            let currentStartTime = profileInfo.startTime;
            for (let i = 0, len = profileInfo.deltas.length; i < len; i++) {
                const id = profileInfo.ids[i];
                const delta = profileInfo.deltas[i];
                let extensionSegments = segments.get(id);
                if (!extensionSegments) {
                    extensionSegments = [];
                    segments.set(id, extensionSegments);
                }
                extensionSegments.push(currentStartTime);
                currentStartTime = currentStartTime + delta;
                extensionSegments.push(currentStartTime);
            }
        }
        let result = [];
        for (let i = 0, len = extensionsDescriptions.length; i < len; i++) {
            const extensionDescription = extensionsDescriptions[i];
            let extProfileInfo = null;
            if (profileInfo) {
                const extensionSegments = segments.get(extensionDescription.identifier) || [];
                let extensionTotalTime = 0;
                for (let j = 0, lenJ = extensionSegments.length / 2; j < lenJ; j++) {
                    const startTime = extensionSegments[2 * j];
                    const endTime = extensionSegments[2 * j + 1];
                    extensionTotalTime += (endTime - startTime);
                }
                extProfileInfo = {
                    segments: extensionSegments,
                    totalTime: extensionTotalTime
                };
            }
            result[i] = {
                originalIndex: i,
                description: extensionDescription,
                marketplaceInfo: marketplaceMap.get(extensionDescription.identifier),
                status: statusMap[extensionDescription.identifier.value],
                profileInfo: extProfileInfo || undefined,
                unresponsiveProfile: this._getUnresponsiveProfile(extensionDescription.identifier)
            };
        }
        result = result.filter(element => element.status.activationStarted);
        const isUnresponsive = extension => extension.unresponsiveProfile === profileInfo;
        const profileTime = extension => extension.profileInfo?.totalTime ?? 0;
        const activationTime = extension => (extension.status.activationTimes?.codeLoadingTime ?? 0) + (extension.status.activationTimes?.activateCallTime ?? 0);
        result = result.sort((a, b) => {
            if (isUnresponsive(a) || isUnresponsive(b)) {
                return +isUnresponsive(b) - +isUnresponsive(a);
            } else if (profileTime(a) || profileTime(b)) {
                return profileTime(b) - profileTime(a);
            } else if (activationTime(a) || activationTime(b)) {
                return activationTime(b) - activationTime(a);
            }
            return a.originalIndex - b.originalIndex;
        });
        return result;
    }
    createEditor(parent) {
        parent.classList.add("runtime-extensions-editor");
        const TEMPLATE_ID = "runtimeExtensionElementTemplate";
        const delegate = new class {
            getHeight(element) {
                return 70;
            }
            getTemplateId(element) {
                return TEMPLATE_ID;
            }
        }();
        const renderer = {
            templateId: TEMPLATE_ID,
            renderTemplate: root => {
                const element = append(root, $(".extension"));
                const iconContainer = append(element, $(".icon-container"));
                const extensionIconWidget = this._instantiationService.createInstance(ExtensionIconWidget, iconContainer);
                const desc = append(element, $("div.desc"));
                const headerContainer = append(desc, $(".header-container"));
                const header = append(headerContainer, $(".header"));
                const name = append(header, $("div.name"));
                const version = append(header, $("span.version"));
                const msgContainer = append(desc, $("div.msg"));
                const actionbar = ( new ActionBar(desc));
                const listener = actionbar.onDidRun((
                    {
                        error
                    }
                ) => error && this._notificationService.error(error));
                const timeContainer = append(element, $(".time"));
                const activationTime = append(timeContainer, $("div.activation-time"));
                const profileTime = append(timeContainer, $("div.profile-time"));
                const disposables = [extensionIconWidget, actionbar, listener];
                return {
                    root,
                    element,
                    name,
                    version,
                    actionbar,
                    activationTime,
                    profileTime,
                    msgContainer,
                    set extension(extension) {
                        extensionIconWidget.extension = extension || null;
                    },
                    disposables,
                    elementDisposables: []
                };
            },
            renderElement: (element, index, data) => {
                data.elementDisposables = dispose(data.elementDisposables);
                data.extension = element.marketplaceInfo;
                data.root.classList.toggle("odd", index % 2 === 1);
                data.name.textContent = (element.marketplaceInfo?.displayName || element.description.identifier.value).substr(0, 50);
                data.version.textContent = element.description.version;
                const activationTimes = element.status.activationTimes;
                if (activationTimes) {
                    const syncTime = activationTimes.codeLoadingTime + activationTimes.activateCallTime;
                    data.activationTime.textContent = activationTimes.activationReason.startup ? `Startup Activation: ${syncTime}ms` : `Activation: ${syncTime}ms`;
                } else {
                    data.activationTime.textContent = `Activating...`;
                }
                data.actionbar.clear();
                const slowExtensionAction = this._createSlowExtensionAction(element);
                if (slowExtensionAction) {
                    data.actionbar.push(slowExtensionAction, {
                        icon: false,
                        label: true
                    });
                }
                if (isNonEmptyArray(element.status.runtimeErrors)) {
                    const reportExtensionIssueAction = this._createReportExtensionIssueAction(element);
                    if (reportExtensionIssueAction) {
                        data.actionbar.push(reportExtensionIssueAction, {
                            icon: false,
                            label: true
                        });
                    }
                }
                let title;
                if (activationTimes) {
                    const activationId = activationTimes.activationReason.extensionId.value;
                    const activationEvent = activationTimes.activationReason.activationEvent;
                    if (activationEvent === "*") {
                        title = ( localize(8810, "Activated by {0} on start-up", activationId));
                    } else if (/^workspaceContains:/.test(activationEvent)) {
                        const fileNameOrGlob = activationEvent.substr("workspaceContains:".length);
                        if (fileNameOrGlob.indexOf("*") >= 0 || fileNameOrGlob.indexOf("?") >= 0) {
                            title = ( localize(
                                8811,
                                "Activated by {1} because a file matching {0} exists in your workspace",
                                fileNameOrGlob,
                                activationId
                            ));
                        } else {
                            title = ( localize(
                                8812,
                                "Activated by {1} because file {0} exists in your workspace",
                                fileNameOrGlob,
                                activationId
                            ));
                        }
                    } else if (/^workspaceContainsTimeout:/.test(activationEvent)) {
                        const glob = activationEvent.substr("workspaceContainsTimeout:".length);
                        title = ( localize(
                            8813,
                            "Activated by {1} because searching for {0} took too long",
                            glob,
                            activationId
                        ));
                    } else if (activationEvent === "onStartupFinished") {
                        title = ( localize(8814, "Activated by {0} after start-up finished", activationId));
                    } else if (/^onLanguage:/.test(activationEvent)) {
                        const language = activationEvent.substr("onLanguage:".length);
                        title = ( localize(
                            8815,
                            "Activated by {1} because you opened a {0} file",
                            language,
                            activationId
                        ));
                    } else {
                        title = ( localize(8816, "Activated by {1} on {0}", activationEvent, activationId));
                    }
                } else {
                    title = ( localize(8817, "Extension is activating..."));
                }
                data.elementDisposables.push(
                    this._hoverService.setupManagedHover(getDefaultHoverDelegate("mouse"), data.activationTime, title)
                );
                clearNode(data.msgContainer);
                if (this._getUnresponsiveProfile(element.description.identifier)) {
                    const el = $("span", undefined, ...renderLabelWithIcons(` $(alert) Unresponsive`));
                    const extensionHostFreezTitle = ( localize(8818, "Extension has caused the extension host to freeze."));
                    data.elementDisposables.push(
                        this._hoverService.setupManagedHover(getDefaultHoverDelegate("mouse"), el, extensionHostFreezTitle)
                    );
                    data.msgContainer.appendChild(el);
                }
                if (isNonEmptyArray(element.status.runtimeErrors)) {
                    const el = $("span", undefined, ...renderLabelWithIcons(`$(bug) ${( localize(8819, "{0} uncaught errors", element.status.runtimeErrors.length))}`));
                    data.msgContainer.appendChild(el);
                }
                if (element.status.messages && element.status.messages.length > 0) {
                    const el = $(
                        "span",
                        undefined,
                        ...renderLabelWithIcons(`$(alert) ${element.status.messages[0].message}`)
                    );
                    data.msgContainer.appendChild(el);
                }
                let extraLabel = null;
                if (element.status.runningLocation && element.status.runningLocation.equals(( new LocalWebWorkerRunningLocation(0)))) {
                    extraLabel = `$(globe) web worker`;
                } else if (element.description.extensionLocation.scheme === Schemas.vscodeRemote) {
                    const hostLabel = this._labelService.getHostLabel(Schemas.vscodeRemote, this._environmentService.remoteAuthority);
                    if (hostLabel) {
                        extraLabel = `$(remote) ${hostLabel}`;
                    } else {
                        extraLabel = `$(remote) ${element.description.extensionLocation.authority}`;
                    }
                } else if (element.status.runningLocation && element.status.runningLocation.affinity > 0) {
                    extraLabel = element.status.runningLocation instanceof LocalWebWorkerRunningLocation ? `$(globe) web worker ${element.status.runningLocation.affinity + 1}` : `$(server-process) local process ${element.status.runningLocation.affinity + 1}`;
                }
                if (extraLabel) {
                    const el = $("span", undefined, ...renderLabelWithIcons(extraLabel));
                    data.msgContainer.appendChild(el);
                }
                const features = ( Registry.as(Extensions.ExtensionFeaturesRegistry)).getExtensionFeatures();
                for (const feature of features) {
                    const accessData = this._extensionFeaturesManagementService.getAccessData(element.description.identifier, feature.id);
                    if (accessData) {
                        const status = accessData?.current?.status;
                        if (status) {
                            data.msgContainer.appendChild($("span", undefined, `${feature.label}: `));
                            data.msgContainer.appendChild($("span", undefined, ...renderLabelWithIcons(
                                `$(${status.severity === Severity$1.Error ? errorIcon.id : warningIcon.id}) ${status.message}`
                            )));
                        }
                        if (accessData?.accessTimes.length > 0) {
                            const element = $("span", undefined, `${( localize(
                                8820,
                                "{0} Usage: {1} Requests",
                                feature.label,
                                accessData.accessTimes.length
                            ))}${accessData.current ? ( localize(8821, ", {0} Requests (Session)", accessData.current.accessTimes.length)) : ""}`);
                            if (accessData.current) {
                                const title = ( localize(
                                    8822,
                                    "Last request was {0}.",
                                    fromNow(accessData.current.lastAccessed, true, true)
                                ));
                                data.elementDisposables.push(
                                    this._hoverService.setupManagedHover(getDefaultHoverDelegate("mouse"), element, title)
                                );
                            }
                            data.msgContainer.appendChild(element);
                        }
                    }
                }
                if (element.profileInfo) {
                    data.profileTime.textContent = `Profile: ${(element.profileInfo.totalTime / 1000).toFixed(2)}ms`;
                } else {
                    data.profileTime.textContent = "";
                }
            },
            disposeTemplate: data => {
                data.disposables = dispose(data.disposables);
            }
        };
        this._list = this._instantiationService.createInstance(WorkbenchList, "RuntimeExtensions", parent, delegate, [renderer], {
            multipleSelectionSupport: false,
            setRowLineHeight: false,
            horizontalScrolling: false,
            overrideStyles: {
                listBackground: editorBackground
            },
            accessibilityProvider: new (class {
                getWidgetAriaLabel() {
                    return localize(8823, "Runtime Extensions");
                }
                getAriaLabel(element) {
                    return element.description.name;
                }
            })()
        });
        this._list.splice(0, this._list.length, this._elements || undefined);
        this._register(this._list.onContextMenu(e => {
            if (!e.element) {
                return;
            }
            const actions = [];
            actions.push(( new Action("runtimeExtensionsEditor.action.copyId", ( localize(8824, "Copy id ({0})", e.element.description.identifier.value)), undefined, true, () => {
                this._clipboardService.writeText(e.element.description.identifier.value);
            })));
            const reportExtensionIssueAction = this._createReportExtensionIssueAction(e.element);
            if (reportExtensionIssueAction) {
                actions.push(reportExtensionIssueAction);
            }
            actions.push(( new Separator()));
            if (e.element.marketplaceInfo) {
                actions.push(( new Action("runtimeExtensionsEditor.action.disableWorkspace", ( localize(8825, "Disable (Workspace)")), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element.marketplaceInfo, EnablementState.DisabledWorkspace))));
                actions.push(( new Action("runtimeExtensionsEditor.action.disable", ( localize(8826, "Disable")), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element.marketplaceInfo, EnablementState.DisabledGlobally))));
            }
            actions.push(( new Separator()));
            const menuActions = this._menuService.getMenuActions(MenuId.ExtensionEditorContextMenu, this.contextKeyService);
            actions.push(...getContextMenuActions(menuActions).secondary);
            this._contextMenuService.showContextMenu({
                getAnchor: () => e.anchor,
                getActions: () => actions
            });
        }));
    }
    layout(dimension) {
        this._list?.layout(dimension.height);
    }
};
AbstractRuntimeExtensionsEditor = AbstractRuntimeExtensionsEditor_1 = ( __decorate([( __param(1, ITelemetryService)), ( __param(2, IThemeService)), ( __param(3, IContextKeyService)), ( __param(4, IExtensionsWorkbenchService)), ( __param(5, IExtensionService)), ( __param(6, INotificationService)), ( __param(7, IContextMenuService)), ( __param(8, IInstantiationService)), ( __param(9, IStorageService)), ( __param(10, ILabelService)), ( __param(11, IWorkbenchEnvironmentService)), ( __param(12, IClipboardService)), ( __param(13, IExtensionFeaturesManagementService)), ( __param(14, IHoverService)), ( __param(15, IMenuService))], AbstractRuntimeExtensionsEditor));
class ShowRuntimeExtensionsAction extends Action2 {
    constructor() {
        super({
            id: "workbench.action.showRuntimeExtensions",
            title: ( localize2(8827, "Show Running Extensions")),
            category: Categories.Developer,
            f1: true,
            menu: {
                id: MenuId.ViewContainerTitle,
                when: ( ContextKeyExpr.equals("viewContainer", "workbench.view.extensions")),
                group: "2_enablement",
                order: 3
            }
        });
    }
    async run(accessor) {
        await accessor.get(IEditorService).openEditor(RuntimeExtensionsInput.instance, {
            pinned: true
        });
    }
}

export { AbstractRuntimeExtensionsEditor, ShowRuntimeExtensionsAction };
