import { createContext, useContext, useEffect, useState } from "react";
import { jwtDecode } from "jwt-decode";
import { API } from "~/api/api";

export function getApiErrorMessage(error: any): string {
  if (error && Array.isArray(error.errors) && error.errors.length > 0) {
    return error.errors.map((e: any) => e.description).join('\n');
  }
  if (error && error.detail) {
    return error.detail;
  }
  return "An unexpected error occurred.";
}

export interface User {
  id: string;
  email: string;
  accessToken: string;
  refreshToken: string;
  isAdmin: boolean;
}

interface AuthContextType {
  user: User | null;
  isLoading: boolean;
  login: (accessToken: string, refreshToken: string) => void;
  logout: () => void;
  renewSession: () => Promise<User | null>;
}

const AuthContext = createContext<AuthContextType>({
  user: null,
  isLoading: true,
  login: () => {},
  logout: () => {},
  renewSession: async () => null,
});

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

  useEffect(() => {
    try {
      const stored = localStorage.getItem("user");
      if (stored) {
        const storedUser: User = JSON.parse(stored);
        try {
          const decoded: { exp: number } = jwtDecode(storedUser.accessToken);
          if (decoded.exp * 1000 < Date.now()) {
            // Token is expired, clear user data
            localStorage.removeItem("user");
            localStorage.removeItem("accessToken");
            localStorage.removeItem("refreshToken");
            setUser(null);
          } else {
            setUser(storedUser);
          }
        } catch (error) {
          // If token is invalid, clear user data
          localStorage.removeItem("user");
          localStorage.removeItem("accessToken");
          localStorage.removeItem("refreshToken");
          setUser(null);
        }
      }
    } finally {
      setIsLoading(false);
    }
  }, []);

  const login = (accessToken: string, refreshToken: string) => {
    const decoded: any = jwtDecode(accessToken);
    const roleField = decoded["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"];
    const isAdmin = Array.isArray(roleField) ? roleField.includes("Admin") : roleField === "Admin";
    const newUser: User = {
      id: decoded.sub,
      email: decoded.email,
      accessToken,
      refreshToken,
      isAdmin,
    };
    setUser(newUser);
    localStorage.setItem("user", JSON.stringify(newUser));
    localStorage.setItem("accessToken", accessToken);
    localStorage.setItem("refreshToken", refreshToken);
  };

  const logout = () => {
    setUser(null);
    localStorage.removeItem("user");
    localStorage.removeItem("accessToken");
    localStorage.removeItem("refreshToken");
  };

  const renewSession = async (): Promise<User | null> => {
    const stored = localStorage.getItem("user");
    if (!stored) {
      logout();
      return null;
    }
    const currentUser: User = JSON.parse(stored);
    
    try {
      const res = await API.renewToken(currentUser.refreshToken);
      if (!res.ok) {
        logout();
        return null;
      }
      const { accessToken, refreshToken: newRefreshToken } = await res.json();
      login(accessToken, newRefreshToken);
      // We need to get the user object that login creates
      const newStored = localStorage.getItem("user");
      return newStored ? JSON.parse(newStored) : null;
    } catch (error) {
      logout();
      return null;
    }
  };

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

export const useAuth = () => useContext(AuthContext);