import { fireEvent, render, screen } from "@testing-library/react";
import { QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";
import { AuthProvider } from "@/auth/store";
import { createQueryClient } from "@/lib/queryClient";
import { createAppRouter } from "@/routes";
import type { LookupResult } from "@/lib/types";

const BLOCKED: LookupResult = {
	domain: "ads.example",
	group_id: 1,
	local_records: false,
	forward_zone: null,
	blocked: true,
	reason: "blocklist_domain",
	matched: "ads.example",
	source_url: "https://lists.test/a",
	safe_search_rewrite: null,
};

let fetchMock: ReturnType<typeof createFetchMock>;

function json(payload: unknown, status = 200): Response {
	return new Response(JSON.stringify(payload), { status, headers: { "content-type": "application/json" } });
}

function createFetchMock() {
	return vi.fn(async (input: RequestInfo | URL) => {
		const url = String(input);
		if (url === "/api/groups") {
			return json({
				groups: [
					{ id: 1, name: "default", safe_search: false },
					{ id: 2, name: "kids", safe_search: true },
				],
			});
		}
		if (url === "/api/lookup?domain=ads.example&group_id=1") return json(BLOCKED);
		return json({ error: "not stubbed" }, 404);
	});
}

beforeEach(() => {
	fetchMock = createFetchMock();
	vi.stubGlobal("fetch", fetchMock);
});

afterEach(() => {
	vi.unstubAllGlobals();
});

function renderPage() {
	const queryClient = createQueryClient();
	const router = createAppRouter(createMemoryHistory({ initialEntries: ["/lookup"] }), queryClient);
	render(
		<AuthProvider>
			<QueryClientProvider client={queryClient}>
				<RouterProvider router={router} />
			</QueryClientProvider>
		</AuthProvider>,
	);
}

function lookupCalls(): string[] {
	return fetchMock.mock.calls.map(([input]) => String(input)).filter((url) => url.startsWith("/api/lookup"));
}

test("fetches nothing until submit, then renders the blocked verdict", async () => {
	renderPage();

	await screen.findByRole("heading", { name: "Lookup" });
	await screen.findByLabelText("Group");
	expect(lookupCalls()).toEqual([]);

	fireEvent.change(screen.getByLabelText("Domain"), { target: { value: "ads.example" } });
	expect(lookupCalls()).toEqual([]);

	fireEvent.click(screen.getByRole("button", { name: "Look up" }));

	await screen.findByRole("heading", { name: "Blocked" });
	expect(lookupCalls()).toEqual(["/api/lookup?domain=ads.example&group_id=1"]);

	expect(screen.getByText("blocklist_domain")).toBeTruthy();
	const link = screen.getByRole("link", { name: "https://lists.test/a" }) as HTMLAnchorElement;
	expect(link.href).toBe("https://lists.test/a");
	expect(screen.getByText("Queries for this name get a blocked response.")).toBeTruthy();
});

test("defaults the group select to the default group (id 1)", async () => {
	renderPage();
	// A RAC Select names its trigger with the current value and then the label, so
	// the selected group's name is the only thing the trigger shows.
	const trigger = await screen.findByRole("button", { name: /Group$/ });
	expect(trigger.textContent).toContain("default");
});
