/**
 * CSRF Token Auto-Refresh System
 *
 * Automatically refreshes CSRF tokens before they expire to prevent
 * form submission errors when users keep forms open for extended periods.
 *
 * Features:
 * - Automatic token refresh every 105 minutes (15 minutes before expiry)
 * - Support for both regular forms and LiveComponents
 * - Visual feedback when tokens are refreshed
 * - Graceful error handling with fallback strategies
 * - Page visibility optimization (pause when tab is inactive)
 * - Multiple form support
 *
 * Usage:
 * import { CsrfAutoRefresh } from './modules/csrf-auto-refresh.js';
 *
 * // Initialize for contact form
 * const csrfRefresh = new CsrfAutoRefresh({
 *     formId: 'contact_form',
 *     refreshInterval: 105 * 60 * 1000 // 105 minutes
 * });
 *
 * // Initialize for a LiveComponent
 * const liveRefresh = new CsrfAutoRefresh({
 *     formId: 'counter:demo', // Component ID
 *     refreshInterval: 105 * 60 * 1000
 * });
 *
 * // Or auto-detect all forms and LiveComponents with CSRF tokens
 * CsrfAutoRefresh.initializeAll();
 */

export class CsrfAutoRefresh {
    
    /**
     * Default configuration
     */
    static DEFAULT_CONFIG = {
        formId: 'contact_form',
        refreshInterval: 105 * 60 * 1000, // 105 minutes (15 min before 2h expiry)
        apiEndpoint: '/api/csrf/refresh',
        tokenSelector: 'input[name="_token"]',
        formIdSelector: 'input[name="_form_id"]',
        enableVisualFeedback: false, // Disabled to hide browser notifications
        enableConsoleLogging: true,
        pauseWhenHidden: true, // Pause refresh when tab is not visible
        maxRetries: 3,
        retryDelay: 5000 // 5 seconds
    };

    /**
     * @param {Object} config Configuration options
     */
    constructor(config = {}) {
        this.config = { ...CsrfAutoRefresh.DEFAULT_CONFIG, ...config };
        this.intervalId = null;
        this.isActive = false;
        this.retryCount = 0;
        this.lastRefreshTime = null;
        
        // Track page visibility for optimization
        this.isPageVisible = !document.hidden;
        
        this.log('CSRF Auto-Refresh initialized', this.config);
        
        // Setup event listeners
        this.setupEventListeners();
        
        // Start auto-refresh if page is visible
        if (this.isPageVisible) {
            this.start();
        }
    }

    /**
     * Setup event listeners for page visibility and unload
     */
    setupEventListeners() {
        if (this.config.pauseWhenHidden) {
            document.addEventListener('visibilitychange', () => {
                this.isPageVisible = !document.hidden;
                
                if (this.isPageVisible) {
                    this.log('Page became visible, resuming CSRF refresh');
                    this.start();
                } else {
                    this.log('Page became hidden, pausing CSRF refresh');
                    this.stop();
                }
            });
        }

        // Cleanup on page unload
        window.addEventListener('beforeunload', () => {
            this.stop();
        });
    }

    /**
     * Start the auto-refresh timer
     */
    start() {
        if (this.isActive) {
            this.log('Auto-refresh already active');
            return;
        }

        this.isActive = true;
        
        // Set up interval for token refresh
        this.intervalId = setInterval(() => {
            this.refreshToken();
        }, this.config.refreshInterval);
        
        this.log(`Auto-refresh started. Next refresh in ${this.config.refreshInterval / 1000 / 60} minutes`);
        
        // Show visual feedback if enabled
        if (this.config.enableVisualFeedback) {
            // this.showStatusMessage('CSRF protection enabled - tokens will refresh automatically', 'info');
        }
    }

    /**
     * Stop the auto-refresh timer
     */
    stop() {
        if (!this.isActive) {
            return;
        }

        if (this.intervalId) {
            clearInterval(this.intervalId);
            this.intervalId = null;
        }

        this.isActive = false;
        this.log('Auto-refresh stopped');
    }

    /**
     * Refresh the CSRF token via API call
     */
    async refreshToken() {
        if (!this.isPageVisible && this.config.pauseWhenHidden) {
            this.log('Page not visible, skipping refresh');
            return;
        }

        try {
            this.log('Refreshing CSRF token...');
            
            const response = await fetch(`${this.config.apiEndpoint}?form_id=${encodeURIComponent(this.config.formId)}`, {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                }
            });

            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }

            const data = await response.json();

            if (!data.success || !data.token) {
                throw new Error(data.error || 'Invalid response from server');
            }

            // Update token in all matching forms
            this.updateTokenInForms(data.token);
            
            this.lastRefreshTime = new Date();
            this.retryCount = 0; // Reset retry count on success
            
            this.log('CSRF token refreshed successfully', {
                token: data.token.substring(0, 8) + '...',
                formId: data.form_id,
                expiresIn: data.expires_in
            });

            // Show visual feedback
            if (this.config.enableVisualFeedback) {
                // this.showStatusMessage('Security token refreshed', 'success');
            }

        } catch (error) {
            this.handleRefreshError(error);
        }
    }

    /**
     * Update CSRF token in all forms on the page
     * Supports both regular forms and LiveComponent data-csrf-token attributes
     */
    updateTokenInForms(newToken) {
        let updatedCount = 0;

        // Update regular form input tokens
        const tokenInputs = document.querySelectorAll(this.config.tokenSelector);
        tokenInputs.forEach(input => {
            // Check if this token belongs to our form
            const form = input.closest('form');
            if (form) {
                const formIdInput = form.querySelector(this.config.formIdSelector);
                if (formIdInput && formIdInput.value === this.config.formId) {
                    input.value = newToken;
                    updatedCount++;
                }
            }
        });

        // Update LiveComponent data-csrf-token attributes
        // LiveComponents use form ID format: "livecomponent:{componentId}"
        const liveComponentFormId = 'livecomponent:' + this.config.formId.replace(/^livecomponent:/, '');
        const liveComponents = document.querySelectorAll('[data-live-component][data-csrf-token]');

        liveComponents.forEach(component => {
            // Check if this component uses our form ID
            const componentId = component.dataset.liveComponent;
            const expectedFormId = 'livecomponent:' + componentId;

            if (expectedFormId === liveComponentFormId || this.config.formId === componentId) {
                component.dataset.csrfToken = newToken;
                updatedCount++;
                this.log(`Updated LiveComponent token: ${componentId}`);
            }
        });

        this.log(`Updated ${updatedCount} token(s) (forms + LiveComponents)`);

        if (updatedCount === 0) {
            console.warn('CsrfAutoRefresh: No tokens found to update. Check your selectors and formId.');
        }

        return updatedCount;
    }

    /**
     * Handle refresh errors with retry logic
     */
    handleRefreshError(error) {
        this.retryCount++;
        
        console.error('CSRF token refresh failed:', error);
        
        if (this.retryCount <= this.config.maxRetries) {
            this.log(`Retrying in ${this.config.retryDelay / 1000}s (attempt ${this.retryCount}/${this.config.maxRetries})`);
            
            setTimeout(() => {
                this.refreshToken();
            }, this.config.retryDelay);
            
            // Show visual feedback for retry
            if (this.config.enableVisualFeedback) {
                // this.showStatusMessage(`Token refresh failed, retrying... (${this.retryCount}/${this.config.maxRetries})`, 'warning');
            }
        } else {
            // Max retries reached
            this.log('Max retries reached, stopping auto-refresh');
            this.stop();
            
            if (this.config.enableVisualFeedback) {
                // this.showStatusMessage('Token refresh failed. Please refresh the page if you encounter errors.', 'error');
            }
        }
    }

    /**
     * Show visual status message to user
     */
    showStatusMessage(message, type = 'info') {
        // Create or update status element
        let statusEl = document.getElementById('csrf-status-message');
        
        if (!statusEl) {
            statusEl = document.createElement('div');
            statusEl.id = 'csrf-status-message';
            statusEl.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 12px 16px;
                border-radius: 6px;
                font-size: 14px;
                z-index: 10000;
                max-width: 300px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.1);
                transition: opacity 0.3s ease;
            `;
            document.body.appendChild(statusEl);
        }

        // Set message and styling based on type
        statusEl.textContent = message;
        statusEl.className = `csrf-status-${type}`;
        
        // Style based on type
        const styles = {
            info: 'background: #e3f2fd; color: #1976d2; border-left: 4px solid #2196f3;',
            success: 'background: #e8f5e8; color: #2e7d32; border-left: 4px solid #4caf50;',
            warning: 'background: #fff3e0; color: #f57c00; border-left: 4px solid #ff9800;',
            error: 'background: #ffebee; color: #d32f2f; border-left: 4px solid #f44336;'
        };
        
        statusEl.style.cssText += styles[type] || styles.info;
        statusEl.style.opacity = '1';

        // Auto-hide after delay (except for errors)
        if (type !== 'error') {
            setTimeout(() => {
                if (statusEl) {
                    statusEl.style.opacity = '0';
                    setTimeout(() => {
                        if (statusEl && statusEl.parentNode) {
                            statusEl.parentNode.removeChild(statusEl);
                        }
                    }, 300);
                }
            }, type === 'success' ? 3000 : 5000);
        }
    }

    /**
     * Log messages if console logging is enabled
     */
    log(message, data = null) {
        if (this.config.enableConsoleLogging) {
            const timestamp = new Date().toLocaleTimeString();
            if (data) {
                console.log(`[${timestamp}] CsrfAutoRefresh: ${message}`, data);
            } else {
                console.log(`[${timestamp}] CsrfAutoRefresh: ${message}`);
            }
        }
    }

    /**
     * Get current status information
     */
    getStatus() {
        return {
            isActive: this.isActive,
            formId: this.config.formId,
            lastRefreshTime: this.lastRefreshTime,
            retryCount: this.retryCount,
            isPageVisible: this.isPageVisible,
            nextRefreshIn: this.isActive ? 
                Math.max(0, this.config.refreshInterval - (Date.now() - (this.lastRefreshTime?.getTime() || Date.now()))) :
                null
        };
    }

    /**
     * Manual token refresh (useful for debugging)
     */
    async manualRefresh() {
        this.log('Manual refresh triggered');
        await this.refreshToken();
    }

    /**
     * Static method to initialize auto-refresh for all forms with CSRF tokens
     * Supports both regular forms and LiveComponents
     */
    static initializeAll() {
        const formIds = new Set();

        // Collect unique form IDs from regular forms
        const tokenInputs = document.querySelectorAll('input[name="_token"]');
        tokenInputs.forEach(input => {
            const form = input.closest('form');
            if (form) {
                const formIdInput = form.querySelector('input[name="_form_id"]');
                if (formIdInput && formIdInput.value) {
                    formIds.add(formIdInput.value);
                }
            }
        });

        // Collect unique component IDs from LiveComponents
        const liveComponents = document.querySelectorAll('[data-live-component][data-csrf-token]');
        liveComponents.forEach(component => {
            const componentId = component.dataset.liveComponent;
            if (componentId) {
                // Use the component ID directly (without "livecomponent:" prefix for config)
                formIds.add(componentId);
            }
        });

        // Initialize auto-refresh for each unique form/component ID
        const instances = [];
        formIds.forEach(formId => {
            const instance = new CsrfAutoRefresh({ formId });
            instances.push(instance);
        });

        console.log(`CsrfAutoRefresh: Initialized for ${instances.length} forms/components:`, Array.from(formIds));
        return instances;
    }
}

// Auto-initialize when DOM is ready
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
        CsrfAutoRefresh.initializeAll();
    });
} else {
    CsrfAutoRefresh.initializeAll();
}

// Export for manual usage
export default CsrfAutoRefresh;