/**
 * @ai-summary Auth0 provider wrapper with API token injection
 */

import React from 'react';
import { Auth0Provider as BaseAuth0Provider, useAuth0 } from '@auth0/auth0-react';
import { useNavigate } from 'react-router-dom';
import { apiClient } from '../api/client';

interface Auth0ProviderProps {
  children: React.ReactNode;
}

export const Auth0Provider: React.FC<Auth0ProviderProps> = ({ children }) => {
  const navigate = useNavigate();

  const domain = import.meta.env.VITE_AUTH0_DOMAIN;
  const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;
  const audience = import.meta.env.VITE_AUTH0_AUDIENCE;


  const onRedirectCallback = (appState?: { returnTo?: string }) => {
    navigate(appState?.returnTo || '/dashboard');
  };

  return (
    <BaseAuth0Provider
      domain={domain}
      clientId={clientId}
      authorizationParams={{
        redirect_uri: window.location.origin,
        audience: audience,
      }}
      onRedirectCallback={onRedirectCallback}
      cacheLocation="localstorage"
      useRefreshTokens={true}
    >
      <TokenInjector>{children}</TokenInjector>
    </BaseAuth0Provider>
  );
};

// Component to inject token into API client with mobile support
const TokenInjector: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const { getAccessTokenSilently, isAuthenticated } = useAuth0();
  const [retryCount, setRetryCount] = React.useState(0);

  // Helper function to get token with retry logic for mobile devices
  const getTokenWithRetry = async (maxRetries = 3, delayMs = 500): Promise<string | null> => {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        // Progressive fallback strategy for mobile compatibility
        let tokenOptions;
        if (attempt === 0) {
          // First attempt: try cache first
          tokenOptions = { timeoutInSeconds: 15, cacheMode: 'on' as const };
        } else if (attempt === 1) {
          // Second attempt: force refresh
          tokenOptions = { timeoutInSeconds: 20, cacheMode: 'off' as const };
        } else {
          // Final attempt: default behavior with longer timeout
          tokenOptions = { timeoutInSeconds: 30 };
        }

        const token = await getAccessTokenSilently(tokenOptions);
        console.log(`Token acquired successfully on attempt ${attempt + 1}`);
        return token;
      } catch (error: any) {
        console.warn(`Token acquisition attempt ${attempt + 1} failed:`, error.message || error);
        
        // On mobile, Auth0 might need more time - wait and retry
        if (attempt < maxRetries - 1) {
          const delay = delayMs * Math.pow(2, attempt); // Exponential backoff
          console.log(`Waiting ${delay}ms before retry...`);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    console.error('All token acquisition attempts failed');
    return null;
  };

  React.useEffect(() => {
    let interceptorId: number | undefined;

    if (isAuthenticated) {
      // Pre-warm token cache for mobile devices with delay
      const initializeToken = async () => {
        // Give Auth0 a moment to fully initialize on mobile
        await new Promise(resolve => setTimeout(resolve, 100));
        
        try {
          const token = await getTokenWithRetry();
          if (token) {
            console.log('Token pre-warming successful');
            setRetryCount(0);
          } else {
            console.error('Failed to acquire token after retries - will retry on API calls');
            setRetryCount(prev => prev + 1);
          }
        } catch (error) {
          console.error('Token initialization failed:', error);
          setRetryCount(prev => prev + 1);
        }
      };

      initializeToken();

      // Add token to all API requests with enhanced error handling
      interceptorId = apiClient.interceptors.request.use(async (config) => {
        try {
          const token = await getTokenWithRetry();
          if (token) {
            config.headers.Authorization = `Bearer ${token}`;
          } else {
            console.error('No token available for request to:', config.url);
            // Allow request to proceed - backend will return 401 if needed
          }
        } catch (error: any) {
          console.error('Failed to get access token for request:', error.message || error);
          // Allow request to proceed - backend will return 401 if needed
        }
        return config;
      });
    } else {
      setRetryCount(0);
    }

    // Cleanup function to remove interceptor
    return () => {
      if (interceptorId !== undefined) {
        apiClient.interceptors.request.eject(interceptorId);
      }
    };
  }, [isAuthenticated, getAccessTokenSilently, retryCount]);

  return <>{children}</>;
};