import { createContext, useState, useEffect, useRef, ReactNode, useCallback } from 'react';
import config from '@/config';

export interface Permission {
  id: number;
  name: string;
  code: string;
  description?: string;
  category: string;
}

export interface User {
  id: number;
  username: string;
  email?: string;
  is_admin: boolean;
  rocket_chat_user_id?: string;
  permissions: string[];
}

interface AuthContextType {
  user: User | null;
  token: string | null;
  isLoading: boolean;
  error: string | null;
  login: (username: string, password: string) => Promise<void>;
  logout: () => void;
  fetchCurrentUser: () => Promise<void>;
}

const defaultContext: AuthContextType = {
  user: null,
  token: null,
  isLoading: false,
  error: null,
  login: async () => {},
  logout: () => {},
  fetchCurrentUser: async () => {},
};

export const AuthContext = createContext<AuthContextType>(defaultContext);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<string | null>(() => localStorage.getItem('token'));
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);

  const fetchCurrentUser = useCallback(async () => {
    if (!token) return;

    try {
      setIsLoading(true);
      setError(null);

      const response = await fetch(`${config.authUrl}/me`, {
        headers: {
          'Authorization': `Bearer ${token}`
        }
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        console.error('Auth check failed:', response.status, errorData);
        // Any failed /me response means the session is invalid — logout
        logout();
        return;
      }

      const userData = await response.json();
      console.log("Fetched current user data:", userData);
      console.log("User permissions:", userData.permissions);
      console.log("User rocket_chat_user_id:", userData.rocket_chat_user_id);

      setUser(userData);
      // Ensure we have the sessionStorage isLoggedIn flag set
      sessionStorage.setItem('isLoggedIn', 'true');
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
      setError(errorMessage);
      console.error('Auth error:', errorMessage);
      // Network errors (server down, etc.) — don't logout, just show error
    } finally {
      setIsLoading(false);
    }
  }, [token]);

  // Load token and fetch user data on init
  useEffect(() => {
    if (token) {
      fetchCurrentUser();
    } else {
      // Clear sessionStorage if no token exists
      sessionStorage.removeItem('isLoggedIn');
    }
  }, [token, fetchCurrentUser]);

  // Re-validate auth when user returns to the tab after being away
  const lastCheckRef = useRef(Date.now());
  useEffect(() => {
    const onVisibilityChange = () => {
      if (document.visibilityState === 'visible' && token) {
        const elapsed = Date.now() - lastCheckRef.current;
        // Only re-check if at least 5 minutes have passed
        if (elapsed > 5 * 60 * 1000) {
          lastCheckRef.current = Date.now();
          fetchCurrentUser();
        }
      }
    };
    document.addEventListener('visibilitychange', onVisibilityChange);
    return () => document.removeEventListener('visibilitychange', onVisibilityChange);
  }, [token, fetchCurrentUser]);

  // Listen for auth:logout events from anywhere in the app (e.g. failed API calls)
  useEffect(() => {
    const onForceLogout = () => logout();
    window.addEventListener('auth:logout', onForceLogout);
    return () => window.removeEventListener('auth:logout', onForceLogout);
  }, []);

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

      const response = await fetch(`${config.authUrl}/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username, password })
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new Error(errorData.error || 'Login failed');
      }

      const data = await response.json();
      console.log("Login successful, received data:", data);
      console.log("User permissions:", data.user?.permissions);
      
      localStorage.setItem('token', data.token);
      sessionStorage.setItem('isLoggedIn', 'true');
      setToken(data.token);
      setUser(data.user);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Login failed';
      setError(errorMessage);
      console.error('Login error:', errorMessage);
      throw err;
    } finally {
      setIsLoading(false);
    }
  };

  const logout = () => {
    localStorage.removeItem('token');
    sessionStorage.removeItem('isLoggedIn');
    setToken(null);
    setUser(null);
  };

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