/**
 * CSRF Token Utility
 *
 * Provides utilities for managing CSRF tokens in the application.
 * Solves the issue where CSRF tokens expire after 2 hours (120 minutes)
 * when users keep the article editing page open for extended periods.
 */

let cachedToken: string | null = null;
let tokenExpiry: number = 0;

/**
 * Get a fresh CSRF token from the server
 */
async function getFreshCSRFToken(): Promise<string> {
  try {
    const response = await fetch('/admin/csrf-token', {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
      },
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`);
    }

    const data = await response.json();
    return data.token;
  } catch (error) {
    console.error('Error fetching fresh CSRF token:', error);
    // Fallback to meta tag token
    return getMetaCSRFToken();
  }
}

/**
 * Get CSRF token from meta tag
 */
function getMetaCSRFToken(): string {
  const metaTag = document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement;
  return metaTag?.content || '';
}

/**
 * Get a valid CSRF token, refreshing if necessary
 *
 * This function implements a caching mechanism with expiry to avoid
 * unnecessary requests while ensuring tokens are fresh.
 */
export async function getValidCSRFToken(): Promise<string> {
  const now = Date.now();

  // If we have a cached token that's still valid (refresh every 30 minutes)
  if (cachedToken && now < tokenExpiry) {
    return cachedToken;
  }

  // Get a fresh token
  const freshToken = await getFreshCSRFToken();

  // Cache the token for 30 minutes (1800000 ms)
  // This is safely within the 120-minute session lifetime
  cachedToken = freshToken;
  tokenExpiry = now + 30 * 60 * 1000;

  // Also update the meta tag for other parts of the app
  const metaTag = document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement;
  if (metaTag) {
    metaTag.content = freshToken;
  }

  return freshToken;
}

/**
 * Force refresh the CSRF token cache
 * Useful when a request fails with a CSRF error
 */
export async function refreshCSRFToken(): Promise<string> {
  cachedToken = null;
  tokenExpiry = 0;
  return getValidCSRFToken();
}

/**
 * Handle CSRF token mismatch errors
 *
 * @param error - The error from the failed request
 * @param retryCallback - Function to retry the original request with new token
 */
export async function handleCSRFError(error: any, retryCallback?: (token: string) => Promise<any>): Promise<any> {
  // Check if it's a CSRF error (status 419 or specific error message)
  if (error.status === 419 || error.message?.includes('CSRF') || error.message?.includes('token')) {
    console.warn('CSRF token expired, refreshing and retrying...');

    // Get a fresh token
    const newToken = await refreshCSRFToken();

    // Retry the original request if callback provided
    if (retryCallback) {
      return retryCallback(newToken);
    }

    return newToken;
  }

  // If it's not a CSRF error, re-throw it
  throw error;
}
