/**
 * Global CSRF Token Management Utility
 * Handles CSRF token retrieval, refresh, and automatic retry logic for 419 errors
 * 
 * Usage:
 * - CSRFManager.getToken() - Get current CSRF token
 * - CSRFManager.refreshToken() - Manually refresh CSRF token
 * - CSRFManager.handleRequest(fetchConfig) - Wrapper for fetch with automatic CSRF handling
 * - CSRFManager.addTokenToHeaders(headers) - Add CSRF token to existing headers object
 */

window.CSRFManager = (function() {
    'use strict';

    let isRefreshing = false;
    let refreshPromise = null;

    /**
     * Get the current CSRF token from the meta tag
     * @returns {string|null} CSRF token or null if not found
     */
    function getToken() {
        const tokenElement = document.querySelector('meta[name="csrf-token"]');
        return tokenElement ? tokenElement.getAttribute('content') : null;
    }

    /**
     * Update the CSRF token in the meta tag
     * @param {string} newToken - New CSRF token
     */
    function setToken(newToken) {
        const tokenElement = document.querySelector('meta[name="csrf-token"]');
        if (tokenElement && newToken) {
            tokenElement.setAttribute('content', newToken);
            console.log('[CSRF Manager] Token updated successfully');
        }
    }

    /**
     * Refresh the CSRF token by making a GET request to current page
     * @returns {Promise<string|null>} Promise resolving to new token or null if failed
     */
    async function refreshToken() {
        // Prevent multiple simultaneous refresh attempts
        if (isRefreshing) {
            return refreshPromise;
        }

        isRefreshing = true;
        refreshPromise = (async () => {
            try {
                console.log('[CSRF Manager] Refreshing CSRF token...');
                
                const response = await fetch(window.location.pathname, {
                    method: 'GET',
                    headers: { 
                        'Accept': 'text/html',
                        'X-Requested-With': 'XMLHttpRequest'
                    },
                    credentials: 'same-origin'
                });

                if (response.ok) {
                    const html = await response.text();
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(html, 'text/html');
                    const newToken = doc.querySelector('meta[name="csrf-token"]')?.getAttribute('content');

                    if (newToken) {
                        setToken(newToken);
                        console.log('[CSRF Manager] Fresh token obtained');
                        return newToken;
                    }
                }
                
                console.error('[CSRF Manager] Failed to refresh token - response not ok or token not found');
                return null;
            } catch (error) {
                console.error('[CSRF Manager] Token refresh failed:', error);
                return null;
            } finally {
                isRefreshing = false;
                refreshPromise = null;
            }
        })();

        return refreshPromise;
    }

    /**
     * Add CSRF token to headers object
     * @param {Object} headers - Headers object to modify
     * @returns {Object} Modified headers object
     */
    function addTokenToHeaders(headers = {}) {
        const token = getToken();
        if (token) {
            headers['X-CSRF-TOKEN'] = token;
        }
        return headers;
    }

    /**
     * Enhanced fetch wrapper with automatic CSRF token handling and 419 retry logic
     * @param {string} url - Request URL
     * @param {Object} options - Fetch options
     * @param {number} maxRetries - Maximum number of retry attempts (default: 2)
     * @returns {Promise<Response>} Fetch response
     */
    async function handleRequest(url, options = {}, maxRetries = 2) {
        let retryCount = 0;

        // Ensure headers object exists
        options.headers = options.headers || {};

        // Add Content-Type for POST requests if not set
        if ((options.method || 'GET').toUpperCase() !== 'GET' && !options.headers['Content-Type']) {
            options.headers['Content-Type'] = 'application/json';
        }

        async function attemptRequest() {
            // Add/update CSRF token to headers
            addTokenToHeaders(options.headers);

            console.log('[CSRF Manager] Making request to:', url, 'Retry count:', retryCount);
            
            const response = await fetch(url, options);

            // Handle 419 CSRF token mismatch errors
            if (response.status === 419 && retryCount < maxRetries) {
                console.log('[CSRF Manager] 419 error detected, attempting token refresh...');
                
                const newToken = await refreshToken();
                
                if (newToken) {
                    retryCount++;
                    console.log('[CSRF Manager] Retrying request with fresh token...');
                    return attemptRequest();
                } else {
                    // Token refresh failed, show user-friendly message
                    console.log('[CSRF Manager] Token refresh failed, requesting page reload...');
                    if (confirm('Session expired due to network changes. Click OK to refresh and try again.')) {
                        window.location.reload();
                    }
                    return response;
                }
            }

            return response;
        }

        return attemptRequest();
    }

    /**
     * jQuery AJAX setup for automatic CSRF token inclusion
     */
    function setupjQueryCSRF() {
        if (typeof $ !== 'undefined' && $.ajaxSetup) {
            $.ajaxSetup({
                beforeSend: function(xhr, settings) {
                    // Skip CSRF for GET requests and cross-domain requests
                    if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
                        const token = getToken();
                        if (token) {
                            xhr.setRequestHeader('X-CSRF-TOKEN', token);
                        }
                    }
                }
            });
            console.log('[CSRF Manager] jQuery AJAX CSRF setup complete');
        }
    }

    /**
     * Axios interceptors for automatic CSRF token inclusion
     */
    function setupAxiosCSRF() {
        if (typeof axios !== 'undefined') {
            // Request interceptor to add CSRF token
            axios.interceptors.request.use(function (config) {
                const token = getToken();
                if (token && !/^(GET|HEAD|OPTIONS|TRACE)$/i.test(config.method)) {
                    config.headers['X-CSRF-TOKEN'] = token;
                }
                return config;
            });

            // Response interceptor to handle 419 errors
            axios.interceptors.response.use(
                response => response,
                async error => {
                    if (error.response && error.response.status === 419 && !error.config._retry) {
                        error.config._retry = true;
                        
                        const newToken = await refreshToken();
                        if (newToken) {
                            error.config.headers['X-CSRF-TOKEN'] = newToken;
                            return axios.request(error.config);
                        } else {
                            if (confirm('Session expired due to network changes. Click OK to refresh and try again.')) {
                                window.location.reload();
                            }
                        }
                    }
                    return Promise.reject(error);
                }
            );
            console.log('[CSRF Manager] Axios CSRF setup complete');
        }
    }

    /**
     * Initialize CSRF manager - sets up jQuery and Axios if available
     */
    function init() {
        console.log('[CSRF Manager] Initializing...');
        setupjQueryCSRF();
        setupAxiosCSRF();
        console.log('[CSRF Manager] Initialization complete');
    }

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

    // Public API
    return {
        getToken,
        refreshToken,
        addTokenToHeaders,
        handleRequest,
        init
    };
})();