/**
 * @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, setAuthReady } from '../api/client';
import { createIndexedDBAdapter } from '../utils/indexeddb-storage';
import { setAuthInitialized } from './auth-gate';

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;

  // Basic component loading debug
  console.log('[Auth0Provider] Component loaded', { domain, clientId, audience });


  const onRedirectCallback = (appState?: { returnTo?: string }) => {
    console.log('[Auth0Provider] Redirect callback triggered', { appState, returnTo: appState?.returnTo });
    // Route to callback page which will check user status and redirect appropriately
    // Pass the intended destination as state for after status check
    navigate('/callback', {
      replace: true,
      state: { returnTo: appState?.returnTo || '/garage' },
    });
  };

  return (
    <BaseAuth0Provider
      domain={domain}
      clientId={clientId}
      authorizationParams={{
        // Dynamic callback - supports staging (staging.motovaultpro.com) and production (motovaultpro.com)
        redirect_uri: `${window.location.origin}/callback`,
        audience: audience,
        scope: 'openid profile email offline_access',
      }}
      onRedirectCallback={onRedirectCallback}
      // Mobile-optimized: use IndexedDB for better mobile compatibility
      cache={createIndexedDBAdapter()}
      useRefreshTokens={true}
      useRefreshTokensFallback={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, isLoading, user } = useAuth0();
  const [retryCount, setRetryCount] = React.useState(0);

  // Basic component loading debug
  console.log('[TokenInjector] Component loaded');

  // Debug mobile authentication state
  React.useEffect(() => {
    const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    console.log(`[Auth Debug] Mobile: ${isMobile}, Loading: ${isLoading}, Authenticated: ${isAuthenticated}, User: ${user ? 'present' : 'null'}`);
  }, [isAuthenticated, isLoading, user]);

  // Helper function to get token with enhanced retry logic for mobile devices
  const getTokenWithRetry = async (maxRetries = 5, delayMs = 300): Promise<any> => {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        // Enhanced progressive strategy for mobile compatibility
        let tokenOptions: any;
        if (attempt === 0) {
          // First attempt: try cache with shorter timeout
          tokenOptions = { timeoutInSeconds: 10, cacheMode: 'on' as const };
        } else if (attempt === 1) {
          // Second attempt: cache with longer timeout
          tokenOptions = { timeoutInSeconds: 20, cacheMode: 'on' as const };
        } else if (attempt === 2) {
          // Third attempt: force refresh with reasonable timeout
          tokenOptions = { timeoutInSeconds: 15, cacheMode: 'off' as const };
        } else if (attempt === 3) {
          // Fourth attempt: force refresh with longer timeout
          tokenOptions = { timeoutInSeconds: 30, cacheMode: 'off' as const };
        } else {
          // Final attempt: default behavior with maximum timeout
          tokenOptions = { timeoutInSeconds: 45 };
        }

        const token = await getAccessTokenSilently(tokenOptions);
        console.log(`[Mobile Auth] Token acquired successfully on attempt ${attempt + 1}`, {
          cacheMode: tokenOptions.cacheMode,
          timeout: tokenOptions.timeoutInSeconds
        });
        return token;
      } catch (error: any) {
        console.warn(`[Mobile Auth] Attempt ${attempt + 1}/${maxRetries} failed:`, {
          error: error.message || error,
          cacheMode: attempt <= 2 ? 'on' : 'off'
        });

        // Mobile-specific: longer delays and more attempts
        if (attempt < maxRetries - 1) {
          const delay = delayMs * Math.pow(1.5, attempt); // Gentler exponential backoff
          console.log(`[Mobile Auth] Waiting ${Math.round(delay)}ms before retry...`);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    console.error('[Mobile Auth] All token acquisition attempts failed - authentication may be broken');
    return null;
  };

  // Force authentication check for devices when user seems logged in but isAuthenticated is false
  React.useEffect(() => {
    const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

    // Debug current state
    console.log('[Auth Debug] State check:', {
      isMobile,
      isLoading,
      isAuthenticated,
      pathname: window.location.pathname,
      userAgent: navigator.userAgent.substring(0, 50) + '...'
    });

    // Trigger for mobile devices OR any device on protected route without authentication
    if (!isLoading && !isAuthenticated && window.location.pathname !== '/') {
      console.log('[Auth Debug] User on protected route but not authenticated, forcing token check...');

      // Aggressive token check
      const forceAuthCheck = async () => {
        try {
          // Try multiple approaches to get token
          const token = await getAccessTokenSilently({
            cacheMode: 'off' as const,
            timeoutInSeconds: 10
          });
          console.log('[Auth Debug] Force auth successful, token acquired');

          // Manually add to API client since isAuthenticated might still be false
          if (token) {
            console.log('[Auth Debug] Manually adding token to API client');
            // Force add the token to subsequent requests
            apiClient.interceptors.request.use((config) => {
              if (!config.headers.Authorization) {
                config.headers.Authorization = `Bearer ${token}`;
                console.log('[Auth Debug] Token manually added to request');
              }
              return config;
            });
            setAuthReady(true);
          }
        } catch (error: any) {
          console.log('[Auth Debug] Force auth failed:', error.message);
        }
      };

      forceAuthCheck();
    }
  }, [isLoading, isAuthenticated, getAccessTokenSilently]);

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

    if (isAuthenticated) {
      // Enhanced pre-warm token cache for mobile devices with IndexedDB wait
      const initializeToken = async () => {
        // Wait for IndexedDB to be ready first
        try {
          const { indexedDBStorage } = await import('../utils/indexeddb-storage');
          await indexedDBStorage.waitForReady();
          console.log('[Auth] IndexedDB storage is ready');
        } catch (error) {
          console.warn('[Auth] IndexedDB not ready, proceeding anyway:', error);
        }

        // Minimal delay only for mobile devices (desktop needs no delay since IndexedDB is already ready)
        const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        if (isMobile) {
          // Small delay for mobile browsers to settle after IndexedDB init
          console.log('[Mobile Auth] Initializing token cache (mobile: true, delay: 50ms)');
          await new Promise(resolve => setTimeout(resolve, 50));
        } else {
          console.log('[Auth] Initializing token cache (desktop, no delay)');
        }

        try {
          const token = await getTokenWithRetry();
          if (token) {
            console.log('[Mobile Auth] Token pre-warming successful');
            setRetryCount(0);
            setAuthReady(true);
            setAuthInitialized(true); // Signal that auth is fully ready
          } else {
            console.error('[Mobile Auth] Failed to acquire token after retries - will retry on API calls');
            setRetryCount(prev => prev + 1);
          }
        } catch (error) {
          console.error('[Mobile Auth] Token initialization failed:', error);
          setRetryCount(prev => prev + 1);
        }
      };

      initializeToken();

      // Add token to all API requests with enhanced error handling and IndexedDB wait
      interceptorId = apiClient.interceptors.request.use(async (config) => {
        try {
          // Ensure IndexedDB is ready before getting tokens
          const { indexedDBStorage } = await import('../utils/indexeddb-storage');
          await indexedDBStorage.waitForReady();

          const token = await getTokenWithRetry();
          if (token) {
            config.headers.Authorization = `Bearer ${token}`;
            setAuthReady(true);
          } 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);
      setAuthReady(false);
      setAuthInitialized(false); // Reset auth gate when not authenticated
    }

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

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