// ---------------------------------------------------------------------------
// Folder: components/auth
// File: AuthProvider.jsx
// Relative Path: components/auth/AuthProvider.jsx
// ---------------------------------------------------------------------------

"use client";

import React from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { Loader2 } from "lucide-react";

import { getMe } from "@/lib/frontend/apiClient";
import { buildLoginUrl, LOGIN_REASONS } from "@/lib/frontend/authRedirect";

import { AuthProvider as AuthContextProvider } from "@/components/auth/authContext";
import { Button } from "@/components/ui/button";
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";

/**
 * AuthProvider (RHL-020)
 *
 * Best-practice approach (per Next.js docs):
 * - We use Next.js navigation hooks (usePathname/useSearchParams/useRouter)
 *   to build a correct `next` parameter and redirect smoothly.
 * - IMPORTANT: When `useSearchParams()` is used, this component MUST be rendered
 *   under a <Suspense> boundary for production builds where the route can be
 *   statically prerendered. The Suspense boundary is added in the protected layout.
 *
 * Responsibilities:
 * - Run session check via GET /api/auth/me.
 * - If authenticated: provide { status: "authenticated", user } and render children.
 * - If unauthenticated: redirect to /login?reason=expired&next=<current-url>.
 * - Show a loading UI while checking.
 * - Show an error UI with a retry button if the check fails.
 *
 * @param {{ children: React.ReactNode }} props
 */
export default function AuthProvider({ children }) {
	const router = useRouter();
	const pathname = usePathname();
	const searchParams = useSearchParams();

	// Create a stable string representation of search params for effect deps.
	const search = searchParams ? searchParams.toString() : "";

	// Prevent double redirects in quick re-renders.
	const didRedirectRef = React.useRef(false);

	// Auth state exposed via context.
	const [auth, setAuth] = React.useState({
		status: "loading",
		user: null,
		error: null,
	});

	// Retry tick for the error UI.
	const [retryTick, setRetryTick] = React.useState(0);

	React.useEffect(() => {
		let cancelled = false;

		async function runSessionCheck() {
			setAuth({ status: "loading", user: null, error: null });

			try {
				const res = await getMe();

				if (cancelled) return;

				// /api/auth/me:
				// - 200 { user: null } when unauthenticated
				// - 200 { user: {...} } when authenticated
				if (res?.user) {
					setAuth({ status: "authenticated", user: res.user, error: null });
					return;
				}

				setAuth({ status: "unauthenticated", user: null, error: null });

				if (!didRedirectRef.current) {
					didRedirectRef.current = true;

					// Build `next` from current URL (path + query).
					const next = search ? `${pathname}?${search}` : pathname;

					const loginUrl = buildLoginUrl({
						reason: LOGIN_REASONS.EXPIRED,
						next,
					});

					// Replace history so back button won't bounce into a protected page.
					router.replace(loginUrl);
				}
			} catch (err) {
				if (cancelled) return;

				// Do not redirect blindly on failures (backend might be down).
				setAuth({
					status: "error",
					user: null,
					error: "Unable to verify your session. Please try again.",
				});
			}
		}

		runSessionCheck();

		return () => {
			cancelled = true;
		};
	}, [router, pathname, search, retryTick]);

	// -----------------------------------------------------------------------
	// Render gating
	// -----------------------------------------------------------------------

	if (auth.status === "loading") {
		return (
			<AuthContextProvider value={auth}>
				<div className="min-h-screen w-full px-4">
					<div className="mx-auto flex min-h-screen max-w-md items-center justify-center">
						<div className="flex items-center gap-3 text-sm text-muted-foreground">
							<Loader2 className="h-4 w-4 animate-spin" />
							<span>Checking session...</span>
						</div>
					</div>
				</div>
			</AuthContextProvider>
		);
	}

	if (auth.status === "error") {
		return (
			<AuthContextProvider value={auth}>
				<div className="min-h-screen w-full px-4">
					<div className="mx-auto flex min-h-screen max-w-md items-center justify-center">
						<div className="w-full space-y-4">
							<Alert variant="destructive">
								<AlertTitle>Session check failed</AlertTitle>
								<AlertDescription>{auth.error}</AlertDescription>
							</Alert>

							<Button
								type="button"
								className="w-full"
								onClick={() => setRetryTick((n) => n + 1)}
							>
								Retry
							</Button>
						</div>
					</div>
				</div>
			</AuthContextProvider>
		);
	}

	if (auth.status === "unauthenticated") {
		// Redirect happens in useEffect. Show a tiny placeholder meanwhile.
		return (
			<AuthContextProvider value={auth}>
				<div className="min-h-screen w-full px-4">
					<div className="mx-auto flex min-h-screen max-w-md items-center justify-center">
						<div className="flex items-center gap-3 text-sm text-muted-foreground">
							<Loader2 className="h-4 w-4 animate-spin" />
							<span>Redirecting to login...</span>
						</div>
					</div>
				</div>
			</AuthContextProvider>
		);
	}

	// Authenticated
	return <AuthContextProvider value={auth}>{children}</AuthContextProvider>;
}
