"use client";

import { useState, useEffect, useCallback } from "react";
import { useRouter, usePathname } from "next/navigation";
import { toast } from "sonner";
import { AuthContext, type AuthContextValue } from "@/presentation/hooks/use-auth";
import type { AdminProfile } from "@/domain/entities/auth";
import { useRepositories } from "@/di/repository-provider";
import { ROUTES } from "@/shared/constants";
import { useT } from "@/shared/i18n/client";
import { tokenStorage } from "@/infrastructure/auth/token-storage";
import { authEvents } from "@/infrastructure/auth/auth-events";

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const t = useT();
  const [user, setUser] = useState<AdminProfile | null>(null);
  const [loading, setLoading] = useState(true);
  const router = useRouter();
  const pathname = usePathname();

  const { authRepository } = useRepositories();

  useEffect(() => {
    const token = tokenStorage.get();
    if (token) {
      authRepository
        .getMe()
        .then(setUser)
        .catch(() => {
          tokenStorage.clear();
          setUser(null);
        })
        .finally(() => setLoading(false));
    } else {
      setLoading(false);
    }
  }, [authRepository]);

  // React to 401 responses from the api-client without forcing a full page reload.
  useEffect(() => {
    return authEvents.onUnauthorized(() => {
      setUser(null);
      router.replace(ROUTES.login);
    });
  }, [router]);

  useEffect(() => {
    // Public auth pages reachable while logged out (login + the emailed reset link).
    const isPublicPath =
      pathname.startsWith(ROUTES.login) || pathname.startsWith(ROUTES.resetPassword);
    if (!loading && !user && !isPublicPath) {
      router.replace(ROUTES.login);
    }
  }, [loading, user, pathname, router]);

  const login = useCallback(
    async (email: string, password: string) => {
      const response = await authRepository.login({ email, password });
      if (!response.status || !response.data?.token) {
        throw new Error(t.auth.invalidCredentials);
      }
      try {
        const profile = await authRepository.getMe();
        setUser(profile);
        router.replace(ROUTES.dashboard);
      } catch (err) {
        // Login succeeded but profile fetch failed: clean up so we don't
        // leave the app in a half-authenticated state.
        tokenStorage.clear();
        setUser(null);
        throw err;
      }
    },
    [authRepository, router, t],
  );

  const logout = useCallback(async () => {
    try {
      await authRepository.logout();
    } catch {
      // Server-side logout is best-effort; continue clearing local state.
    }
    setUser(null);
    toast.success(t.auth.logoutSuccess);
    router.replace(ROUTES.login);
  }, [authRepository, router, t]);

  const hasPermission = useCallback(
    (code: string) => !!user?.permissions?.includes(code),
    [user],
  );

  const value: AuthContextValue = {
    user,
    isAuthenticated: !!user,
    loading,
    login,
    logout,
    hasPermission,
  };

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