
import { NotificationsFilter, NoOpNotification, NotificationPriority, isNotificationSource } from '../../platform/notification/common/notification.js';
import { isErrorWithActions, toErrorMessage } from '../../base/common/errorMessage.js';
import { Emitter, Event } from '../../base/common/event.js';
import { Disposable } from '../../base/common/lifecycle.js';
import { isCancellationError } from '../../base/common/errors.js';
import { Action } from '../../base/common/actions.js';
import { equals } from '../../base/common/arrays.js';
import { parseLinkedText } from '../../base/common/linkedText.js';
import { mapsStrictEqualIgnoreOrder } from '../../base/common/map.js';
import Severity$1 from '../../base/common/severity.js';

var NotificationChangeType;
(function(NotificationChangeType) {
    NotificationChangeType[NotificationChangeType["ADD"] = 0] = "ADD";
    NotificationChangeType[NotificationChangeType["CHANGE"] = 1] = "CHANGE";
    NotificationChangeType[NotificationChangeType["EXPAND_COLLAPSE"] = 2] = "EXPAND_COLLAPSE";
    NotificationChangeType[NotificationChangeType["REMOVE"] = 3] = "REMOVE";
})(NotificationChangeType || (NotificationChangeType = {}));
var StatusMessageChangeType;
(function(StatusMessageChangeType) {
    StatusMessageChangeType[StatusMessageChangeType["ADD"] = 0] = "ADD";
    StatusMessageChangeType[StatusMessageChangeType["REMOVE"] = 1] = "REMOVE";
})(StatusMessageChangeType || (StatusMessageChangeType = {}));
class NotificationHandle extends Disposable {
    constructor(item, onClose) {
        super();
        this.item = item;
        this.onClose = onClose;
        this._onDidClose = this._register(( new Emitter()));
        this.onDidClose = this._onDidClose.event;
        this._onDidChangeVisibility = this._register(( new Emitter()));
        this.onDidChangeVisibility = this._onDidChangeVisibility.event;
        this.registerListeners();
    }
    registerListeners() {
        this._register(
            this.item.onDidChangeVisibility(visible => this._onDidChangeVisibility.fire(visible))
        );
        Event.once(this.item.onDidClose)(() => {
            this._onDidClose.fire();
            this.dispose();
        });
    }
    get progress() {
        return this.item.progress;
    }
    updateSeverity(severity) {
        this.item.updateSeverity(severity);
    }
    updateMessage(message) {
        this.item.updateMessage(message);
    }
    updateActions(actions) {
        this.item.updateActions(actions);
    }
    close() {
        this.onClose(this.item);
        this.dispose();
    }
}
class NotificationsModel extends Disposable {
    constructor() {
        super(...arguments);
        this._onDidChangeNotification = this._register(( new Emitter()));
        this.onDidChangeNotification = this._onDidChangeNotification.event;
        this._onDidChangeStatusMessage = this._register(( new Emitter()));
        this.onDidChangeStatusMessage = this._onDidChangeStatusMessage.event;
        this._onDidChangeFilter = this._register(( new Emitter()));
        this.onDidChangeFilter = this._onDidChangeFilter.event;
        this._notifications = [];
        this.filter = {
            global: NotificationsFilter.OFF,
            sources: ( new Map())
        };
    }
    static {
        this.NO_OP_NOTIFICATION = ( new NoOpNotification());
    }
    get notifications() {
        return this._notifications;
    }
    get statusMessage() {
        return this._statusMessage;
    }
    setFilter(filter) {
        let globalChanged = false;
        if (typeof filter.global === "number") {
            globalChanged = this.filter.global !== filter.global;
            this.filter.global = filter.global;
        }
        let sourcesChanged = false;
        if (filter.sources) {
            sourcesChanged = !mapsStrictEqualIgnoreOrder(this.filter.sources, filter.sources);
            this.filter.sources = filter.sources;
        }
        if (globalChanged || sourcesChanged) {
            this._onDidChangeFilter.fire({
                global: globalChanged ? filter.global : undefined,
                sources: sourcesChanged ? filter.sources : undefined
            });
        }
    }
    addNotification(notification) {
        const item = this.createViewItem(notification);
        if (!item) {
            return NotificationsModel.NO_OP_NOTIFICATION;
        }
        const duplicate = this.findNotification(item);
        duplicate?.close();
        this._notifications.splice(0, 0, item);
        this._onDidChangeNotification.fire({
            item,
            index: 0,
            kind: NotificationChangeType.ADD
        });
        return ( new NotificationHandle(item, item => this.onClose(item)));
    }
    onClose(item) {
        const liveItem = this.findNotification(item);
        if (liveItem && liveItem !== item) {
            liveItem.close();
        } else {
            item.close();
        }
    }
    findNotification(item) {
        return this._notifications.find(notification => notification.equals(item));
    }
    createViewItem(notification) {
        const item = NotificationViewItem.create(notification, this.filter);
        if (!item) {
            return undefined;
        }
        const fireNotificationChangeEvent = (kind, detail) => {
            const index = this._notifications.indexOf(item);
            if (index >= 0) {
                this._onDidChangeNotification.fire({
                    item,
                    index,
                    kind,
                    detail
                });
            }
        };
        const itemExpansionChangeListener = item.onDidChangeExpansion(() => fireNotificationChangeEvent(NotificationChangeType.EXPAND_COLLAPSE));
        const itemContentChangeListener = item.onDidChangeContent(e => fireNotificationChangeEvent(NotificationChangeType.CHANGE, e.kind));
        Event.once(item.onDidClose)(() => {
            itemExpansionChangeListener.dispose();
            itemContentChangeListener.dispose();
            const index = this._notifications.indexOf(item);
            if (index >= 0) {
                this._notifications.splice(index, 1);
                this._onDidChangeNotification.fire({
                    item,
                    index,
                    kind: NotificationChangeType.REMOVE
                });
            }
        });
        return item;
    }
    showStatusMessage(message, options) {
        const item = StatusMessageViewItem.create(message, options);
        if (!item) {
            return {
                close: () => {}
            };
        }
        this._statusMessage = item;
        this._onDidChangeStatusMessage.fire({
            kind: StatusMessageChangeType.ADD,
            item
        });
        return {
            close: () => {
                if (this._statusMessage === item) {
                    this._statusMessage = undefined;
                    this._onDidChangeStatusMessage.fire({
                        kind: StatusMessageChangeType.REMOVE,
                        item
                    });
                }
            }
        };
    }
}
function isNotificationViewItem(obj) {
    return obj instanceof NotificationViewItem;
}
var NotificationViewItemContentChangeKind;
(function(NotificationViewItemContentChangeKind) {
    NotificationViewItemContentChangeKind[NotificationViewItemContentChangeKind["SEVERITY"] = 0] = "SEVERITY";
    NotificationViewItemContentChangeKind[NotificationViewItemContentChangeKind["MESSAGE"] = 1] = "MESSAGE";
    NotificationViewItemContentChangeKind[NotificationViewItemContentChangeKind["ACTIONS"] = 2] = "ACTIONS";
    NotificationViewItemContentChangeKind[NotificationViewItemContentChangeKind["PROGRESS"] = 3] = "PROGRESS";
})(
    NotificationViewItemContentChangeKind || (NotificationViewItemContentChangeKind = {})
);
class NotificationViewItemProgress extends Disposable {
    constructor() {
        super();
        this._onDidChange = this._register(( new Emitter()));
        this.onDidChange = this._onDidChange.event;
        this._state = Object.create(null);
    }
    get state() {
        return this._state;
    }
    infinite() {
        if (this._state.infinite) {
            return;
        }
        this._state.infinite = true;
        this._state.total = undefined;
        this._state.worked = undefined;
        this._state.done = undefined;
        this._onDidChange.fire();
    }
    done() {
        if (this._state.done) {
            return;
        }
        this._state.done = true;
        this._state.infinite = undefined;
        this._state.total = undefined;
        this._state.worked = undefined;
        this._onDidChange.fire();
    }
    total(value) {
        if (this._state.total === value) {
            return;
        }
        this._state.total = value;
        this._state.infinite = undefined;
        this._state.done = undefined;
        this._onDidChange.fire();
    }
    worked(value) {
        if (typeof this._state.worked === "number") {
            this._state.worked += value;
        } else {
            this._state.worked = value;
        }
        this._state.infinite = undefined;
        this._state.done = undefined;
        this._onDidChange.fire();
    }
}
class NotificationViewItem extends Disposable {
    static {
        this.MAX_MESSAGE_LENGTH = 1000;
    }
    static create(notification, filter) {
        if (!notification?.message || isCancellationError(notification.message)) {
            return undefined;
        }
        let severity;
        if (typeof notification.severity === "number") {
            severity = notification.severity;
        } else {
            severity = Severity$1.Info;
        }
        const message = NotificationViewItem.parseNotificationMessage(notification.message);
        if (!message) {
            return undefined;
        }
        let actions;
        if (notification.actions) {
            actions = notification.actions;
        } else if (isErrorWithActions(notification.message)) {
            actions = {
                primary: notification.message.actions
            };
        }
        let priority = notification.priority ?? NotificationPriority.DEFAULT;
        if ((priority === NotificationPriority.DEFAULT || priority === NotificationPriority.OPTIONAL) && severity !== Severity$1.Error) {
            if (filter.global === NotificationsFilter.ERROR) {
                priority = NotificationPriority.SILENT;
            } else if (isNotificationSource(notification.source) && filter.sources.get(notification.source.id) === NotificationsFilter.ERROR) {
                priority = NotificationPriority.SILENT;
            }
        }
        return ( new NotificationViewItem(
            notification.id,
            severity,
            notification.sticky,
            priority,
            message,
            notification.source,
            notification.progress,
            actions
        ));
    }
    static parseNotificationMessage(input) {
        let message;
        if (input instanceof Error) {
            message = toErrorMessage(input, false);
        } else if (typeof input === "string") {
            message = input;
        }
        if (!message) {
            return undefined;
        }
        const raw = message;
        if (message.length > NotificationViewItem.MAX_MESSAGE_LENGTH) {
            message = `${message.substr(0, NotificationViewItem.MAX_MESSAGE_LENGTH)}...`;
        }
        message = message.replace(/(\r\n|\n|\r)/gm, " ").trim();
        const linkedText = parseLinkedText(message);
        return {
            raw,
            linkedText,
            original: input
        };
    }
    constructor(id, _severity, _sticky, _priority, _message, _source, progress, actions) {
        super();
        this.id = id;
        this._severity = _severity;
        this._sticky = _sticky;
        this._priority = _priority;
        this._message = _message;
        this._source = _source;
        this._visible = false;
        this._onDidChangeExpansion = this._register(( new Emitter()));
        this.onDidChangeExpansion = this._onDidChangeExpansion.event;
        this._onDidClose = this._register(( new Emitter()));
        this.onDidClose = this._onDidClose.event;
        this._onDidChangeContent = this._register(( new Emitter()));
        this.onDidChangeContent = this._onDidChangeContent.event;
        this._onDidChangeVisibility = this._register(( new Emitter()));
        this.onDidChangeVisibility = this._onDidChangeVisibility.event;
        if (progress) {
            this.setProgress(progress);
        }
        this.setActions(actions);
    }
    setProgress(progress) {
        if (progress.infinite) {
            this.progress.infinite();
        } else if (progress.total) {
            this.progress.total(progress.total);
            if (progress.worked) {
                this.progress.worked(progress.worked);
            }
        }
    }
    setActions(
        actions = {
            primary: [],
            secondary: []
        }
    ) {
        this._actions = {
            primary: Array.isArray(actions.primary) ? actions.primary : [],
            secondary: Array.isArray(actions.secondary) ? actions.secondary : []
        };
        this._expanded = actions.primary && actions.primary.length > 0;
    }
    get canCollapse() {
        return !this.hasActions;
    }
    get expanded() {
        return !!this._expanded;
    }
    get severity() {
        return this._severity;
    }
    get sticky() {
        if (this._sticky) {
            return true;
        }
        const hasActions = this.hasActions;
        if (
        (hasActions && this._severity === Severity$1.Error) || (!hasActions && this._expanded) || (this._progress && !this._progress.state.done)) {
            return true;
        }
        return false;
    }
    get priority() {
        return this._priority;
    }
    get hasActions() {
        if (!this._actions) {
            return false;
        }
        if (!this._actions.primary) {
            return false;
        }
        return this._actions.primary.length > 0;
    }
    get hasProgress() {
        return !!this._progress;
    }
    get progress() {
        if (!this._progress) {
            this._progress = this._register(( new NotificationViewItemProgress()));
            this._register(this._progress.onDidChange(() => this._onDidChangeContent.fire({
                kind: NotificationViewItemContentChangeKind.PROGRESS
            })));
        }
        return this._progress;
    }
    get message() {
        return this._message;
    }
    get source() {
        return typeof this._source === "string" ? this._source : (this._source ? this._source.label : undefined);
    }
    get sourceId() {
        return (this._source && typeof this._source !== "string" && "id" in this._source) ? this._source.id : undefined;
    }
    get actions() {
        return this._actions;
    }
    get visible() {
        return this._visible;
    }
    updateSeverity(severity) {
        if (severity === this._severity) {
            return;
        }
        this._severity = severity;
        this._onDidChangeContent.fire({
            kind: NotificationViewItemContentChangeKind.SEVERITY
        });
    }
    updateMessage(input) {
        const message = NotificationViewItem.parseNotificationMessage(input);
        if (!message || message.raw === this._message.raw) {
            return;
        }
        this._message = message;
        this._onDidChangeContent.fire({
            kind: NotificationViewItemContentChangeKind.MESSAGE
        });
    }
    updateActions(actions) {
        this.setActions(actions);
        this._onDidChangeContent.fire({
            kind: NotificationViewItemContentChangeKind.ACTIONS
        });
    }
    updateVisibility(visible) {
        if (this._visible !== visible) {
            this._visible = visible;
            this._onDidChangeVisibility.fire(visible);
        }
    }
    expand() {
        if (this._expanded || !this.canCollapse) {
            return;
        }
        this._expanded = true;
        this._onDidChangeExpansion.fire();
    }
    collapse(skipEvents) {
        if (!this._expanded || !this.canCollapse) {
            return;
        }
        this._expanded = false;
        if (!skipEvents) {
            this._onDidChangeExpansion.fire();
        }
    }
    toggle() {
        if (this._expanded) {
            this.collapse();
        } else {
            this.expand();
        }
    }
    close() {
        this._onDidClose.fire();
        this.dispose();
    }
    equals(other) {
        if (this.hasProgress || other.hasProgress) {
            return false;
        }
        if (typeof this.id === "string" || typeof other.id === "string") {
            return this.id === other.id;
        }
        if (typeof this._source === "object") {
            if (this._source.label !== other.source || this._source.id !== other.sourceId) {
                return false;
            }
        } else if (this._source !== other.source) {
            return false;
        }
        if (this._message.raw !== other.message.raw) {
            return false;
        }
        const primaryActions = this._actions?.primary || [];
        const otherPrimaryActions = other.actions?.primary || [];
        return equals(
            primaryActions,
            otherPrimaryActions,
            (action, otherAction) => (action.id + action.label) === (otherAction.id + otherAction.label)
        );
    }
}
class ChoiceAction extends Action {
    constructor(id, choice) {
        super(id, choice.label, undefined, true, async () => {
            choice.run();
            this._onDidRun.fire();
        });
        this._onDidRun = this._register(( new Emitter()));
        this.onDidRun = this._onDidRun.event;
        this._keepOpen = !!choice.keepOpen;
        this._menu = !choice.isSecondary && choice.menu ? ( choice.menu.map((c, index) => ( new ChoiceAction(`${id}.${index}`, c)))) : undefined;
    }
    get menu() {
        return this._menu;
    }
    get keepOpen() {
        return this._keepOpen;
    }
}
class StatusMessageViewItem {
    static create(notification, options) {
        if (!notification || isCancellationError(notification)) {
            return undefined;
        }
        let message;
        if (notification instanceof Error) {
            message = toErrorMessage(notification, false);
        } else if (typeof notification === "string") {
            message = notification;
        }
        if (!message) {
            return undefined;
        }
        return {
            message,
            options
        };
    }
}

export { ChoiceAction, NotificationChangeType, NotificationHandle, NotificationViewItem, NotificationViewItemContentChangeKind, NotificationViewItemProgress, NotificationsModel, StatusMessageChangeType, isNotificationViewItem };
