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 { LocalRecord, LocalRecordInput } from "@/lib/types";

let records: LocalRecord[];
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, init?: RequestInit) => {
		const url = String(input);
		const method = init?.method ?? "GET";
		if (url === "/api/local-records" && method === "GET") return json({ local_records: records });
		if (url === "/api/local-records" && method === "POST") {
			const body = JSON.parse(String(init?.body)) as LocalRecordInput;
			const created: LocalRecord = { id: 99, ttl: body.ttl ?? 300, ...body };
			records = [...records, created];
			return json(created, 201);
		}
		if (url === "/api/forward-zones" && method === "GET") {
			return json({ forward_zones: [{ id: 7, zone: "lan.home", resolver: "udp://192.168.1.1:53" }] });
		}
		return json({ error: "not stubbed" }, 404);
	});
}

beforeEach(() => {
	records = [{ id: 1, name: "nas.lan.home", rtype: "A", value: "192.168.1.10", ttl: 300 }];
	fetchMock = createFetchMock();
	vi.stubGlobal("fetch", fetchMock);
});

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

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

test("renders the records table and switches to the forward zones tab", async () => {
	renderPage();

	await screen.findByRole("heading", { name: "Local DNS" });
	await screen.findByText("nas.lan.home");
	expect(screen.getByText("192.168.1.10")).toBeTruthy();

	fireEvent.click(screen.getByRole("tab", { name: "Forward zones" }));
	await screen.findByText("lan.home");
	expect(screen.getByText("udp://192.168.1.1:53")).toBeTruthy();
});

test("creates a record: POST body per LocalRecordInput, list refreshes", async () => {
	renderPage();
	await screen.findByText("nas.lan.home");

	fireEvent.click(screen.getByRole("button", { name: "Add record" }));
	fireEvent.change(screen.getByLabelText("Name"), { target: { value: "printer.lan.home" } });
	fireEvent.change(screen.getByLabelText("Type"), { target: { value: "AAAA" } });
	fireEvent.change(screen.getByLabelText("Value"), { target: { value: "fd00::11" } });
	fireEvent.click(screen.getByRole("button", { name: "Save" }));

	await screen.findByText("printer.lan.home");

	const post = fetchMock.mock.calls.find(
		([input, init]) => init?.method === "POST" && String(input) === "/api/local-records",
	);
	expect(post).toBeTruthy();
	expect(JSON.parse(String(post?.[1]?.body))).toEqual({ name: "printer.lan.home", rtype: "AAAA", value: "fd00::11" });
});
