"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import { getDefaultRouteForRole } from "@/lib/auth/permissions";
import { getRoleLabel, isAdminWebRole, type AppRole } from "@/lib/auth/roles";
import {
  clearAuthUser,
  getAuthUser,
  setAuthUser,
  type AuthUser,
} from "@/lib/auth/session";
import { getAuthToken } from "@/lib/auth/token";

type AuthContextValue = {
  user: AuthUser | null;
  role: AppRole | null;
  roleLabel: string;
  isReady: boolean;
  setUser: (user: AuthUser) => void;
  clearUser: () => void;
  defaultRoute: string;
};

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUserState] = useState<AuthUser | null>(null);
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const storedUser = getAuthUser();

    if (storedUser) {
      setAuthUser(storedUser);
      setUserState(storedUser);
    }

    setIsReady(true);
  }, []);

  useEffect(() => {
    if (user || !getAuthToken()) return;

    const storedUser = getAuthUser();

    if (storedUser) {
      setAuthUser(storedUser);
      setUserState(storedUser);
    }
  }, [user]);

  const setUser = useCallback((nextUser: AuthUser) => {
    setAuthUser(nextUser);
    setUserState(nextUser);
  }, []);

  const clearUser = useCallback(() => {
    clearAuthUser();
    setUserState(null);
  }, []);

  const value = useMemo<AuthContextValue>(() => {
    const role = user?.role ?? null;

    return {
      user,
      role,
      roleLabel: getRoleLabel(role),
      isReady,
      setUser,
      clearUser,
      defaultRoute: getDefaultRouteForRole(role),
    };
  }, [clearUser, isReady, setUser, user]);

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

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

  if (!context) {
    throw new Error("useAuth harus digunakan di dalam AuthProvider");
  }

  return context;
}
