import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { AsyncPipe, isPlatformBrowser } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, input, computed, signal, output, HostListener, Component, ChangeDetectionStrategy, Injector, PLATFORM_ID, Injectable } from '@angular/core';
import { areAnimationsDisabled, isRTL } from '@siemens/element-ng/common';
import { t, SiTranslatePipe, SiTranslateService, SiNoTranslateService } from '@siemens/element-translate-ng/translate';
import { ReplaySubject, Subject } from 'rxjs';
import { elementCancel } from '@siemens/element-icons';
import { STATUS_ICON_CONFIG, addIcons, SiIconComponent, SiStatusIconComponent } from '@siemens/element-ng/icon';
import * as i1 from '@siemens/element-ng/link';
import { SiLinkModule } from '@siemens/element-ng/link';

const SI_TOAST_AUTO_HIDE_DELAY = 6000;

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiToastNotificationComponent {
    statusIcons = inject(STATUS_ICON_CONFIG);
    toast = input.required(...(ngDevMode ? [{ debugName: "toast" }] : []));
    closeAriaLabelDefault = t(() => $localize `:@@SI_TOAST.CLOSE:Close`);
    closeAriaLabel = computed(() => this.toast().closeAriaLabel ?? this.closeAriaLabelDefault, ...(ngDevMode ? [{ debugName: "closeAriaLabel" }] : []));
    icons = addIcons({ elementCancel });
    status = computed(() => {
        const toast = this.toast();
        return Object.keys(this.statusIcons).includes(toast.state) ? toast.state : 'info';
    }, ...(ngDevMode ? [{ debugName: "status" }] : []));
    statusColor = computed(() => this.statusIcons[this.status()].color, ...(ngDevMode ? [{ debugName: "statusColor" }] : []));
    toastTimeoutInSeconds = computed(() => {
        const toast = this.toast();
        return toast.timeout ? toast.timeout / 1000 : SI_TOAST_AUTO_HIDE_DELAY / 1000;
    }, ...(ngDevMode ? [{ debugName: "toastTimeoutInSeconds" }] : []));
    animationMode = signal('running', ...(ngDevMode ? [{ debugName: "animationMode" }] : []));
    paused = output();
    resumed = output();
    onMouseEnter() {
        if (!this.toast().disableAutoClose) {
            this.animationMode.set('paused');
            this.paused.emit();
        }
    }
    onMouseLeave() {
        if (!this.toast().disableAutoClose) {
            this.animationMode.set('running');
            this.resumed.emit();
        }
    }
    close() {
        this.toast().close();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiToastNotificationComponent, isStandalone: true, selector: "si-toast-notification", inputs: { toast: { classPropertyName: "toast", publicName: "toast", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { paused: "paused", resumed: "resumed" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0, template: "@let toastValue = toast();\n@let autoClose = !toastValue.disableAutoClose;\n@let manualClose = !toastValue.disableManualClose;\n<div class=\"si-toast elevation-2\" [class.si-toast-auto-close]=\"autoClose\">\n  @if (autoClose) {\n    <div\n      class=\"si-toast-timer-bar\"\n      [style.--play-state]=\"animationMode()\"\n      [style.--toast-timer-duration.s]=\"toastTimeoutInSeconds()\"\n    ></div>\n  }\n  <div [class]=\"`bar ${statusColor()}`\"></div>\n  <si-status-icon class=\"icon\" [status]=\"status()\" />\n\n  <div class=\"toast-content px-4\">\n    <p class=\"toast-title\"\n      ><b>{{ toastValue.title | translate: toastValue.translationParams }}</b></p\n    >\n    @if (toastValue.message) {\n      <p class=\"mt-4\">{{ toastValue.message | translate: toastValue.translationParams }}</p>\n    }\n    @if (toastValue.action) {\n      <p [class.mt-3]=\"toastValue.message\" [class.mt-4]=\"!toastValue.message\">\n        <a [siLink]=\"toastValue.action\">{{\n          toastValue.action!.title | translate: toastValue.translationParams\n        }}</a>\n      </p>\n    }\n  </div>\n  @if (manualClose) {\n    <button\n      type=\"button\"\n      tabindex=\"0\"\n      class=\"btn btn-icon btn-ghost mt-n2 me-n2\"\n      [attr.aria-label]=\"closeAriaLabel() | translate\"\n      (keydown.enter)=\"close()\"\n      (click)=\"close()\"\n    >\n      <si-icon [icon]=\"icons.elementCancel\" />\n    </button>\n  }\n</div>\n", styles: [".si-toast-timer-bar,.si-toast.si-toast-auto-close:before{position:absolute;inset-block-end:0;inset-inline-start:0;block-size:2px}:host{display:block}.si-toast{block-size:auto;position:relative;display:flex;align-items:flex-start;color:var(--element-text-primary);background:var(--element-base-3);border-radius:var(--element-radius-2);padding-inline:12px 8px;padding-block:8px;margin-block-end:20px;font-size:1rem;pointer-events:all;overflow:hidden;min-inline-size:250px;max-inline-size:calc(100vw - 40px)}@media(min-width:768px){.si-toast{max-inline-size:400px}}.si-toast.si-toast-auto-close{padding-block-end:10px}.si-toast.si-toast-auto-close:before{content:\"\";background:var(--element-ui-4);inset-inline-end:0}.bar{inset-block-start:0;inset-inline-start:0;position:absolute;inline-size:4px;block-size:100%;background:currentColor}@keyframes si-toast-auto-close-animation{0%{inline-size:100%}to{inline-size:0}}.si-toast-timer-bar{animation:si-toast-auto-close-animation var(--toast-timer-duration, 4s) linear forwards;animation-play-state:var(--play-state, running);background-color:var(--element-ui-0)}.toast-content{flex:1;overflow:hidden;white-space:nowrap}.toast-content p{margin-block:0;line-height:1.125rem;white-space:pre-line;overflow-wrap:break-word;word-wrap:break-word}.toast-content .toast-title{line-height:1.25rem}\n"], dependencies: [{ kind: "ngmodule", type: SiLinkModule }, { kind: "directive", type: i1.SiLinkDirective, selector: "[siLink]", inputs: ["siLink", "siLinkDefaultTarget", "actionParam", "activeClass", "exactMatch", "ariaCurrent"], outputs: ["activeChange"], exportAs: ["siLink"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiStatusIconComponent, selector: "si-status-icon", inputs: ["status"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-toast-notification', imports: [SiLinkModule, SiIconComponent, SiStatusIconComponent, SiTranslatePipe], template: "@let toastValue = toast();\n@let autoClose = !toastValue.disableAutoClose;\n@let manualClose = !toastValue.disableManualClose;\n<div class=\"si-toast elevation-2\" [class.si-toast-auto-close]=\"autoClose\">\n  @if (autoClose) {\n    <div\n      class=\"si-toast-timer-bar\"\n      [style.--play-state]=\"animationMode()\"\n      [style.--toast-timer-duration.s]=\"toastTimeoutInSeconds()\"\n    ></div>\n  }\n  <div [class]=\"`bar ${statusColor()}`\"></div>\n  <si-status-icon class=\"icon\" [status]=\"status()\" />\n\n  <div class=\"toast-content px-4\">\n    <p class=\"toast-title\"\n      ><b>{{ toastValue.title | translate: toastValue.translationParams }}</b></p\n    >\n    @if (toastValue.message) {\n      <p class=\"mt-4\">{{ toastValue.message | translate: toastValue.translationParams }}</p>\n    }\n    @if (toastValue.action) {\n      <p [class.mt-3]=\"toastValue.message\" [class.mt-4]=\"!toastValue.message\">\n        <a [siLink]=\"toastValue.action\">{{\n          toastValue.action!.title | translate: toastValue.translationParams\n        }}</a>\n      </p>\n    }\n  </div>\n  @if (manualClose) {\n    <button\n      type=\"button\"\n      tabindex=\"0\"\n      class=\"btn btn-icon btn-ghost mt-n2 me-n2\"\n      [attr.aria-label]=\"closeAriaLabel() | translate\"\n      (keydown.enter)=\"close()\"\n      (click)=\"close()\"\n    >\n      <si-icon [icon]=\"icons.elementCancel\" />\n    </button>\n  }\n</div>\n", styles: [".si-toast-timer-bar,.si-toast.si-toast-auto-close:before{position:absolute;inset-block-end:0;inset-inline-start:0;block-size:2px}:host{display:block}.si-toast{block-size:auto;position:relative;display:flex;align-items:flex-start;color:var(--element-text-primary);background:var(--element-base-3);border-radius:var(--element-radius-2);padding-inline:12px 8px;padding-block:8px;margin-block-end:20px;font-size:1rem;pointer-events:all;overflow:hidden;min-inline-size:250px;max-inline-size:calc(100vw - 40px)}@media(min-width:768px){.si-toast{max-inline-size:400px}}.si-toast.si-toast-auto-close{padding-block-end:10px}.si-toast.si-toast-auto-close:before{content:\"\";background:var(--element-ui-4);inset-inline-end:0}.bar{inset-block-start:0;inset-inline-start:0;position:absolute;inline-size:4px;block-size:100%;background:currentColor}@keyframes si-toast-auto-close-animation{0%{inline-size:100%}to{inline-size:0}}.si-toast-timer-bar{animation:si-toast-auto-close-animation var(--toast-timer-duration, 4s) linear forwards;animation-play-state:var(--play-state, running);background-color:var(--element-ui-0)}.toast-content{flex:1;overflow:hidden;white-space:nowrap}.toast-content p{margin-block:0;line-height:1.125rem;white-space:pre-line;overflow-wrap:break-word;word-wrap:break-word}.toast-content .toast-title{line-height:1.25rem}\n"] }]
        }], propDecorators: { toast: [{ type: i0.Input, args: [{ isSignal: true, alias: "toast", required: true }] }], paused: [{ type: i0.Output, args: ["paused"] }], resumed: [{ type: i0.Output, args: ["resumed"] }], onMouseEnter: [{
                type: HostListener,
                args: ['mouseenter']
            }], onMouseLeave: [{
                type: HostListener,
                args: ['mouseleave']
            }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiToastNotificationDrawerComponent {
    toasts = input(...(ngDevMode ? [undefined, { debugName: "toasts" }] : []));
    paused = output();
    resumed = output();
    animationsDisabled = areAnimationsDisabled();
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiToastNotificationDrawerComponent, isStandalone: true, selector: "si-toast-notification-drawer", inputs: { toasts: { classPropertyName: "toasts", publicName: "toasts", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { paused: "paused", resumed: "resumed" }, host: { attributes: { "aria-live": "polite" }, properties: { "class.animations-disabled": "animationsDisabled" } }, ngImport: i0, template: "@for (toast of toasts() | async; track toast) {\n  <si-toast-notification\n    class=\"position-relative\"\n    animate.enter=\"toast-enter\"\n    animate.leave=\"toast-leave\"\n    [toast]=\"toast\"\n    (paused)=\"paused.emit(toast)\"\n    (resumed)=\"resumed.emit(toast)\"\n  />\n}\n", styles: ["::ng-deep .cdk-global-overlay-wrapper:has(si-toast-notification-drawer){z-index:2000}:host{padding-inline-end:20px}si-toast-notification{inset-inline-end:0}.toast-enter{transition-property:opacity,transform;transition-duration:.5s;transition-timing-function:cubic-bezier(.175,.885,.32,1.275);opacity:1;transform:translateY(0)}@starting-style{.toast-enter{opacity:0;transform:translateY(100%)}}.toast-leave{transition-property:opacity,transform;transition-duration:.3s;transition-timing-function:cubic-bezier(.175,.885,.32,1.275);opacity:0;transform:translate(100%)}:host.animations-disabled si-toast-notification{transition:none}:host.animations-disabled si-toast-notification.toast-enter,:host.animations-disabled si-toast-notification.toast-leave{transition:none}\n"], dependencies: [{ kind: "component", type: SiToastNotificationComponent, selector: "si-toast-notification", inputs: ["toast"], outputs: ["paused", "resumed"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationDrawerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-toast-notification-drawer', imports: [AsyncPipe, SiToastNotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        'aria-live': 'polite',
                        '[class.animations-disabled]': 'animationsDisabled'
                    }, template: "@for (toast of toasts() | async; track toast) {\n  <si-toast-notification\n    class=\"position-relative\"\n    animate.enter=\"toast-enter\"\n    animate.leave=\"toast-leave\"\n    [toast]=\"toast\"\n    (paused)=\"paused.emit(toast)\"\n    (resumed)=\"resumed.emit(toast)\"\n  />\n}\n", styles: ["::ng-deep .cdk-global-overlay-wrapper:has(si-toast-notification-drawer){z-index:2000}:host{padding-inline-end:20px}si-toast-notification{inset-inline-end:0}.toast-enter{transition-property:opacity,transform;transition-duration:.5s;transition-timing-function:cubic-bezier(.175,.885,.32,1.275);opacity:1;transform:translateY(0)}@starting-style{.toast-enter{opacity:0;transform:translateY(100%)}}.toast-leave{transition-property:opacity,transform;transition-duration:.3s;transition-timing-function:cubic-bezier(.175,.885,.32,1.275);opacity:0;transform:translate(100%)}:host.animations-disabled si-toast-notification{transition:none}:host.animations-disabled si-toast-notification.toast-enter,:host.animations-disabled si-toast-notification.toast-leave{transition:none}\n"] }]
        }], propDecorators: { toasts: [{ type: i0.Input, args: [{ isSignal: true, alias: "toasts", required: false }] }], paused: [{ type: i0.Output, args: ["paused"] }], resumed: [{ type: i0.Output, args: ["resumed"] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiToastNotificationService {
    /**
     * List of currently active toasts to see details or close them.
     *
     * @defaultValue []
     */
    activeToasts = [];
    activeToastsSubject = new ReplaySubject(1);
    queuedToastSubject = new Subject();
    maxToasts = 3;
    componentRef;
    overlayRef;
    injector = inject(Injector);
    overlay = inject(Overlay);
    toastTimeoutMap = new Map();
    toastTimerDefaults = new Map();
    constructor() {
        const isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
        this.queuedToastSubject.subscribe((toast) => {
            this.activeToasts.push(toast);
            if (this.activeToasts.length > this.maxToasts) {
                this.hideToastNotification(this.activeToasts[0]);
            }
            this.activeToastsSubject.next(this.activeToasts);
            if (!toast.disableAutoClose && toast.timeout) {
                this.toastTimerDefaults.set(toast, {
                    pendingTimeout: toast.timeout,
                    initializeTime: Date.now()
                });
                this.toastTimeoutMap.set(toast, setTimeout(() => this.hideToastNotification(toast), toast.timeout));
            }
        });
        if (isBrowser) {
            this.addToastDrawer();
        }
    }
    ngOnDestroy() {
        this.overlayRef?.dispose();
        this.componentRef?.destroy();
    }
    /**
     * Queue a new toast to be shown.
     * @param action - Passing a Link object will optionally add a clickable link to the toast which can contain an action.
     * @returns the toast object
     */
    queueToastNotification(state, title, message, disableAutoClose, disableManualClose, action) {
        const toast = {
            state,
            title,
            message,
            disableAutoClose,
            disableManualClose,
            action,
            hidden: new Subject()
        };
        return this.showToastNotification(toast);
    }
    /**
     * Show a toast notification
     * @param toast - The toast object of the toast to be shown, can also be constructed while calling this.
     */
    showToastNotification(toast) {
        this.overlayRef?.setDirection(isRTL() ? 'rtl' : 'ltr');
        toast.timeout ??= SI_TOAST_AUTO_HIDE_DELAY;
        toast.hidden ??= new Subject();
        toast.close = () => this.hideToastNotification(toast);
        this.queuedToastSubject.next(toast);
        return toast;
    }
    /**
     * Hide a toast notification
     * @param toast - The toast object of the toast to be hidden, can be retrieved from {@link activeToasts} and is returned by {@link queueToastNotification}.
     */
    hideToastNotification(toast) {
        const hiddenToasts = [];
        const activeToasts = [];
        this.activeToasts.forEach(item => {
            if (!toast || item === toast) {
                hiddenToasts.push(item);
            }
            else {
                activeToasts.push(item);
            }
        });
        this.activeToasts = activeToasts;
        this.activeToastsSubject.next(this.activeToasts);
        hiddenToasts.forEach(item => {
            item.hidden?.next();
            item.hidden?.complete();
            this.toastTimerDefaults.delete(item);
            this.toastTimeoutMap.delete(item);
        });
    }
    pauseToastNotification(toast) {
        if (!toast.disableAutoClose) {
            clearTimeout(this.toastTimeoutMap.get(toast));
            const initialTimeout = this.toastTimerDefaults.get(toast)?.initializeTime;
            const elapsedTime = initialTimeout ? Date.now() - initialTimeout : 0;
            this.toastTimerDefaults.get(toast).pendingTimeout -= elapsedTime;
        }
    }
    resumeToastNotification(toast) {
        if (!toast.disableAutoClose) {
            this.toastTimerDefaults.get(toast).initializeTime = Date.now();
            this.toastTimeoutMap.set(toast, setTimeout(() => {
                this.hideToastNotification(this.activeToasts.find(t => t === toast));
            }, this.toastTimerDefaults.get(toast).pendingTimeout));
        }
    }
    addToastDrawer() {
        this.overlayRef = this.overlay.create({
            positionStrategy: this.overlay.position().global().end().bottom()
        });
        const portal = new ComponentPortal(SiToastNotificationDrawerComponent, null, this.buildInjector());
        this.componentRef = this.overlayRef.attach(portal);
        this.componentRef.setInput('toasts', this.activeToastsSubject);
        this.componentRef.instance.paused.subscribe(toast => {
            this.pauseToastNotification(toast);
        });
        this.componentRef.instance.resumed.subscribe(toast => {
            this.resumeToastNotification(toast);
        });
    }
    // TODO remove once translation must be defined at application start
    // Notification service is provided in 'root'. If no translation is defined, SiNoTranslateService is not provided
    buildInjector() {
        let injector = this.injector;
        if (!injector.get(SiTranslateService, null)) {
            injector = Injector.create({
                providers: [{ provide: SiTranslateService, useClass: SiNoTranslateService, deps: [] }],
                parent: this.injector
            });
        }
        return injector;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiToastNotificationService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Generated bundle index. Do not edit.
 */

export { SI_TOAST_AUTO_HIDE_DELAY, SiToastNotificationService };
//# sourceMappingURL=siemens-element-ng-toast-notification.mjs.map
