import { createContext, useContext, useEffect, useState } from 'react';
import { useMsal } from '@azure/msal-react';
import { EventType } from '@azure/msal-browser';
import {
  getInstructors,
  getStudents,
  getTAs,
  getUsers,
  User,
} from '../api/Users';
import { useLocation } from 'react-router-dom';

// Authentication state management
interface AuthState {
  user: User | null;
  loading: boolean;
  error: Error | null;
}

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const { instance } = useMsal();

  const location = useLocation();

  // Set default state
  const [state, setState] = useState<AuthState>({
    user: null, // No user
    loading: true, // Waiting on auth
    error: null, // No error
  });

  useEffect(() => {
    let isMounted = true;
    let loginCompleted = false;

    const checkAuth = async () => {
      try {
        if (!isMounted) {
          return;
        }

        // Only set loading to true if we haven't completed login yet
        if (!loginCompleted) {
          setState((prev) => ({ ...prev, loading: true }));
        }

        // Make sure redirect from incoming successful login is handled
        await instance.handleRedirectPromise();

        // Get active Microsoft account
        const account = instance.getActiveAccount();
        if (!account) {
          if (isMounted) {
            setState({
              user: null,
              loading: false,
              error: null,
            });
          }
          return;
        }

        // Find matching user from database
        const users = await getUsers();
        let user = users.find(
          (user) => user.email_address === account.username
        );
        if (!user) {
          if (isMounted) {
            setState({
              user: null,
              loading: false,
              error: new Error(
                'No matching user found for email address ' +
                  account.username +
                  '.'
              ),
            });
          }
          return;
        }

        if (user?.type === 'instructor') {
          // Retrieve matching instructor object
          const instructors = await getInstructors();
          const instructor = instructors.find(
            (instructor) => instructor.user_id === user?.user_id
          );

          // Add instructor properties
          user.instructor_id = instructor?.instructor_id;
          user.is_admin = instructor?.is_admin;
        } else if (user?.type === 'ta') {
          // Retrieve matching TA object
          const tas = await getTAs();
          const ta = tas.find((ta) => ta.user_id === user?.user_id);

          // Add TA properties
          user.ta_id = ta?.ta_id;
        } else if (user?.type === 'student') {
          // Retrieve matching student object
          const students = await getStudents();
          const student = students.find(
            (student) => student.user_id === user?.user_id
          );

          // Add student properties
          user.student_id = student?.student_id;
          user.team_id = student?.team_id;
          user.section_id = student?.section_id;
        }

        if (isMounted) {
          setState({
            user: user || null,
            loading: false,
            error: null,
          });
        }
        loginCompleted = true;
      } catch (err) {
        if (isMounted) {
          setState({
            user: null,
            loading: false,
            error: new Error(
              'Failed to authenticate. Please report this issue to a system administrator.'
            ),
          });
        }
      }
    };

    // Create callback function to handle response from Microsoft OAuth
    const callbackId = instance.addEventCallback((event) => {
      if (event.eventType === EventType.LOGIN_SUCCESS) {
        loginCompleted = false;
        checkAuth();
      } else if (event.eventType === EventType.LOGOUT_SUCCESS) {
        if (isMounted) {
          setState({
            user: null,
            loading: false,
            error: null,
          });
        }
      }
    });

    checkAuth();

    return () => {
      isMounted = false;
      if (callbackId) {
        instance.removeEventCallback(callbackId);
      }
    };
  }, [instance, location.key]);

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

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