'use client';

import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { useRouter } from 'next/navigation';
import apiClient from '@/lib/api/client';
import { tokenStorage } from '@/lib/utils/tokenStorage';
import { handleError, formatErrorMessage } from '@/lib/utils/errorHandler';

export interface User {
  id: string;
  email: string;
  name: string;
  photoUrl?: string;
  role: string;
  families?: Array<{
    id: string;
    familyId: string;
    role: string;
  }>;
  eulaAcceptedAt?: string | null;
  eulaVersion?: string | null;
}

export interface LoginCredentials {
  email: string;
  password: string;
  deviceFingerprint?: string;
}

export interface RegisterData {
  email: string;
  password: string;
  name: string;
  role?: string;
  inviteCode?: string; // Required if REGISTRATION_MODE=invite_only
  dateOfBirth: string; // COPPA compliance - required
  parentalEmail?: string; // For users 13-17
  coppaConsentGiven?: boolean; // For users 13-17
}

interface AuthContextType {
  user: User | null;
  token: string | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: (credentials: LoginCredentials) => Promise<void>;
  register: (data: RegisterData) => Promise<void>;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const router = useRouter();

  const isAuthenticated = !!user;

  // Check authentication status on mount
  useEffect(() => {
    // Only run on client side
    if (typeof window !== 'undefined') {
      checkAuth();
    } else {
      setIsLoading(false);
    }
  }, []);

  const checkAuth = async () => {
    // Ensure we're on client side
    if (typeof window === 'undefined') {
      setIsLoading(false);
      return;
    }

    try {
      const accessToken = tokenStorage.getAccessToken();
      const refreshToken = tokenStorage.getRefreshToken();

      console.log('[AuthContext] checkAuth - tokens present:', {
        hasAccess: !!accessToken,
        hasRefresh: !!refreshToken
      });

      if (!accessToken && !refreshToken) {
        console.log('[AuthContext] No tokens found, user not authenticated');
        setUser(null);
        setToken(null);
        setIsLoading(false);
        return;
      }

      // If we only have refresh token but no access token, don't make /me call
      // The axios interceptor will handle getting a new access token when needed
      if (!accessToken && refreshToken) {
        console.log('[AuthContext] Only refresh token present, skipping /me call');
        setUser(null);
        setToken(null);
        setIsLoading(false);
        return;
      }

      // If we only have access token but no refresh token, it might be a timing issue
      // during login (React Strict Mode). Give it a moment and check again.
      if (accessToken && !refreshToken) {
        console.log('[AuthContext] Only access token present, checking if this is temporary...');

        // Wait a tiny bit and check again (for React Strict Mode race condition)
        await new Promise(resolve => setTimeout(resolve, 10));
        const refreshTokenRetry = tokenStorage.getRefreshToken();

        if (!refreshTokenRetry) {
          console.log('[AuthContext] Still no refresh token after retry, clearing invalid state');
          tokenStorage.clearTokens();
          setUser(null);
          setToken(null);
          setIsLoading(false);
          return;
        } else {
          console.log('[AuthContext] Refresh token found on retry, proceeding with auth check');
          // Update local variable for the rest of the function
        }
      }

      // At this point we have both tokens - proceed with auth check
      // Set token in state if we have one
      if (accessToken) {
        setToken(accessToken);
      }

      const response = await apiClient.get('/api/v1/auth/me');

      console.log('[AuthContext] /me response:', response.data);

      // Check if response has expected structure
      if (response.data?.data) {
        console.log('[AuthContext] Setting user from response.data.data:', response.data.data);
        console.log('[AuthContext] EULA fields from /me:', {
          eulaAcceptedAt: response.data.data.eulaAcceptedAt,
          eulaVersion: response.data.data.eulaVersion,
        });
        setUser(response.data.data);
      } else if (response.data?.user) {
        // Handle alternative response structure
        console.log('[AuthContext] Setting user from response.data.user:', response.data.user);
        setUser(response.data.user);
      } else {
        throw new Error('Invalid response structure');
      }
    } catch (error: any) {
      console.error('[AuthContext] Auth check failed:', error);
      // Don't clear tokens on 401 during initial auth check
      // The axios interceptor in client.ts will handle token refresh automatically
      // Only clear tokens if the error is NOT a 401 (e.g., network error, 403, etc.)
      // Or if there's no refresh token available (meaning refresh already failed)
      const hasRefreshToken = tokenStorage.getRefreshToken();

      if (!hasRefreshToken) {
        // No refresh token means we can't recover - clear everything
        console.log('[AuthContext] No refresh token available, clearing auth state');
        tokenStorage.clearTokens();
        setUser(null);
        setToken(null);
      } else if (error?.response?.status === 401) {
        // 401 with refresh token - let axios interceptor handle refresh
        console.log('[AuthContext] 401 error but refresh token exists, letting axios interceptor handle refresh');
        // Don't clear tokens - the axios interceptor will attempt refresh
        setUser(null);
        setToken(null);
      } else if (error?.response?.status === 403) {
        // 403 means forbidden - clear tokens
        console.log('[AuthContext] 403 Forbidden, clearing auth state');
        tokenStorage.clearTokens();
        setUser(null);
        setToken(null);
      }
    } finally {
      setIsLoading(false);
    }
  };

  const login = async (credentials: LoginCredentials) => {
    try {
      const deviceId = generateDeviceFingerprint();
      const deviceInfo = {
        deviceId,
        platform: 'web',
        model: navigator.userAgent,
        osVersion: navigator.platform,
      };

      const response = await apiClient.post('/api/v1/auth/login', {
        email: credentials.email,
        password: credentials.password,
        deviceInfo,
      });

      // Backend returns { success, data: { user, tokens } }
      const { data: responseData } = response.data;
      const { tokens, user: userData } = responseData;

      console.log('[AuthContext] Login response user data:', userData);
      console.log('[AuthContext] EULA fields:', {
        eulaAcceptedAt: userData.eulaAcceptedAt,
        eulaVersion: userData.eulaVersion,
      });

      // Store tokens and deviceId
      tokenStorage.setTokens(tokens.accessToken, tokens.refreshToken, deviceId);
      setToken(tokens.accessToken);
      setUser(userData);

      router.push('/');
    } catch (error: any) {
      const errorMessage = handleError(error, 'AuthContext.login');
      throw new Error(errorMessage);
    }
  };

  const register = async (data: RegisterData) => {
    try {
      const deviceId = generateDeviceFingerprint();
      const deviceInfo = {
        deviceId,
        platform: 'web',
        model: navigator.userAgent,
        osVersion: navigator.platform,
      };

      // Auto-detect timezone from user's device
      const detectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;

      const payload: any = {
        email: data.email,
        password: data.password,
        name: data.name,
        timezone: detectedTimezone || 'UTC',
        dateOfBirth: data.dateOfBirth,
        deviceInfo,
      };

      // Add optional invite code if provided
      if (data.inviteCode) {
        payload.inviteCode = data.inviteCode;
      }

      // Add optional COPPA fields if provided
      if (data.parentalEmail) {
        payload.parentalEmail = data.parentalEmail;
      }
      if (data.coppaConsentGiven !== undefined) {
        payload.coppaConsentGiven = data.coppaConsentGiven;
      }

      console.log('[Auth] Registration payload:', JSON.stringify(payload, null, 2));

      const response = await apiClient.post('/api/v1/auth/register', payload);

      // Backend returns { success, data: { user, family, tokens } }
      const { data: responseData } = response.data;
      const { tokens, user: userData, family: familyData } = responseData;

      if (!tokens?.accessToken || !tokens?.refreshToken) {
        throw new Error('Invalid response from server');
      }

      const { accessToken, refreshToken } = tokens;

      // Add family data to user object (registration returns family separately)
      const userWithFamily = {
        ...userData,
        families: familyData ? [{
          id: familyData.id,
          familyId: familyData.id,
          role: familyData.role || 'parent',
        }] : [],
      };

      tokenStorage.setTokens(accessToken, refreshToken, deviceId);
      setToken(accessToken);
      setUser(userWithFamily);

      // Redirect to onboarding
      router.push('/onboarding');
    } catch (error: any) {
      const errorMessage = handleError(error, 'AuthContext.register');
      throw new Error(errorMessage);
    }
  };

  const logout = async () => {
    try {
      await apiClient.post('/api/v1/auth/logout');
    } catch (error) {
      console.error('Logout failed:', error);
    } finally {
      tokenStorage.clearTokens();
      setUser(null);
      setToken(null);

      // Clear all localStorage and sessionStorage to remove cached data
      // This ensures a fresh start on next login
      if (typeof window !== 'undefined') {
        localStorage.clear();
        sessionStorage.clear();
        console.log('[AuthContext] Cleared all browser storage on logout');
      }

      router.push('/login');
    }
  };

  const refreshUser = async () => {
    try {
      const response = await apiClient.get('/api/v1/auth/me');
      setUser(response.data.data);
    } catch (error) {
      console.error('Failed to refresh user:', error);
    }
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        token,
        isLoading,
        isAuthenticated,
        login,
        register,
        logout,
        refreshUser,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};

// Helper function to generate a simple device fingerprint
function generateDeviceFingerprint(): string {
  const navigator = window.navigator;
  const screen = window.screen;

  const data = [
    navigator.userAgent,
    navigator.language,
    screen.colorDepth,
    screen.width,
    screen.height,
    new Date().getTimezoneOffset(),
  ].join('|');

  // Simple hash function
  let hash = 0;
  for (let i = 0; i < data.length; i++) {
    const char = data.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash;
  }

  return hash.toString(36);
}
