"use client";

import React, { createContext, useContext, useEffect, useState, useCallback } from "react";
import { useRouter } from "next/navigation";
import { User, UserRole, PermissionCode, LoginCredentials } from "@/types/auth";
import { apiClient, setAccessToken, setAuthFailureHandler } from "@/lib/api-client";
import { toast } from "sonner";

interface AuthContextValue {
  user: User | null;
  accessToken: string | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  login: (credentials: LoginCredentials) => Promise<boolean>;
  logout: () => Promise<void>;
  hasRole: (...roles: UserRole[]) => boolean;
  hasPermission: (permission: PermissionCode) => boolean;
}

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [accessTokenState, setAccessTokenState] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const router = useRouter();

  const handleAuthFailure = useCallback(() => {
    setUser(null);
    setAccessTokenState(null);
    setAccessToken(null);
    setIsLoading(false);
  }, []);

  // Configure global API client failure handler
  useEffect(() => {
    setAuthFailureHandler(handleAuthFailure);
  }, [handleAuthFailure]);

  // Attempt initial session restoration via refresh cookie & /auth/me
  useEffect(() => {
    let isMounted = true;

    async function restoreSession() {
      try {
        // Attempt token refresh from HttpOnly cookie
        const refreshRes = await apiClient.post<{
          success: boolean;
          data: { accessToken: string };
        }>("/auth/refresh");

        if (refreshRes.data.success && isMounted) {
          const token = refreshRes.data.data.accessToken;
          setAccessToken(token);
          setAccessTokenState(token);

          // Fetch authenticated user profile and permissions
          const meRes = await apiClient.get<{
            success: boolean;
            data: User;
          }>("/auth/me");

          if (meRes.data.success && isMounted) {
            setUser(meRes.data.data);
          }
        }
      } catch {
        // User is not authenticated; proceed as public guest
        if (isMounted) {
          handleAuthFailure();
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    }

    restoreSession();

    return () => {
      isMounted = false;
    };
  }, [handleAuthFailure]);

  const login = async (credentials: LoginCredentials): Promise<boolean> => {
    setIsLoading(true);
    try {
      const res = await apiClient.post<{
        success: boolean;
        data: { accessToken: string; user: User };
      }>("/auth/login", {
        email: credentials.identifier.trim(),
        password: credentials.password,
        rememberMe: credentials.rememberMe,
      });

      if (res.data.success) {
        const { accessToken, user: loggedInUser } = res.data.data;
        setAccessToken(accessToken);
        setAccessTokenState(accessToken);
        setUser(loggedInUser);
        toast.success(`Welcome back, ${loggedInUser.name || loggedInUser.email}`);

        // Redirect based on user role
        switch (loggedInUser.role) {
          case "SUPER_ADMIN":
          case "ACADEMIC_ADMIN":
            router.push("/admin/dashboard");
            break;
          case "DEPARTMENT_ADMIN":
            router.push("/dept-admin/dashboard");
            break;
          case "FACULTY":
            router.push("/faculty/dashboard");
            break;
          case "STUDENT":
            router.push("/student/dashboard");
            break;
          case "PARENT":
            router.push("/parent/dashboard");
            break;
          default:
            router.push("/");
        }

        return true;
      }
      return false;
    } catch (err: any) {
      const errorMessage =
        err?.response?.data?.error?.message ||
        err?.response?.data?.message ||
        "Invalid username/email or password. Please verify your credentials and try again.";
      toast.error(errorMessage);
      return false;
    } finally {
      setIsLoading(false);
    }
  };

  const logout = async (): Promise<void> => {
    setIsLoading(true);
    try {
      await apiClient.post("/auth/logout");
    } catch {
      // Ignore network errors during logout
    } finally {
      setAccessToken(null);
      setAccessTokenState(null);
      setUser(null);
      setIsLoading(false);
      toast.info("Logged out successfully");
      router.push("/login");
    }
  };

  const hasRole = (...roles: UserRole[]): boolean => {
    if (!user) return false;
    return roles.includes(user.role);
  };

  const hasPermission = (permission: PermissionCode): boolean => {
    if (!user) return false;
    if (user.role === "SUPER_ADMIN") return true;
    return Boolean(user.permissions?.includes(permission));
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        accessToken: accessTokenState,
        isAuthenticated: Boolean(user && accessTokenState),
        isLoading,
        login,
        logout,
        hasRole,
        hasPermission,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

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