import { useState } from 'react';

import { useMsal } from '@azure/msal-react';
import api from '../api';
import { useApiRequest } from './useApi';
import { getApiBaseUrl } from '../../config/config';
import { setUserDataCache, clearUserDataCache, type CachedUserData } from '../utils/userCache';
import {
  loginApi,
  fetchCurrentUserApi,
  registerApi,
  registerWithMsalApi,
  checkUsernameAvailabilityApi,
  logoutApi,
  requestPasswordResetApi,
  resetPasswordApi,
  type LoginResponse,
  type RegisterResponse,
  type UsernameAvailabilityResponse,
  type RegisterData,
  type MsalRegisterData,
  type PasswordResetRequestResponse,
  type PasswordResetResponse
} from '../api/authApi';

// Regular authentication
export function useAuth() {
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  const login = async (username: string, password: string): Promise<LoginResponse> => {
    setIsLoading(true);
    setError(null);

    try {
      const response = await loginApi({ username, password });

      // Tokens are automatically set in httpOnly cookies by backend
      if (response.type === 'local_auth_success') {
        if (response.authenticationAuthority) {
          // Use sessionStorage for non-sensitive routing hint (cleared when tab closes)
          sessionStorage.setItem('auth_authority', response.authenticationAuthority);
        }
        
        // CRITICAL: Immediately fetch user data after successful login
        try {
          const userData = await fetchCurrentUserApi();
          
          if (userData) {
            // Cache user data in sessionStorage (cleared on tab close - more secure than localStorage)
            setUserDataCache(userData as CachedUserData);
          }
        } catch (userError) {
          console.error('Failed to fetch user data after login:', userError);
        }
        
        return response;
      }
      throw new Error('Login failed');
    } catch (error: any) {
      let errorMessage = 'An error occurred during login';
      
      console.error('Login error:', error);
      
      if (error.response) {
        // Handle different error response formats
        if (error.response.data?.detail) {
          if (Array.isArray(error.response.data.detail)) {
            errorMessage = error.response.data.detail.map((err: any) => err.msg || err).join(', ');
          } else {
            errorMessage = error.response.data.detail;
          }
        } else if (error.response.data?.message) {
          errorMessage = error.response.data.message;
        } else if (error.response.status === 500) {
          errorMessage = 'Server error during login. Please try again.';
        } else {
          errorMessage = 'Invalid username or password';
        }
      } else if (error.request) {
        errorMessage = 'No response received from server';
      } else {
        errorMessage = error.message;
      }
      
      setError(errorMessage);
      throw error;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    login,
    error,
    isLoading
  };
}

// Microsoft Authentication
interface MsalAuthResponse {
  accessToken: string;
  tokenType: string;
  user: {
    username: string;
    email: string;
    fullName: string;
    mandateId: number;
  };
}

export function useMsalAuth() {
  const [msalError, setMsalError] = useState<string | null>(null);
  const [isMsalLoading, setIsMsalLoading] = useState(false);

  const loginWithMsal = async (): Promise<MsalAuthResponse> => {
    setIsMsalLoading(true);
    setMsalError(null);

    try {
      return new Promise((resolve, reject) => {
        const backendUrl = getApiBaseUrl();
        
        // Open popup window
        const popup = window.open(
          `${backendUrl}/api/msft/login?state=login`,
          'microsoft-login',
          'width=600,height=700,left=100,top=100'
        );

        if (!popup) {
          const errorMsg = 'Popup was blocked by browser. Please allow popups for this site and try again.';
          console.error('Popup blocked:', errorMsg);
          setMsalError(errorMsg);
          setIsMsalLoading(false);
          reject(new Error('Popup was blocked'));
          return;
        }

        // Listen for messages from the popup
        const messageListener = (event: MessageEvent) => {
          // Filter out React DevTools messages
          if (event.data?.source?.includes('react-devtools') || 
              event.data?.source?.includes('devtools') ||
              event.data?.hello === true) {
            return; // Ignore React DevTools messages
          }
          
          // Verify the message origin for security (should match backend origin)
          const apiUrl = new URL(backendUrl);
          if (event.origin !== apiUrl.origin) {
            console.warn('Message from unauthorized origin:', event.origin, 'Expected:', apiUrl.origin);
            return;
          }

          if (event.data.type === 'msft_auth_success') {
            console.log('Login successful!');
            const tokenData = event.data.token_data;
            
            // Store the token FIRST
            localStorage.setItem('authToken', tokenData.tokenAccess);
            
            // Set auth authority
            if (event.data.authenticationAuthority) {
              sessionStorage.setItem('auth_authority', event.data.authenticationAuthority);
            } else {
              sessionStorage.setItem('auth_authority', 'msft');
            }
            
            // Configure axios to use the token
            api.defaults.headers.common['Authorization'] = `Bearer ${tokenData.tokenAccess}`;
            
            // NOW fetch user data with proper authentication
            setTimeout(async () => {
              try {
                const userData = await fetchCurrentUserApi('msft');
                if (userData) {
                  setUserDataCache(userData as CachedUserData);
                }
              } catch (userError) {
                console.error('Failed to fetch user data after Microsoft login:', userError);
              }
            }, 100); // Reduced timeout since we're not waiting for cookies
            
            // Clean up
            window.removeEventListener('message', messageListener);
            popup.close();
            setIsMsalLoading(false);
            
            // Resolve with the response data
            resolve(event.data);
          } else if (event.data.type === 'msft_connection_error') {
            console.error('Login failed:', event.data.error);
            // Handle error
            window.removeEventListener('message', messageListener);
            popup.close();
            setIsMsalLoading(false);
            setMsalError(event.data.error || 'Microsoft authentication failed');
            reject(new Error(event.data.error || 'Microsoft authentication failed'));
          }
        };

        // Add message listener
        window.addEventListener('message', messageListener);

        // Optional: Check if popup was closed without completing auth
        const checkPopup = setInterval(() => {
          if (popup.closed) {
            clearInterval(checkPopup);
            window.removeEventListener('message', messageListener);
            setIsMsalLoading(false);
            setMsalError('Authentication was cancelled - popup was closed before completing login');
            reject(new Error('Authentication was cancelled'));
          }
        }, 1000);
      });
    } catch (error: any) {
      console.error('MSAL authentication error:', error);
      setMsalError(error.message || 'Microsoft authentication failed');
      setIsMsalLoading(false);
      throw error;
    }
  };

  return {
    loginWithMsal,
    error: msalError,
    isLoading: isMsalLoading
  };
}

// Registration
export function useRegister() {
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  const register = async (userData: RegisterData): Promise<RegisterResponse> => {
    setIsLoading(true);
    setError(null);

    try {
      return await registerApi(userData);
    } catch (error: any) {
      let errorMessage = 'An error occurred during registration';
      
      if (error.response) {
        // Handle validation errors from FastAPI
        if (error.response.data?.detail) {
          if (Array.isArray(error.response.data.detail)) {
            // Handle FastAPI validation errors array
            errorMessage = error.response.data.detail.map((err: any) => err.msg).join(', ');
          } else {
            errorMessage = error.response.data.detail;
          }
        } else {
          errorMessage = 'Registration failed';
        }
      } else if (error.request) {
        errorMessage = 'No response received from server';
      } else {
        errorMessage = error.message;
      }
      
      setError(errorMessage);
      throw error;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    register,
    error,
    isLoading
  };
}

// Google Authentication
interface GoogleAuthResponse {
  accessToken: string;
  tokenType: string;
  user: {
    username: string;
    email: string;
    fullName: string;
    mandateId: number;
  };
}

export function useGoogleAuth() {
  const [googleError, setGoogleError] = useState<string | null>(null);
  const [isGoogleLoading, setIsGoogleLoading] = useState(false);

  const loginWithGoogle = async (): Promise<GoogleAuthResponse> => {
    setIsGoogleLoading(true);
    setGoogleError(null);

    try {
      return new Promise((resolve, reject) => {
        const backendUrl = getApiBaseUrl();
        
        // Open popup window
        const popup = window.open(
          `${backendUrl}/api/google/login?state=login`,
          'google-login',
          'width=600,height=700,left=100,top=100'
        );

        if (!popup) {
          const errorMsg = 'Popup was blocked by browser. Please allow popups for this site and try again.';
          console.error('Popup blocked:', errorMsg);
          setGoogleError(errorMsg);
          setIsGoogleLoading(false);
          reject(new Error('Popup was blocked'));
          return;
        }

        // Listen for messages from the popup
        const messageListener = (event: MessageEvent) => {
          // Filter out React DevTools messages
          if (event.data?.source?.includes('react-devtools') || 
              event.data?.source?.includes('devtools') ||
              event.data?.hello === true) {
            return; // Ignore React DevTools messages
          }
          
          // Verify the message origin for security (should match backend origin)
          const apiUrl = new URL(backendUrl);
          if (event.origin !== apiUrl.origin) {
            console.warn('Message from unauthorized origin:', event.origin, 'Expected:', apiUrl.origin);
            return;
          }

          if (event.data.type === 'google_auth_success') {
            console.log('Login successful!');
            const tokenData = event.data.token_data;
            
            // Store the token FIRST
            localStorage.setItem('authToken', tokenData.tokenAccess);
            
            // Set auth authority
            if (event.data.authenticationAuthority) {
              sessionStorage.setItem('auth_authority', event.data.authenticationAuthority);
            } else {
              sessionStorage.setItem('auth_authority', 'google');
            }
            
            // Configure axios to use the token
            api.defaults.headers.common['Authorization'] = `Bearer ${tokenData.tokenAccess}`;
            
            // NOW fetch user data with proper authentication
            setTimeout(async () => {
              try {
                const userData = await fetchCurrentUserApi('google');
                if (userData) {
                  setUserDataCache(userData as CachedUserData);
                }
              } catch (userError) {
                console.error('Failed to fetch user data after Google login:', userError);
              }
            }, 100); // Reduced timeout since we're not waiting for cookies
            
            // Clean up
            window.removeEventListener('message', messageListener);
            popup.close();
            setIsGoogleLoading(false);
            
            // Resolve with the response data
            resolve(event.data);
          } else if (event.data.type === 'google_connection_error') {
            console.error('Login failed:', event.data.error);
            // Handle error
            window.removeEventListener('message', messageListener);
            popup.close();
            setIsGoogleLoading(false);
            setGoogleError(event.data.error || 'Google authentication failed');
            reject(new Error(event.data.error || 'Google authentication failed'));
          }
        };

        // Add message listener
        window.addEventListener('message', messageListener);

        // Optional: Check if popup was closed without completing auth
        const checkPopup = setInterval(() => {
          if (popup.closed) {
            clearInterval(checkPopup);
            window.removeEventListener('message', messageListener);
            setIsGoogleLoading(false);
            setGoogleError('Authentication was cancelled - popup was closed before completing login');
            reject(new Error('Authentication was cancelled'));
          }
        }, 1000);
      });
    } catch (error: any) {
      console.error('Google authentication error:', error);
      setGoogleError(error.message || 'Google authentication failed');
      setIsGoogleLoading(false);
      throw error;
    }
  };

  return {
    loginWithGoogle,
    error: googleError,
    isLoading: isGoogleLoading
  };
}

// Microsoft Registration
export function useMsalRegister() {
  const { instance, accounts } = useMsal();
  const { request, isLoading, error } = useApiRequest<MsalRegisterData, any>();

  const registerWithMsal = async (): Promise<RegisterResponse> => {
    try {
      if (!accounts || accounts.length === 0) {
        // If not signed in with Microsoft, sign in first
        await instance.loginPopup({
          scopes: ['user.read']
        });
      }

      // Get the current account
      const currentAccount = instance.getAllAccounts()[0];
      if (!currentAccount) {
        throw new Error('No Microsoft account found');
      }

      // Prepare user data from Microsoft account
      const userData: MsalRegisterData = {
        username: currentAccount.username,
        email: currentAccount.username,
        fullName: currentAccount.name || currentAccount.username,
        language: 'de'
      };

      // Register the user through our backend
      return await registerWithMsalApi(request, userData);
    } catch (error: any) {
      throw error;
    }
  };

  return {
    registerWithMsal,
    error,
    isLoading
  };
}

// Username availability check
export function useUsernameAvailability() {
  const [isChecking, setIsChecking] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const checkAvailability = async (
    username: string,
    authenticationAuthority: string = 'local'
  ): Promise<UsernameAvailabilityResponse> => {
    setIsChecking(true);
    setError(null);

    try {
      return await checkUsernameAvailabilityApi(username, authenticationAuthority);
    } catch (error: any) {
      let errorMessage = 'Failed to check username availability';
      
      if (error.response) {
        errorMessage = error.response.data?.detail || errorMessage;
      }
      
      setError(errorMessage);
      throw error;
    } finally {
      setIsChecking(false);
    }
  };

  return {
    checkAvailability,
    isChecking,
    error
  };
}

// Password reset request (by username)
export function usePasswordResetRequest() {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState(false);

  const requestReset = async (username: string): Promise<PasswordResetRequestResponse> => {
    setIsLoading(true);
    setError(null);
    setSuccess(false);

    try {
      const response = await requestPasswordResetApi(username);
      setSuccess(true);
      return response;
    } catch (error: any) {
      // For security, we don't reveal if the username exists or not
      // So we still show success even on error
      setSuccess(true);
      return { success: true, message: 'If a user with this username exists, a reset link has been sent to their email.' };
    } finally {
      setIsLoading(false);
    }
  };

  return {
    requestReset,
    isLoading,
    error,
    success
  };
}

// Password reset (set new password with token)
export function usePasswordReset() {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState(false);

  const resetPassword = async (token: string, password: string): Promise<PasswordResetResponse> => {
    setIsLoading(true);
    setError(null);
    setSuccess(false);

    try {
      const response = await resetPasswordApi(token, password);
      setSuccess(true);
      return response;
    } catch (error: any) {
      let errorMessage = 'Passwort-Zurücksetzung fehlgeschlagen';
      
      if (error.response) {
        if (error.response.data?.detail) {
          if (Array.isArray(error.response.data.detail)) {
            errorMessage = error.response.data.detail.map((err: any) => err.msg || err).join(', ');
          } else {
            errorMessage = error.response.data.detail;
          }
        }
      } else if (error.message) {
        errorMessage = error.message;
      }
      
      setError(errorMessage);
      throw error;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    resetPassword,
    isLoading,
    error,
    success
  };
}

// Logout function
export function useLogout() {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const logout = async (): Promise<void> => {
    setIsLoading(true);
    setError(null);

    try {
      // Call logout endpoint to clear JWT tokens on server
      await logoutApi();
      

      
      // CRITICAL: Wait for browser to process Set-Cookie headers from logout response
      // This gives the browser time to clear httpOnly cookies before redirect
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // Clear user data cache from sessionStorage
      clearUserDataCache();
      
      // Clear auth authority from sessionStorage
      sessionStorage.removeItem('auth_authority');
      
      // Clear MSAL cache tokens from localStorage
      // MSAL stores tokens with keys starting with 'msal.'
      const keysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key && (
          key.startsWith('msal.') || 
          key === 'auth_token' || 
          key === 'refresh_token' ||
          key.includes('token') ||
          key.includes('auth') ||
          key.includes('msal')
        )) {
          keysToRemove.push(key);
        }
      }
      keysToRemove.forEach(key => {

        localStorage.removeItem(key);
      });
      
      // Clear ALL MSAL cache data (including account keys, token keys, version)
      const msalKeysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key && key.startsWith('msal.')) {
          msalKeysToRemove.push(key);
        }
      }
      msalKeysToRemove.forEach(key => {

        localStorage.removeItem(key);
      });
      
      // Clear sessionStorage as well (CSRF tokens, etc.)
      sessionStorage.clear();
      
      // Clear cookies as backup (in case backend doesn't clear them properly)
      // Note: This only works for cookies that are accessible to JavaScript

      
      const cookies = document.cookie.split(";");

      
      cookies.forEach(function(c) { 
        const cookieName = c.split("=")[0].trim();

        
        if (cookieName === 'auth_token' || cookieName === 'refresh_token' || cookieName.includes('token') || cookieName.includes('msal')) {

          document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
        }
      });
      

      
      // Redirect to login page
      window.location.href = '/login?logout=true';
    } catch (error: any) {
      let errorMessage = 'Logout failed';
      
      if (error.response) {
        errorMessage = error.response.data?.detail || errorMessage;
      }
      
      setError(errorMessage);
      
      // Even if logout fails on server, clear local data and redirect
      clearUserDataCache();
      sessionStorage.removeItem('auth_authority');
      
      // Clear MSAL cache tokens from localStorage
      const keysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key && (
          key.startsWith('msal.') || 
          key === 'auth_token' || 
          key === 'refresh_token' ||
          key.includes('token') ||
          key.includes('auth') ||
          key.includes('msal')
        )) {
          keysToRemove.push(key);
        }
      }
      keysToRemove.forEach(key => {

        localStorage.removeItem(key);
      });
      
      // Clear ALL MSAL cache data (including account keys, token keys, version)
      const msalKeysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key && key.startsWith('msal.')) {
          msalKeysToRemove.push(key);
        }
      }
      msalKeysToRemove.forEach(key => {

        localStorage.removeItem(key);
      });
      
      // Clear sessionStorage as well
      sessionStorage.clear();
      
      // Clear cookies as backup (in case backend doesn't clear them properly)
      document.cookie.split(";").forEach(function(c) { 
        const cookieName = c.split("=")[0].trim();
        if (cookieName === 'auth_token' || cookieName === 'refresh_token' || cookieName.includes('token') || cookieName.includes('msal')) {

          document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
        }
      });
      
      window.location.href = '/login?logout=true';
    } finally {
      setIsLoading(false);
    }
  };

  return {
    logout,
    isLoading,
    error
  };
}

// Get current user
export function useCurrentUser() {
  const [user, setUser] = useState<any>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const getCurrentUser = async (): Promise<any> => {
    setIsLoading(true);
    setError(null);

    try {
      // Determine the correct endpoint based on authentication authority
      const authAuthority = sessionStorage.getItem('auth_authority') || undefined;
      
      const userData = await fetchCurrentUserApi(authAuthority);
      setUser(userData);
      
      // Cache user data in sessionStorage (cleared on tab close - more secure than localStorage)
      setUserDataCache(userData as CachedUserData);
      
      return userData;
    } catch (error: any) {
      let errorMessage = 'Failed to get current user';
      
      if (error.response) {
        errorMessage = error.response.data?.detail || errorMessage;
      }
      
      setError(errorMessage);
      throw error;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    user,
    getCurrentUser,
    isLoading,
    error
  };
} 