import React, { createContext, useCallback, useContext, useState, useEffect, ReactNode } from 'react';
import { AuthContextType, AuthState } from '../types/auth.types';
import { authService } from '../services/auth';
import { getToken, setToken, removeToken, getUser, setUser, removeUser, setRefreshToken, removeRefreshToken } from '../utils/storage';
import { useNotification } from './NotificationContext';
import { setAuthInitialized } from '../services/api';

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

interface AuthProviderProps {
  children: ReactNode;
}

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
  const notification = useNotification();
  const [state, setState] = useState<AuthState>({
    user: null,
    token: null,
    isAuthenticated: false,
    isLoading: true,
  });

  // Check for existing token on mount
  useEffect(() => {
    const initializeAuth = async () => {
      const token = getToken();
      const user = getUser();

      if (token && user) {
        setState({
          user,
          token,
          isAuthenticated: true,
          isLoading: false,
        });

        // Optionally verify token is still valid
        try {
          await authService.getCurrentUser();
        } catch (error: any) {
          console.error('Token validation failed:', error);
          // Only clear auth for explicit 401 Unauthorized
          // Network errors or server errors (5xx) should not log out the user
          if (error?.status === 401) {
            removeToken();
            removeUser();
            setState({ user: null, token: null, isAuthenticated: false, isLoading: false });
          } else {
            // Keep existing auth state on non-auth errors (network issues, server down)
            // The user may still be authenticated, just the server is temporarily unavailable
            setState({ user, token, isAuthenticated: true, isLoading: false });
          }
        } finally {
          setAuthInitialized(true);
        }
      } else {
        setState({
          user: null,
          token: null,
          isAuthenticated: false,
          isLoading: false,
        });
        setAuthInitialized(true);
      }
    };

    initializeAuth();
  }, []);

  const login = useCallback(async (code: string): Promise<void> => {
    try {
      setState((prev) => ({ ...prev, isLoading: true }));

      const { token, refreshToken, user } = await authService.handleCallback(code);

      // Save to localStorage
      setToken(token);
      setRefreshToken(refreshToken);
      setUser(user);

      // Update state
      setState({
        user,
        token,
        isAuthenticated: true,
        isLoading: false,
      });

      // Show success notification
      notification.showSuccess('Anmeldung erfolgreich');
    } catch (error) {
      console.error('Login failed:', error);
      setState({
        user: null,
        token: null,
        isAuthenticated: false,
        isLoading: false,
      });

      // Show error notification
      const is429 = error && typeof error === 'object' && 'status' in error && (error as any).status === 429;
      notification.showError(
        is429
          ? 'Zu viele Anmeldeversuche. Bitte warten Sie einige Minuten und versuchen Sie es erneut.'
          : 'Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut.'
      );
      throw error;
    }
  }, [notification]);

  const logout = useCallback((): void => {
    // Call backend logout (fire and forget)
    authService.logout().catch((error) => {
      console.error('Backend logout failed:', error);
    });

    // Clear local state
    removeToken();
    removeRefreshToken();
    removeUser();
    setState({
      user: null,
      token: null,
      isAuthenticated: false,
      isLoading: false,
    });

    // Show logout notification
    notification.showSuccess('Abmeldung erfolgreich');

    // Redirect to login after a short delay to show notification
    setTimeout(() => {
      window.location.href = '/login';
    }, 1000);
  }, [notification]);

  const refreshAuth = useCallback(async (): Promise<void> => {
    try {
      const user = await authService.getCurrentUser();
      setUser(user);
      setState((prev) => ({ ...prev, user }));
    } catch (error: any) {
      console.error('Failed to refresh user data:', error);
      // Only logout on explicit 401 — network errors / 5xx should not destroy the session
      if (error?.response?.status === 401) {
        logout();
      }
    }
  }, [logout]);

  const value: AuthContextType = {
    ...state,
    login,
    logout,
    refreshAuth,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

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