import { createContext, useState, useEffect, useCallback, useRef } from 'react';
import Lightswitch from '../core/index.js';
import { jsx } from 'react/jsx-runtime';
import { hasAuthTokensInUrl, extractTokensFromUrl } from '../utils/authHelpers.js';

/**
 * Lightswitch React Provider
 * 
 * React adapter that wraps the vanilla JS core SDK.
 * Provides React context and state management.
 */

const LightswitchContext = /*#__PURE__*/createContext(null);

/**
 * React Provider component for Lightswitch SDK
 * @param {Object} props - Component props
 * @param {React.ReactNode} props.children - Child components
 * @param {string} props.publishableKey - The publishable key for API requests
 * @param {string} [props.appSlug='default'] - The app slug for endpoint generation
 * @param {boolean} [props.autoAuth=true] - Whether to automatically check for auth tokens
 * @param {boolean} [props.autoExternalAuth=true] - Whether to automatically handle external auth tokens from URL
 * @param {boolean} [props.autoPageTracking=false] - Whether to automatically track page views
 * @param {boolean} [props.autoClickTracking=false] - Whether to automatically track clicks on interactive elements
 * @param {boolean} [props.autoShowPaywall=false] - Whether to automatically show paywall when user is not entitled
 * @param {Object} [props.supabaseClient] - Optional Supabase client instance
 */
const LightswitchProvider = _ref => {
  let {
    children,
    publishableKey,
    appSlug = 'default',
    autoAuth = true,
    autoExternalAuth = true,
    autoPageTracking = false,
    autoClickTracking = false,
    autoShowPaywall = false,
    supabaseClient = null
  } = _ref;
  // React state that mirrors the core SDK state
  const [authState, setAuthState] = useState({
    user: null,
    isAuthenticated: false,
    isLoading: false,
    error: null,
    authToken: null
  });
  const [isInitialized, setIsInitialized] = useState(false);
  const [isReady, setIsReady] = useState(false); // New ready state
  const [initError, setInitError] = useState(null);
  
  // Entitlement state
  const [entitlementState, setEntitlementState] = useState({
    entitled: false,
    loading: false,
    error: null,
    paywallConfigId: null,
    lastChecked: null
  });

  // Initialize the SDK
  useEffect(() => {
    const initSDK = async () => {
      try {
        console.log('🚀 Starting Lightswitch SDK initialization...', {
          publishableKey: publishableKey ? 'present' : 'missing',
          appSlug,
          autoAuth,
          supabaseClient: supabaseClient ? 'present' : 'missing'
        });
        
        setAuthState(prev => ({
          ...prev,
          isLoading: true
        }));
        
        await Lightswitch.init({
          publishableKey,
          appSlug,
          autoAuth,
          supabaseClient
        });
        
        setIsInitialized(true);
        console.log('✅ Lightswitch SDK initialized successfully');

        // Get initial auth state
        const initialState = Lightswitch.getAuthState();
        setAuthState(initialState);

        // Handle external auth tokens from URL (funnel returns)
        console.log('🔍 Checking for external auth tokens...', {
          autoExternalAuth,
          currentUrl: window.location.href,
          hasTokens: hasAuthTokensInUrl()
        });
        
        if (autoExternalAuth && hasAuthTokensInUrl()) {
          console.log('🔄 Detected external auth tokens in URL, processing...');
          
          try {
            const { accessToken, refreshToken, expiresAt } = extractTokensFromUrl();
            console.log('📋 Extracted tokens:', {
              hasAccessToken: !!accessToken,
              hasRefreshToken: !!refreshToken,
              expiresAt,
              accessTokenLength: accessToken?.length
            });
            
            if (accessToken) {
              console.log('🔄 Setting Supabase session from external auth token...');
              const success = await Lightswitch.setSupabaseSession(accessToken, refreshToken, expiresAt);
              
              if (success) {
                console.log('✅ External auth session set successfully');
                
                // Clean up URL parameters
                const cleanUrl = new URL(window.location);
                cleanUrl.searchParams.delete('token');
                cleanUrl.searchParams.delete('access_token');
                cleanUrl.searchParams.delete('refresh_token');
                cleanUrl.searchParams.delete('expires_at');
                
                window.history.replaceState({}, document.title, cleanUrl.toString());
                console.log('🧹 URL cleaned up after external auth processing');
                
                // The Supabase auth listener will handle updating the auth state
                // No need to manually update here
              } else {
                console.error('❌ Failed to set external auth session');
              }
            } else {
              console.error('❌ No access token found in extracted tokens');
            }
          } catch (error) {
            console.error('❌ Error processing external auth tokens:', error);
          }
        } else {
          const hasTokens = hasAuthTokensInUrl();
          const tokenData = extractTokensFromUrl();
          console.log('⏭️ Skipping external auth processing', {
            autoExternalAuth,
            hasTokens,
            tokenData,
            currentUrl: window.location.href
          });
        }

        // Set ready state - SDK is initialized and auth state is loaded
        setIsReady(true);
      } catch (error) {
        console.error('❌ Failed to initialize Lightswitch SDK:', error);
        console.error('❌ Error details:', {
          message: error.message,
          stack: error.stack,
          name: error.name
        });
        setInitError(error.message);
        setAuthState(prev => ({
          ...prev,
          isLoading: false,
          error: error.message
        }));
      }
    };
    initSDK();
  }, [publishableKey, appSlug, autoAuth, supabaseClient]);

  // Create a stable ref for the last entitlement check time
  const lastEntitlementCheckRef = useRef(null);
  const entitlementCheckInProgressRef = useRef(false);

  // Function to check entitlements with caching to prevent redundant calls
  const checkEntitlements = useCallback(async (force = false, overrideAuthState = null) => {
    const currentAuthState = overrideAuthState || authState;
    console.log('🔍 checkEntitlements called', { 
      force, 
      isInitialized, 
      isAuthenticated: currentAuthState.isAuthenticated,
      user: currentAuthState.user?.email,
      fullAuthState: currentAuthState,
      usingOverride: !!overrideAuthState
    });

    // Don't check if not ready
    if (!isInitialized || !currentAuthState.isAuthenticated) {
      console.log('❌ Not checking entitlements - not ready or not authenticated');
      setEntitlementState({
        entitled: false,
        loading: false,
        error: currentAuthState.isAuthenticated ? null : 'User not authenticated',
        paywallConfigId: null,
        lastChecked: null
      });
      return;
    }

    // Prevent redundant calls - only check if forced or if it's been more than 5 seconds (reduced for debugging)
    const now = Date.now();
    const lastCheck = lastEntitlementCheckRef.current;
    if (!force && lastCheck && (now - lastCheck) < 5000) {
      console.log('⏭️ Skipping entitlement check - recent check within 5 seconds');
      return;
    }

    // Prevent multiple concurrent calls
    if (entitlementCheckInProgressRef.current && !force) {
      console.log('⏭️ Skipping entitlement check - already in progress');
      return;
    }

    entitlementCheckInProgressRef.current = true;
    lastEntitlementCheckRef.current = now;

    setEntitlementState(prev => ({
      ...prev,
      loading: true,
      error: null
    }));

    try {
      console.log('🔍 Checking entitlements...');
      // Check general access entitlement (no feature parameter)
      const result = await Lightswitch.checkEntitlement();
      setEntitlementState({
        entitled: result.entitled,
        loading: false,
        error: result.error,
        paywallConfigId: result.paywallConfigId,
        lastChecked: new Date()
      });
      
      // Auto-show paywall if user is not entitled and autoShowPaywall is enabled
      if (autoShowPaywall && !result.entitled && result.paywallConfigId) {
        console.log('User not entitled, auto-showing paywall with config:', result.paywallConfigId);
        setTimeout(async () => {
          try {
            await Lightswitch.showPaywall({ 
              paywallConfigId: result.paywallConfigId,
              feature: 'has_access'
            });
          } catch (error) {
            console.error('Error auto-showing paywall:', error);
          }
        }, 500); // Small delay to ensure UI is ready
      }
    } catch (error) {
      console.error('Error checking entitlements:', error);
      setEntitlementState(prev => ({
        ...prev,
        loading: false,
        error: error.message || 'Failed to check entitlements'
      }));
    } finally {
      entitlementCheckInProgressRef.current = false;
    }
  }, [isInitialized, authState.isAuthenticated, autoShowPaywall]);

  // Initial entitlement check when SDK is ready and user is authenticated
  useEffect(() => {
    console.log('🔍 Entitlement check useEffect triggered:', {
      isInitialized,
      isAuthenticated: authState.isAuthenticated,
      isReady,
      shouldCheck: isInitialized && authState.isAuthenticated && isReady
    });
    
    if (isInitialized && authState.isAuthenticated && isReady) {
      console.log('🔄 SDK ready and user authenticated, doing initial entitlement check...');
      // Use setTimeout to avoid dependency issues
      setTimeout(() => checkEntitlements(true), 50);
    }
  }, [isInitialized, authState.isAuthenticated, isReady]);

  // Subscribe to auth state changes
  useEffect(() => {
    if (!isInitialized) return;
    const unsubscribe = Lightswitch.onAuthChange(newAuthState => {
      setAuthState(newAuthState);
      // Update ready state based on auth state
      setIsReady(true);
      
      // Check entitlements when auth state changes
      if (newAuthState.isAuthenticated) {
        // Small delay to ensure auth state is fully settled
        console.log('🔄 Auth state changed to authenticated, checking entitlements...');
        setTimeout(() => checkEntitlements(), 100);
      } else {
        // Clear entitlements when user logs out
        setEntitlementState({
          entitled: false,
          loading: false,
          error: null,
          paywallConfigId: null,
          lastChecked: null
        });
      }
    });
    return unsubscribe;
  }, [isInitialized]);

  // Monitor Supabase auth state changes directly (in addition to SDK auth changes)
  useEffect(() => {
    if (!supabaseClient) return;

    let unsubscribe = () => {};
    
    const setupSupabaseListener = async () => {
      try {
        // Get initial session
        const { data: { session } } = await supabaseClient.auth.getSession();
        
        // Set up auth state change listener
        const { data } = supabaseClient.auth.onAuthStateChange(async (event, session) => {
          console.log('🔔 Supabase auth state change:', {
            event,
            userId: session?.user?.id,
            userEmail: session?.user?.email,
            hasSession: !!session,
            accessToken: session?.access_token ? 'present' : 'missing'
          });
          
          if ((event === 'SIGNED_IN' || event === 'INITIAL_SESSION') && session) {
            // User signed in or session restored - sync Lightswitch auth state with Supabase session
            console.log('Syncing Lightswitch auth state with Supabase session (event:', event, ')');
            
            // Update Lightswitch core auth state to match Supabase
            const userData = {
              id: session.user.id,
              email: session.user.email || 'user@example.com',
              name: session.user.user_metadata?.full_name || session.user.email || 'User'
            };

            // Immediately update the React auth state to match Supabase session
            console.log('🔄 Immediately updating React auth state with session data');
            const newAuthState = {
              user: userData,
              isAuthenticated: true,
              isLoading: false,
              error: null,
              authToken: session.access_token
            };
            console.log('🔍 Setting auth state to:', newAuthState);
            setAuthState(newAuthState);
            
            // Set ready state immediately since we have a valid session
            setIsReady(true);
            
            // Also force a refresh of the core auth state to ensure everything is in sync
            if (isInitialized) {
              setTimeout(async () => {
                try {
                  await Lightswitch.initAuth?.();
                  console.log('✅ Core auth state refreshed after Supabase session change');
                } catch (error) {
                  console.error('Error refreshing core auth state:', error);
                }
              }, 50); // Reduced delay
            }
            
            // Check entitlements once SDK is initialized
            console.log('🔄 Supabase session set, will check entitlements once SDK is initialized...');
            if (isInitialized) {
              console.log('🔄 SDK already initialized, checking entitlements now...');
              checkEntitlements(true, newAuthState);
            } else {
              console.log('🔄 SDK not yet initialized, entitlements will be checked via useEffect...');
            }
          } else if (event === 'SIGNED_OUT') {
            // User signed out - refresh auth state to sync with Supabase
            console.log('User signed out via Supabase, refreshing auth state');
            
            if (isInitialized) {
              setTimeout(async () => {
                try {
                  await Lightswitch.initAuth();
                  console.log('✅ Auth state refreshed after Supabase sign out');
                } catch (error) {
                  console.error('Error refreshing auth state:', error);
                }
              }, 100);
            }
            
            setEntitlementState({
              entitled: false,
              loading: false,
              error: null,
              paywallConfigId: null,
              lastChecked: null
            });
          }
        });
        
        unsubscribe = () => data.subscription.unsubscribe();
      } catch (error) {
        console.error('Error setting up Supabase auth listener:', error);
      }
    };

    setupSupabaseListener();
    return unsubscribe;
  }, [supabaseClient]);

  // Auto page tracking setup
  useEffect(() => {
    if (!isInitialized || !autoPageTracking) return;
    if (typeof window === 'undefined' || typeof history === 'undefined') return;
    let lastPath = ''; // Initialize to empty string so first call will always trigger

    const track = () => {
      const currentPath = window.location.pathname + window.location.search;
      if (currentPath !== lastPath) {
        lastPath = currentPath;
        console.log('Automatically tracking page view', currentPath);
        // Use the core SDK directly to avoid initialization checks in wrapped methods
        Lightswitch.trackEvent('page_view', {}).catch(error => {
          console.warn('Auto page tracking failed:', error);
        });
      }
    };

    // Override history methods to detect programmatic navigation
    const originalPushState = history.pushState;
    history.pushState = function () {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }
      originalPushState.apply(this, args);
      // Small delay to ensure the DOM has updated
      setTimeout(track, 0);
    };
    const originalReplaceState = history.replaceState;
    history.replaceState = function () {
      for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
        args[_key2] = arguments[_key2];
      }
      originalReplaceState.apply(this, args);
      // Small delay to ensure the DOM has updated
      setTimeout(track, 0);
    };

    // Listen for browser back/forward navigation
    window.addEventListener('popstate', track);

    // Track initial page load
    track();

    // Cleanup function to restore original methods and remove listeners
    return () => {
      history.pushState = originalPushState;
      history.replaceState = originalReplaceState;
      window.removeEventListener('popstate', track);
    };
  }, [isInitialized, autoPageTracking]);

  // Auto click tracking setup
  useEffect(() => {
    if (!isInitialized || !autoClickTracking) return;
    if (typeof document === 'undefined') return;
    const handleClick = event => {
      try {
        const element = event.target;

        // Skip clicks on document/body or if no element
        if (!element || element === document || element === document.body) return;

        // Extract meaningful element information
        const elementInfo = {
          tag: element.tagName?.toLowerCase(),
          id: element.id || null,
          className: element.className || null,
          text: element.textContent?.trim().substring(0, 100) || null,
          // Limit text length
          type: element.type || null,
          // For inputs, buttons
          href: element.href || null,
          // For links
          role: element.getAttribute('role') || null,
          'data-track': element.getAttribute('data-track') || null // Custom tracking attribute
        };

        // Filter out empty/irrelevant data
        const cleanElementInfo = Object.fromEntries(Object.entries(elementInfo).filter(_ref2 => {
          let [key, value] = _ref2;
          return value !== null && value !== '';
        }));

        // Only track if we have meaningful element info
        if (Object.keys(cleanElementInfo).length > 1) {
          // More than just 'tag'
          console.log('Automatically tracking click', cleanElementInfo);
          Lightswitch.trackEvent('click', {
            element: cleanElementInfo,
            page: window.location.pathname + window.location.search
          }).catch(error => {
            console.warn('Auto click tracking failed:', error);
          });
        }
      } catch (error) {
        console.warn('Click tracking error:', error);
      }
    };

    // Add click listener
    document.addEventListener('click', handleClick, {
      passive: true
    });

    // Cleanup
    return () => {
      document.removeEventListener('click', handleClick);
    };
  }, [isInitialized, autoClickTracking]);

  // Enhanced wrapped methods that wait for ready state
  const createWrappedMethod = (method, methodName) => {
    return useCallback(async function () {
      if (!isReady) {
        // Wait for ready state with timeout
        const timeout = 5000; // 5 seconds
        const startTime = Date.now();
        while (!isReady && Date.now() - startTime < timeout) {
          await new Promise(resolve => setTimeout(resolve, 50));
        }
        if (!isReady) {
          throw new Error(`SDK not ready for ${methodName}. Initialization may have failed.`);
        }
      }
      return method(...arguments);
    }, [isReady]);
  };

  // Wrapped SDK methods that ensure initialization and readiness
  const wrappedMethods = {
    // Authentication methods
    login: useCallback(redirectUrl => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.login(redirectUrl);
    }, [isInitialized]),
    signup: useCallback(redirectUrl => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.signup(redirectUrl);
    }, [isInitialized]),
    logout: useCallback(async () => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.logout();
    }, [isInitialized]),
    authenticateWithToken: useCallback(async token => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.authenticateWithToken(token);
    }, [isInitialized]),
    setSupabaseSession: useCallback(async (accessToken, refreshToken, expiresAt) => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.setSupabaseSession(accessToken, refreshToken, expiresAt);
    }, [isInitialized]),
    // API methods - these need to wait for ready state
    fetchWithAuth: createWrappedMethod(Lightswitch.fetchWithAuth, 'fetchWithAuth'),
    callWithAuth: createWrappedMethod(Lightswitch.callWithAuth, 'callWithAuth'),
    // Entitlement methods
    checkEntitlement: createWrappedMethod(Lightswitch.checkEntitlement, 'checkEntitlement'),
    // Paywall methods
    showPaywall: useCallback(async options => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return await Lightswitch.showPaywall(options);
    }, [isInitialized]),
    closePaywall: useCallback(() => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.closePaywall();
    }, [isInitialized]),
    isPaywallOpen: useCallback(() => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.isPaywallOpen();
    }, [isInitialized]),
    getCurrentPaywall: useCallback(() => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.getCurrentPaywall();
    }, [isInitialized]),
    onPaywallEvent: useCallback(listener => {
      if (!isInitialized) {
        console.log('⏳ SDK not initialized yet, paywall event listener will be set up later');
        return () => {}; // Return empty cleanup function
      }
      return Lightswitch.onPaywallEvent(listener);
    }, [isInitialized]),
    // Utility methods
    createPaywallUrl: useCallback((paywallConfigId, token) => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.createPaywallUrl(paywallConfigId, token);
    }, [isInitialized]),
    // Configuration getters
    getConfig: useCallback(() => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.getConfig();
    }, [isInitialized]),
    getEndpoints: useCallback(() => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.getEndpoints();
    }, [isInitialized]),
    // Tracking methods (anonymous - no auth required)
    trackEvent: useCallback(async (eventType, params, options) => {
      if (!isInitialized) throw new Error('SDK not initialized');
      return Lightswitch.trackEvent(eventType, params, options);
    }, [isInitialized])
  };

  // Debug logging for context value (only when state changes)
  if (isInitialized && authState.isAuthenticated) {
    console.log('🔄 LightswitchProvider context update:', {
      isAuthenticated: authState.isAuthenticated,
      entitled: entitlementState.entitled,
      entitlementLoading: entitlementState.loading,
      user: authState.user?.email
    });
  }

  // Context value
  const contextValue = {
    // Auth state
    ...authState,
    // Entitlement state
    entitled: entitlementState.entitled,
    entitlementLoading: entitlementState.loading,
    entitlementError: entitlementState.error,
    paywallConfigId: entitlementState.paywallConfigId,
    lastEntitlementCheck: entitlementState.lastChecked,
    // SDK state
    isInitialized,
    isReady,
    // New ready state
    initError,
    // Configuration
    publishableKey,
    appSlug,
    autoPageTracking,
    autoClickTracking,
    autoShowPaywall,
    autoExternalAuth,
    // All SDK methods
    ...wrappedMethods,
    // Entitlement methods
    checkEntitlements,
    refreshEntitlements: checkEntitlements,
    // Direct access to core SDK (for advanced usage)
    core: isInitialized ? Lightswitch : null
  };
  return /*#__PURE__*/jsx(LightswitchContext.Provider, {
    value: contextValue,
    children: children
  });
};

export { LightswitchContext, LightswitchProvider };
//# sourceMappingURL=LightswitchProvider.js.map
