export class NotificationManager {
    constructor(options = {}) {
        this.container = null;
        this.notifications = new Map();
        this.options = {
            position: options.position ?? "top-right",
            maxNotifications: options.maxNotifications ?? 5,
            cssClass: options.cssClass ?? "ss-notification",
            animationDuration: options.animationDuration ?? 300,
            defaultDuration: options.defaultDuration ?? 4000,
            newestOnTop: options.newestOnTop ?? true,
            pauseOnHover: options.pauseOnHover ?? true,
        };
        this.createContainer();
        if (!NotificationManager.instance) {
            NotificationManager.instance = this;
        }
    }
    success(message, options) {
        return this.show({ ...options, message, type: "success" });
    }
    error(message, options) {
        return this.show({
            ...options,
            message,
            type: "error",
            duration: options?.duration ?? 0,
        });
    }
    warning(message, options) {
        return this.show({ ...options, message, type: "warning" });
    }
    info(message, options) {
        return this.show({ ...options, message, type: "info" });
    }
    show(options) {
        if (this.notifications.size >= this.options.maxNotifications) {
            const oldest = this.options.newestOnTop
                ? Array.from(this.notifications.keys()).pop()
                : Array.from(this.notifications.keys()).shift();
            if (oldest)
                this.dismiss(oldest);
        }
        const id = `notification-${Date.now()}-${Math.random().toString(36).slice(2)}`;
        const element = this.createNotification(id, options);
        const duration = options.duration ?? this.options.defaultDuration;
        const instance = {
            id,
            element,
            options,
            timeout: null,
            startTime: Date.now(),
            remainingTime: duration,
        };
        this.notifications.set(id, instance);
        if (this.options.newestOnTop) {
            this.container?.prepend(element);
        }
        else {
            this.container?.appendChild(element);
        }
        requestAnimationFrame(() => {
            element.classList.add(`${this.options.cssClass}--visible`);
        });
        if (duration > 0) {
            instance.timeout = setTimeout(() => this.dismiss(id), duration);
        }
        return id;
    }
    dismiss(id) {
        const instance = this.notifications.get(id);
        if (!instance)
            return;
        if (instance.timeout) {
            clearTimeout(instance.timeout);
        }
        instance.element.classList.remove(`${this.options.cssClass}--visible`);
        instance.element.classList.add(`${this.options.cssClass}--removing`);
        setTimeout(() => {
            instance.element.remove();
            this.notifications.delete(id);
            instance.options.onClose?.();
        }, this.options.animationDuration);
    }
    dismissAll() {
        this.notifications.forEach((_, id) => this.dismiss(id));
    }
    get count() {
        return this.notifications.size;
    }
    destroy() {
        this.dismissAll();
        this.container?.remove();
        this.container = null;
        if (NotificationManager.instance === this) {
            NotificationManager.instance = null;
        }
    }
    static getInstance() {
        if (!NotificationManager.instance) {
            NotificationManager.instance = new NotificationManager();
        }
        return NotificationManager.instance;
    }
    static init() {
        const container = document.querySelector('[data-ss="notification-container"]');
        return new NotificationManager({
            position: container?.dataset
                .ssNotificationPosition,
            maxNotifications: container?.dataset.ssNotificationMax
                ? parseInt(container.dataset.ssNotificationMax, 10)
                : undefined,
        });
    }
    createContainer() {
        this.container = document.querySelector(`[data-ss="notification-container"], .${this.options.cssClass}-container`);
        if (!this.container) {
            this.container = document.createElement("div");
            this.container.className = `${this.options.cssClass}-container`;
            document.body.appendChild(this.container);
        }
        this.container.classList.add(`${this.options.cssClass}-container--${this.options.position}`);
        this.container.setAttribute("role", "region");
        this.container.setAttribute("aria-label", "Notifications");
        this.container.setAttribute("aria-live", "polite");
    }
    createNotification(id, options) {
        const el = document.createElement("div");
        el.className = `${this.options.cssClass} ${this.options.cssClass}--${options.type || "info"}`;
        if (options.className) {
            el.classList.add(options.className);
        }
        el.setAttribute("role", "alert");
        el.setAttribute("aria-live", "assertive");
        el.setAttribute("data-notification-id", id);
        const iconHtml = options.icon
            ? `<span class="${this.options.cssClass}__icon">${options.icon}</span>`
            : this.getDefaultIcon(options.type || "info");
        const titleHtml = options.title
            ? `<div class="${this.options.cssClass}__title">${options.title}</div>`
            : "";
        const actionHtml = options.actionText
            ? `<button type="button" class="${this.options.cssClass}__action">${options.actionText}</button>`
            : "";
        const closeHtml = options.closable !== false
            ? `<button type="button" class="${this.options.cssClass}__close" aria-label="Close">&times;</button>`
            : "";
        const progressHtml = options.showProgress &&
            (options.duration ?? this.options.defaultDuration) > 0
            ? `<div class="${this.options.cssClass}__progress"><div class="${this.options.cssClass}__progress-bar"></div></div>`
            : "";
        el.innerHTML = `
            ${iconHtml}
            <div class="${this.options.cssClass}__content">
                ${titleHtml}
                <div class="${this.options.cssClass}__message">${options.message}</div>
                ${actionHtml}
            </div>
            ${closeHtml}
            ${progressHtml}
        `;
        const closeBtn = el.querySelector(`.${this.options.cssClass}__close`);
        closeBtn?.addEventListener("click", () => this.dismiss(id));
        const actionBtn = el.querySelector(`.${this.options.cssClass}__action`);
        actionBtn?.addEventListener("click", () => {
            options.onAction?.();
            this.dismiss(id);
        });
        if (this.options.pauseOnHover) {
            el.addEventListener("mouseenter", () => this.pauseTimeout(id));
            el.addEventListener("mouseleave", () => this.resumeTimeout(id));
        }
        if (options.showProgress) {
            const duration = options.duration ?? this.options.defaultDuration;
            const progressBar = el.querySelector(`.${this.options.cssClass}__progress-bar`);
            if (progressBar && duration > 0) {
                progressBar.style.transition = `width ${duration}ms linear`;
                requestAnimationFrame(() => {
                    progressBar.style.width = "0%";
                });
            }
        }
        return el;
    }
    getDefaultIcon(type) {
        const icons = {
            success: `<span class="${this.options.cssClass}__icon">✓</span>`,
            error: `<span class="${this.options.cssClass}__icon">✕</span>`,
            warning: `<span class="${this.options.cssClass}__icon">⚠</span>`,
            info: `<span class="${this.options.cssClass}__icon">ℹ</span>`,
        };
        return icons[type];
    }
    pauseTimeout(id) {
        const instance = this.notifications.get(id);
        if (!instance || !instance.timeout)
            return;
        clearTimeout(instance.timeout);
        instance.remainingTime -= Date.now() - instance.startTime;
        const progressBar = instance.element.querySelector(`.${this.options.cssClass}__progress-bar`);
        if (progressBar) {
            const computed = getComputedStyle(progressBar);
            progressBar.style.width = computed.width;
            progressBar.style.transition = "none";
        }
    }
    resumeTimeout(id) {
        const instance = this.notifications.get(id);
        if (!instance || instance.remainingTime <= 0)
            return;
        instance.startTime = Date.now();
        instance.timeout = setTimeout(() => this.dismiss(id), instance.remainingTime);
        const progressBar = instance.element.querySelector(`.${this.options.cssClass}__progress-bar`);
        if (progressBar) {
            progressBar.style.transition = `width ${instance.remainingTime}ms linear`;
            requestAnimationFrame(() => {
                progressBar.style.width = "0%";
            });
        }
    }
}
NotificationManager.instance = null;
export default NotificationManager;
//# sourceMappingURL=NotificationManager.js.map