import {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useState,
  type PropsWithChildren,
} from 'react';
import { onAuthStateChanged, type User as FirebaseAuthUser } from 'firebase/auth';
import { onSnapshot } from 'firebase/firestore';

import { auth } from '@/lib/firebase';
import { userDoc } from '@/lib/firestore';
import type { UserDocument } from '@/types/firestore';

type AuthContextValue = {
  authUser: FirebaseAuthUser | null;
  user: UserDocument | null;
  initializing: boolean;
};

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

export function AuthProvider({ children }: PropsWithChildren) {
  const [authUser, setAuthUser] = useState<FirebaseAuthUser | null>(null);
  const [user, setUser] = useState<UserDocument | null>(null);
  const [initializing, setInitializing] = useState(true);

  useEffect(() => {
    let unsubscribeUserSnapshot: (() => void) | undefined;

    const unsubscribe = onAuthStateChanged(auth, (nextUser) => {
      setAuthUser(nextUser);

      if (unsubscribeUserSnapshot) {
        unsubscribeUserSnapshot();
        unsubscribeUserSnapshot = undefined;
      }

      if (!nextUser) {
        setUser(null);
        setInitializing(false);
        return;
      }

      unsubscribeUserSnapshot = onSnapshot(
        userDoc(nextUser.uid),
        (snapshot) => {
          setUser(snapshot.data() ?? null);
          setInitializing(false);
        },
        () => {
          setUser(null);
          setInitializing(false);
        }
      );
    });

    return () => {
      unsubscribe();
      unsubscribeUserSnapshot?.();
    };
  }, []);

  const value = useMemo(
    () => ({
      authUser,
      user,
      initializing,
    }),
    [authUser, initializing, user]
  );

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

export function useAuth() {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }

  return context;
}
