import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
import { AuthContextType, AuthState, LoginCredentials, RegisterData, UserRole } from '@/types';
import { authService } from '@/utils/auth';

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

interface AuthProviderProps {
  children: ReactNode;
}

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

  const login = async (credentials: LoginCredentials): Promise<void> => {
    try {
      setAuthState(prev => ({ ...prev, isLoading: true }));
      
      const result = await authService.login(credentials);
      
      setAuthState({
        isAuthenticated: true,
        user: result.user,
        token: result.accessToken,
        isLoading: false,
      });
    } catch (error) {
      setAuthState(prev => ({ ...prev, isLoading: false }));
      throw error;
    }
  };

  const register = async (data: RegisterData): Promise<void> => {
    try {
      setAuthState(prev => ({ ...prev, isLoading: true }));
      
      const result = await authService.register(data);
      
      setAuthState({
        isAuthenticated: true,
        user: result.user,
        token: result.accessToken,
        isLoading: false,
      });
    } catch (error) {
      setAuthState(prev => ({ ...prev, isLoading: false }));
      throw error;
    }
  };

  const logout = useCallback((): void => {
    authService.logout();
    setAuthState({
      isAuthenticated: false,
      user: null,
      token: null,
      isLoading: false,
    });
  }, []);

  const refreshToken = useCallback(async (): Promise<void> => {
    try {
      const newToken = await authService.refreshToken();
      const user = authService.getCurrentUserFromToken();
      
      setAuthState(prev => ({
        ...prev,
        token: newToken,
        user,
        isAuthenticated: true,
      }));
    } catch (error) {
      logout();
      throw error;
    }
  }, [logout]);

  const hasRole = (role: UserRole): boolean => {
    return authService.hasRole(role);
  };

  const hasPermission = (permission: string): boolean => {
    return authService.hasPermission(permission);
  };

  const loadUserFromToken = useCallback(async (): Promise<void> => {
    try {
      if (authService.isAuthenticated()) {
        const user = authService.getCurrentUserFromToken();
        const token = authService.getAccessToken();
        
        if (user && token) {
          setAuthState({
            isAuthenticated: true,
            user,
            token,
            isLoading: false,
          });
          
          // 토큰 갱신 체크
          if (authService.shouldRefreshToken()) {
            await refreshToken();
          }
        } else {
          // 토큰이 유효하지 않으면 최신 사용자 정보 가져오기
          const currentUser = await authService.getCurrentUser();
          setAuthState({
            isAuthenticated: true,
            user: currentUser,
            token,
            isLoading: false,
          });
        }
      } else {
        setAuthState({
          isAuthenticated: false,
          user: null,
          token: null,
          isLoading: false,
        });
      }
    } catch (error) {
      console.error('Failed to load user from token:', error);
      logout();
    }
  }, [refreshToken, logout]);

  useEffect(() => {
    loadUserFromToken();
  }, [loadUserFromToken]);

  // 토큰 자동 갱신 체크
  useEffect(() => {
    if(!authState.isAuthenticated){
      return () => {};
    }

    const checkTokenExpiration = setInterval(() => {
      if (authService.shouldRefreshToken()) {
        refreshToken().catch(() => {
          logout();
        });
      }
    }, 60000); // 1분마다 체크

    return () => clearInterval(checkTokenExpiration);
  }, [authState.isAuthenticated, refreshToken, logout]);

  const contextValue: AuthContextType = {
    ...authState,
    login,
    register,
    logout,
    refreshToken,
    hasRole,
    hasPermission,
  };

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

// eslint-disable-next-line react-refresh/only-export-components
export const useAuth = (): AuthContextType => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};