import type { AdminLoginInput, AdminUserView } from "@batch-cooking/shared";
import { createContext, type ReactNode, useCallback, useContext, useEffect, useState } from "react";
import { adminApiClient } from "../../api/admin-client";

/** Auth state/actions exposed via {@link useAdminAuth} — the admin-app counterpart of apps/web's `AuthContext`. */
interface AdminAuthContextValue {
  /** Currently authenticated admin, or `null` if no active session. */
  admin: AdminUserView | null;
  /** True only while the initial `GET /admin/auth/me` check is pending — lets `RequireAdmin` avoid a premature redirect. */
  isLoading: boolean;
  /** Verifies credentials and updates `admin` on success. Throws `ApiError` on failure. */
  login: (input: AdminLoginInput) => Promise<void>;
  /** Ends the session and clears `admin`. */
  logout: () => Promise<void>;
}

const AdminAuthContext = createContext<AdminAuthContextValue | null>(null);

/**
 * Provides admin authentication state to the whole app. On mount, calls
 * `GET /admin/auth/me` once to restore the session from the `admin_session`
 * httpOnly cookie (if any) — same "reload keeps you logged in" behaviour as
 * apps/web's `AuthProvider`.
 */
export function AdminAuthProvider({ children }: { children: ReactNode }) {
  const [admin, setAdmin] = useState<AdminUserView | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    adminApiClient
      .me()
      .then(setAdmin)
      // No/invalid session — the normal state for a first visit, not an error.
      .catch(() => setAdmin(null))
      .finally(() => setIsLoading(false));
  }, []);

  const login = useCallback(async (input: AdminLoginInput) => {
    try {
      setAdmin(await adminApiClient.login(input));
    } catch (err) {
      // Rethrown as-is — `LoginPage`'s submit handler catches and displays
      // it; this callback just isn't allowed a bare `await`.
      throw err;
    }
  }, []);

  const logout = useCallback(async () => {
    try {
      await adminApiClient.logout();
      setAdmin(null);
    } catch (err) {
      throw err; // see login()'s catch comment
    }
  }, []);

  return (
    <AdminAuthContext.Provider value={{ admin, isLoading, login, logout }}>
      {children}
    </AdminAuthContext.Provider>
  );
}

/** Reads the current admin auth state/actions. Must be called within an {@link AdminAuthProvider}. */
export function useAdminAuth(): AdminAuthContextValue {
  const ctx = useContext(AdminAuthContext);
  if (!ctx) {
    throw new Error("useAdminAuth must be used within an AdminAuthProvider");
  }
  return ctx;
}
