export default class LivewireNotification {
    constructor(config = {}) {
        const defaultConfig = {
            notificationTimeout: 6000, // Tiempo predeterminado para las notificaciones
            onNotificationShown: null, // Callback al mostrar una notificación
            onNotificationRemoved: null, // Callback al eliminar una notificación
            onNotificationClosed: null // Callback al cerrar una notificación mediante botón
        };

        this.config = { ...defaultConfig, ...config };
        this.initLivewireNotification();
    }

    /**
     * Inicializa la escucha de notificaciones desde Livewire.
     */
    initLivewireNotification() {
        // Mostrar notificación almacenada después de la recarga
        const storedNotification = localStorage.getItem('pendingNotification');

        if (storedNotification) {
            const event = JSON.parse(storedNotification);
            this.showStoredNotification(event);
            localStorage.removeItem('pendingNotification'); // Limpiar después de mostrar
        }

        // Escuchar nuevas notificaciones desde Livewire
        Livewire.on('notification', event => {
            if (event.deferReload) {
                // Guardar la notificación en localStorage para mostrar después de la recarga
                localStorage.setItem('pendingNotification', JSON.stringify(event));

                window.location.reload();
            } else {
                // Mostrar la notificación inmediatamente
                this.showNotification(event);
            }
        });
    }

    /**
     * Método para emitir notificaciones desde JavaScript.
     * @param {Object} options - Opciones de la notificación.
     * @param {Function} callback - Callback opcional que se ejecutará después de mostrar la notificación.
     * @param {number} customTimeout - Timeout personalizado (opcional).
     */
    emitNotification(options, callback, customTimeout) {
        const event = {
            target: options.target || 'body',
            message: options.message || 'Notificación',
            type: options.type || 'info',
            deferReload: options.deferReload || false,
            notificationTimeout: customTimeout || options.notificationTimeout || this.config.notificationTimeout // Usar el timeout personalizado o el predeterminado
        };

        // Mostrar la notificación
        this.showNotification(event);

        // Ejecutar callback si está definido
        if (typeof callback === 'function') {
            callback(event);
        }
    }

    /**
     * Muestra una notificación almacenada.
     * @param {Object} event - Datos del evento de notificación.
     */
    showStoredNotification(event) {
        this.showNotification(event);
    }

    /**
     * Muestra una notificación.
     * @param {Object} event - Datos del evento de notificación.
     */
    showNotification(event) {
        const targetElement = document.querySelector(event.target);

        if (!targetElement) {
            console.error(`Target ${event.target} no encontrado. Mostrando en el contenedor global.`);

            this.showInGlobalContainer(event);
            return;
        }

        // Crear un contenedor para notificaciones si no existe
        if (!targetElement.querySelector('.notification-container')) {
            const container = document.createElement('div');

            container.className = 'notification-container';
            targetElement.appendChild(container);
        }

        const notificationContainer = targetElement.querySelector('.notification-container');
        const notificationElement = this.renderNotification(notificationContainer, event);

        // Callback opcional al mostrar la notificación
        if (typeof this.config.onNotificationShown === 'function') {
            this.config.onNotificationShown(notificationElement, event);
        }

        // Configurar el timeout para eliminar la notificación
        this.setNotificationTimeout(notificationElement, event);

        // Configurar el evento para el botón de cierre
        this.setupCloseButton(notificationElement, event);
    }

    /**
     * Renderiza una notificación en el contenedor global (body).
     * @param {Object} event - Datos del evento de notificación.
     */
    showInGlobalContainer(event) {
        const globalContainer = document.body;
        if (!globalContainer.querySelector('.notification-container')) {
            const container = document.createElement('div');

            container.className = 'notification-container';
            globalContainer.appendChild(container);
        }

        const notificationContainer = globalContainer.querySelector('.notification-container');
        const notificationElement = this.renderNotification(notificationContainer, event);

        if (typeof this.config.onNotificationShown === 'function') {
            this.config.onNotificationShown(notificationElement, event);
        }

        this.setNotificationTimeout(notificationElement, event);
        this.setupCloseButton(notificationElement, event);
    }

    /**
     * Renderiza una notificación en el contenedor.
     * @param {HTMLElement} container - Contenedor de notificaciones.
     * @param {Object} event - Evento de notificación con tipo y mensaje.
     * @returns {HTMLElement} - Elemento de la notificación recién creada.
     */
    renderNotification(container, event) {
        const notificationElement = document.createElement('div');

        notificationElement.className = `alert alert-${event.type} alert-dismissible fade show`;
        notificationElement.role = 'alert';
        notificationElement.innerHTML = `${event.message} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>`;

        container.appendChild(notificationElement);

        return notificationElement;
    }

    /**
     * Configura un timeout para limpiar una notificación específica.
     * @param {HTMLElement} notificationElement - Elemento de la notificación.
     * @param {Object} event - Evento asociado a la notificación.
     */
    setNotificationTimeout(notificationElement, event) {
        const timeout = event.notificationTimeout || this.config.notificationTimeout;

        setTimeout(() => {
            if (notificationElement && notificationElement.parentElement) {
                notificationElement.remove();

                // Callback opcional al eliminar la notificación
                if (typeof this.config.onNotificationRemoved === 'function') {
                    this.config.onNotificationRemoved(notificationElement, event);
                }
            }
        }, timeout);
    }

    /**
     * Configura el cierre manual de una notificación mediante el botón "Cerrar".
     * @param {HTMLElement} notificationElement - Elemento de la notificación.
     * @param {Object} event - Evento asociado a la notificación.
     */
    setupCloseButton(notificationElement, event) {
        const closeButton = notificationElement.querySelector('.btn-close');
        if (closeButton) {
            closeButton.addEventListener('click', () => {
                notificationElement.remove();

                // Callback opcional al cerrar la notificación manualmente
                if (typeof this.config.onNotificationClosed === 'function') {
                    this.config.onNotificationClosed(notificationElement, event);
                }
            });
        }
    }
}
