import { useState, type FormEvent, type ReactNode } from "react";
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { ApiError } from "@/lib/api";
import { groupsQuery, lookupQuery } from "@/lib/queries";
import type { Group, LookupResult } from "@/lib/types";
import { defaultGroupId } from "@/lib/defaultGroup";
import { inputClass, largePrimaryButtonClass } from "@/ui/classes";

interface Submitted {
	domain: string;
	groupId: number;
}

interface Verdict {
	label: string;
	className: string;
	description: string;
}

/**
 * Header priority follows the pipeline order the lookup handler documents
 * (PLAN §6): local records answer first, then the block decision, then
 * forward zones, then plain forwarding to the upstream pool.
 */
export function verdictOf(result: LookupResult): Verdict {
	if (result.local_records) {
		return {
			label: "Local answer",
			className: "bg-blue-100 text-blue-800 dark:bg-blue-950 dark:text-blue-300",
			description: "A local record answers this name directly.",
		};
	}
	if (result.blocked) {
		return {
			label: "Blocked",
			className: "bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-300",
			description: "Queries for this name get a blocked response.",
		};
	}
	if (result.forward_zone !== null) {
		return {
			label: "Forwarded",
			className: "bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-300",
			description: `Queries go to the resolver for zone ${result.forward_zone}.`,
		};
	}
	return {
		label: "Allowed",
		className: "bg-green-100 text-green-800 dark:bg-green-950 dark:text-green-300",
		description: "Queries resolve through the upstream pool.",
	};
}

function errorMessage(error: unknown): string {
	if (error instanceof ApiError) {
		if (error.status === 503) {
			return "No filter snapshot is loaded yet — the server is starting or degraded. Try again shortly.";
		}
		if (error.status === 429) {
			return error.retryAfter !== undefined
				? `Rate limited. Try again in ${error.retryAfter}s.`
				: "Rate limited. Try again shortly.";
		}
		return error.message;
	}
	return "Could not reach the server.";
}

function DetailRow({ label, children }: { label: string; children: ReactNode }) {
	return (
		<div className="flex gap-4 py-2">
			<dt className="w-40 shrink-0 text-zinc-500">{label}</dt>
			<dd className="min-w-0 break-words">{children}</dd>
		</div>
	);
}

function VerdictCard({ result, groups }: { result: LookupResult; groups: Group[] }) {
	const verdict = verdictOf(result);
	const groupName = groups.find((group) => group.id === result.group_id)?.name ?? `#${result.group_id}`;

	return (
		<div className="mt-6 rounded border border-zinc-200 dark:border-zinc-800">
			<div className={`rounded-t px-4 py-3 ${verdict.className}`}>
				<h2 className="text-lg font-semibold">{verdict.label}</h2>
				<p className="text-sm">{verdict.description}</p>
			</div>
			<dl className="divide-y divide-zinc-100 px-4 py-2 text-sm dark:divide-zinc-900">
				<DetailRow label="Domain">
					<span className="font-mono">{result.domain}</span>
				</DetailRow>
				<DetailRow label="Group">{groupName}</DetailRow>
				<DetailRow label="Local record">{result.local_records ? "Yes" : "No"}</DetailRow>
				<DetailRow label="Forward zone">
					{result.forward_zone !== null ? <span className="font-mono">{result.forward_zone}</span> : "—"}
				</DetailRow>
				<DetailRow label="Blocked">{result.blocked ? "Yes" : "No"}</DetailRow>
				<DetailRow label="Reason">
					<span className="font-mono">{result.reason}</span>
				</DetailRow>
				<DetailRow label="Matched pattern">
					{result.matched !== "" ? <span className="font-mono">{result.matched}</span> : "—"}
				</DetailRow>
				<DetailRow label="Blocklist source">
					{result.source_url !== null ? (
						<a
							href={result.source_url}
							target="_blank"
							rel="noreferrer"
							className="text-blue-600 underline dark:text-blue-400"
						>
							{result.source_url}
						</a>
					) : (
						"—"
					)}
				</DetailRow>
				<DetailRow label="Safe search rewrite">
					{result.safe_search_rewrite !== null ? (
						<span className="font-mono">{result.safe_search_rewrite}</span>
					) : (
						"—"
					)}
				</DetailRow>
			</dl>
		</div>
	);
}

export default function LookupPage() {
	const groups = useSuspenseQuery(groupsQuery()).data;
	const preselectedGroupId = defaultGroupId(groups);

	const [domain, setDomain] = useState("");
	const [groupId, setGroupId] = useState(preselectedGroupId);
	const [submitted, setSubmitted] = useState<Submitted | null>(null);

	const lookup = useQuery({
		...lookupQuery(submitted?.domain ?? "", submitted?.groupId),
		enabled: submitted !== null,
	});

	function onSubmit(event: FormEvent<HTMLFormElement>) {
		event.preventDefault();
		const trimmed = domain.trim();
		if (trimmed === "") return;
		if (submitted !== null && submitted.domain === trimmed && submitted.groupId === groupId) {
			void lookup.refetch();
			return;
		}
		setSubmitted({ domain: trimmed, groupId });
	}

	return (
		<section>
			<h1 className="text-2xl font-semibold">Lookup</h1>
			<p className="mt-2 text-zinc-500">
				What the pipeline would do with a domain: local records, forward zones, block decision, safe search.
			</p>
			<form onSubmit={onSubmit} className="mt-6 flex max-w-2xl flex-wrap items-end gap-3">
				<div className="min-w-56 grow">
					<label htmlFor="lookup-domain" className="block text-sm font-medium">
						Domain
					</label>
					<input
						id="lookup-domain"
						required
						value={domain}
						onChange={(event) => setDomain(event.target.value)}
						placeholder="ads.example.com"
						className={inputClass}
					/>
				</div>
				<div>
					<label htmlFor="lookup-group" className="block text-sm font-medium">
						Group
					</label>
					<select
						id="lookup-group"
						value={groupId}
						onChange={(event) => setGroupId(Number(event.target.value))}
						className={inputClass}
					>
						{groups.map((group) => (
							<option key={group.id} value={group.id}>
								{group.name}
							</option>
						))}
					</select>
				</div>
				<button type="submit" className={largePrimaryButtonClass} disabled={lookup.isFetching}>
					Look up
				</button>
			</form>
			{lookup.isFetching && <p className="mt-6 text-zinc-500">Looking up…</p>}
			{!lookup.isFetching && lookup.isError && (
				<p role="alert" className="mt-6 text-sm text-red-600 dark:text-red-400">
					{errorMessage(lookup.error)}
				</p>
			)}
			{!lookup.isFetching && lookup.data !== undefined && !lookup.isError && (
				<VerdictCard result={lookup.data} groups={groups} />
			)}
		</section>
	);
}
