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

const NAV_LABELS = [
	"Dashboard",
	"Query Log",
	"Live",
	"Clients",
	"Groups",
	"Blocklists",
	"Rules",
	"Local DNS",
	"Upstreams",
	"Lookup",
	"Diagnostics",
	"Settings",
];

const RESPONSES: Record<string, unknown> = {
	"/api/stats?period=24h": {
		period: "24h",
		since: 0,
		until: 86400,
		queries: 0,
		blocked: 0,
		cached: 0,
		clients: 0,
		avg_response_time_us: null,
	},
	"/api/stats/timeseries?period=24h": { period: "24h", since: 0, until: 86400, bucket_seconds: 1800, buckets: [] },
	"/api/health": {
		status: "ok",
		disk: { state: "ok", free_bytes: 0, db_bytes: 0, log_bytes: 0, sample_failures: 0 },
		upstreams: { available: 1, total: 1 },
		queries_dropped: 0,
		writer_failed: false,
		refreshes_gated: 0,
		snapshot_generation: null,
		diagnostics: { state: "recording", active_warnings: 0, active_errors: 0 },
	},
	"/api/upstream/health": { upstreams: [], available: 1, total: 1 },
	"/api/version": { version: "0.0.0-test", git_commit: "0000000", zig_version: "0.16.0", uptime_seconds: 1 },
};

beforeEach(() => {
	sessionStorage.clear();
	resetAuthProbeForTests();
	vi.stubGlobal(
		"fetch",
		vi.fn(async (input: RequestInfo | URL) => {
			const url = String(input);
			const payload = RESPONSES[url];
			if (payload === undefined) return new Response(JSON.stringify({ error: "not stubbed" }), { status: 404 });
			return new Response(JSON.stringify(payload), {
				status: 200,
				headers: { "content-type": "application/json" },
			});
		}),
	);
});

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

test("shell renders the dashboard route with all nav links", async () => {
	const queryClient = createQueryClient();
	const router = createAppRouter(createMemoryHistory({ initialEntries: ["/"] }), queryClient);
	render(
		<AuthProvider>
			<QueryClientProvider client={queryClient}>
				<RouterProvider router={router} />
			</QueryClientProvider>
		</AuthProvider>,
	);

	await screen.findByRole("heading", { name: "Dashboard" });

	const nav = screen.getByRole("navigation", { name: "Main" });
	expect(nav).toBeTruthy();
	for (const label of NAV_LABELS) {
		expect(screen.getByRole("link", { name: label })).toBeTruthy();
	}
});

test("mount probe reveals the logout button and a failed logout surfaces inline", async () => {
	vi.stubGlobal(
		"fetch",
		vi.fn(async (input: RequestInfo | URL) => {
			const url = String(input);
			if (url === "/api/auth/login")
				return new Response(JSON.stringify({ error: "password required" }), {
					status: 401,
					headers: { "content-type": "application/json" },
				});
			if (url === "/api/auth/logout")
				return new Response(JSON.stringify({ error: "rate limited" }), {
					status: 429,
					headers: { "content-type": "application/json", "retry-after": "7" },
				});
			const payload = RESPONSES[url];
			if (payload === undefined) return new Response(JSON.stringify({ error: "not stubbed" }), { status: 404 });
			return new Response(JSON.stringify(payload), {
				status: 200,
				headers: { "content-type": "application/json" },
			});
		}),
	);

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

	fireEvent.click(await screen.findByRole("button", { name: "Log out" }));

	await screen.findByText("Rate limited. Try again in 7s.");
	expect(screen.getByRole("heading", { name: "Dashboard" })).toBeTruthy();
});
