import { useEffect, useState, type FormEvent } from "react";
import { useRouter, useSearch } from "@tanstack/react-router";
import { ApiError } from "@/lib/api";
import { useAuth } from "@/auth/store";
import { inputClass, largePrimaryButtonClass } from "@/ui/classes";

export function safeRedirect(raw: string | undefined): string {
	if (raw === undefined) return "/";
	if (!/^\/(?![/\\])/.test(raw) || raw.includes("\\")) return "/";
	return raw;
}

function errorMessage(error: unknown, remaining: number | null): string {
	if (error instanceof ApiError) {
		if (error.status === 401) return "Incorrect password.";
		if (error.status === 429) {
			return remaining !== null && remaining > 0
				? `Too many attempts. Try again in ${remaining}s.`
				: "Too many attempts. Try again shortly.";
		}
		if (error.status === 503) return "The server is starting or degraded. Try again shortly.";
		return error.message;
	}
	return "Could not reach the server.";
}

export default function LoginPage() {
	const { authRequired, probe, login } = useAuth();
	const router = useRouter();
	const search = useSearch({ from: "/login" });
	const redirect = safeRedirect(search.redirect);

	const [password, setPassword] = useState("");
	const [error, setError] = useState<unknown>(null);
	const [busy, setBusy] = useState(false);

	const retryAfter = error instanceof ApiError && error.status === 429 ? (error.retryAfter ?? null) : null;
	const [remaining, setRemaining] = useState<number | null>(null);

	useEffect(() => {
		setRemaining(retryAfter);
		if (retryAfter === null) return;
		const timer = setInterval(() => setRemaining((s) => (s === null || s <= 1 ? 0 : s - 1)), 1000);
		return () => clearInterval(timer);
	}, [error, retryAfter]);

	const lockedOut = remaining !== null && remaining > 0;

	useEffect(() => {
		if (authRequired === false) {
			router.history.replace(redirect);
			return;
		}
		if (authRequired === null) {
			probe()
				.then((required) => {
					if (!required) router.history.replace(redirect);
				})
				.catch((probeError: unknown) => setError(probeError));
		}
	}, [authRequired, probe, redirect, router]);

	async function onSubmit(event: FormEvent<HTMLFormElement>) {
		event.preventDefault();
		if (busy || lockedOut) return;
		setBusy(true);
		setError(null);
		try {
			await login(password);
			router.history.push(redirect);
		} catch (loginError) {
			setError(loginError);
		} finally {
			setBusy(false);
		}
	}

	return (
		<main className="flex min-h-dvh items-center justify-center bg-zinc-50 p-4 text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
			<section className="w-full max-w-sm">
				<h1 className="text-2xl font-semibold">nxdns</h1>
				{authRequired !== true ? (
					<p className="mt-4 text-zinc-500">Checking whether a password is required…</p>
				) : (
					<form onSubmit={onSubmit} className="mt-6 space-y-4">
						<div>
							<label htmlFor="password" className="block text-sm font-medium">
								Password
							</label>
							<input
								id="password"
								type="password"
								autoComplete="current-password"
								autoFocus
								required
								value={password}
								onChange={(event) => setPassword(event.target.value)}
								className={inputClass}
							/>
						</div>
						<button
							type="submit"
							disabled={busy || lockedOut}
							className={`w-full ${largePrimaryButtonClass}`}
						>
							{busy ? "Logging in…" : "Log in"}
						</button>
					</form>
				)}
				{error !== null && (
					<p role="alert" className="mt-4 text-sm text-red-600 dark:text-red-400">
						{errorMessage(error, remaining)}
					</p>
				)}
			</section>
		</main>
	);
}
