'use client';

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react';
import { useRouter } from 'next/navigation';

import type { SessionViewModel } from '@/lib/view-models/SessionViewModel';
import { useServices } from '@/lib/services/ServiceProvider';

export type AuthContextValue = {
  session: SessionViewModel | null;
  loading: boolean;
  login: (returnTo?: string) => void;
  logout: () => Promise<void>;
  refreshSession: () => Promise<void>;
};

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

interface AuthProviderProps {
  initialSession?: SessionViewModel | null;
  children: ReactNode;
}

export function AuthProvider({ initialSession = null, children }: AuthProviderProps) {
  const router = useRouter();
  const { sessionService, authService } = useServices();
  const [session, setSession] = useState<SessionViewModel | null>(initialSession);
  const [loading, setLoading] = useState(true);

  const fetchSession = useCallback(async () => {
    setLoading(true);
    try {
      const current = await sessionService.getSession();
      setSession(current);
    } catch {
      setSession(null);
    } finally {
      setLoading(false);
    }
  }, [sessionService]);

  const refreshSession = useCallback(async () => {
    await fetchSession();
  }, [fetchSession]);

  useEffect(() => {
    fetchSession();
  }, [fetchSession]);

  const login = useCallback(
    (returnTo?: string) => {
      const search = new URLSearchParams();
      if (returnTo) {
        search.set('returnTo', returnTo);
      }

      const target = search.toString()
        ? `/auth/login?${search.toString()}`
        : '/auth/login';

      router.push(target);
    },
    [router],
  );

  const logout = useCallback(async () => {
    setLoading(true);
    try {
      await authService.logout();
      setSession(null);
      router.push('/');
      router.refresh();
    } finally {
      setLoading(false);
    }
  }, [authService, router]);

  const value = useMemo(
    () => ({
      session,
      loading,
      login,
      logout,
      refreshSession,
    }),
    [session, loading, login, logout, refreshSession],
  );

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

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