'use client';

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { authClient, AuthClientError } from './auth-client';
import { AUTH_CONFIG } from './auth-config';
import type { AuthUser } from './auth-types';

interface AuthContextValue {
  user: AuthUser | null;
  loading: boolean;
  login: (email: string, password: string, mfaCode?: string) => Promise<AuthUser>;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
}

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

export function AuthProvider({
  initialUser = null,
  children,
}: {
  initialUser?: AuthUser | null;
  children: React.ReactNode;
}) {
  const router = useRouter();
  const [user, setUser] = useState<AuthUser | null>(initialUser);
  const [loading, setLoading] = useState<boolean>(initialUser === null);

  useEffect(() => {
    if (initialUser) return;
    let cancelled = false;
    void (async () => {
      try {
        const { user: fetched } = await authClient.me();
        if (!cancelled) setUser(fetched);
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [initialUser]);

  const login = useCallback(
    async (email: string, password: string, mfaCode?: string): Promise<AuthUser> => {
      const { user: signedIn } = await authClient.login(email, password, mfaCode);
      // Doctor portal is doctor-only — refuse non-doctor accounts.
      if (signedIn.role !== 'doctor') {
        await authClient.logout();
        throw new AuthClientError(
          'This portal is for doctors only. Patients should use sehatsahoolat.com.',
          403,
        );
      }
      setUser(signedIn);
      router.refresh();
      return signedIn;
    },
    [router],
  );

  const logout = useCallback(async (): Promise<void> => {
    try {
      await authClient.logout();
    } catch (e) {
      if (!(e instanceof AuthClientError)) throw e;
    }
    setUser(null);
    router.replace(AUTH_CONFIG.loginPath);
    router.refresh();
  }, [router]);

  const refresh = useCallback(async (): Promise<void> => {
    const { user: fetched } = await authClient.me();
    setUser(fetched);
  }, []);

  const value = useMemo<AuthContextValue>(
    () => ({ user, loading, login, logout, refresh }),
    [user, loading, login, logout, refresh],
  );

  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 inside <AuthProvider>');
  return ctx;
}
