import { render, screen, waitFor } from "@testing-library/react";
import { QueryClientProvider } from "@tanstack/react-query";
import { createQueryClient } from "@/lib/queryClient";
import DefinitionList from "@/ui/DefinitionList";
import ConfigLockIndicator from "./ConfigLockIndicator";
import { CONFIG_PATH, DATABASE, MANAGED_FILE, stubApi } from "./testFixtures";
import type { ConfigStatus } from "@/lib/types";

/**
 * The two shared pieces the redesign adds: the file-mode rendering of a scalar
 * and the compact lock a configuration control outside a configuration page
 * carries.
 */

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

function renderIndicator(status: ConfigStatus | "failed") {
	if (status === "failed") {
		stubApi(DATABASE, {
			responses: {
				"GET /api/config/status": new Response(JSON.stringify({ error: "unavailable" }), { status: 503 }),
			},
		});
	} else {
		stubApi(status);
	}
	render(
		<QueryClientProvider client={createQueryClient()}>
			<ConfigLockIndicator />
		</QueryClientProvider>,
	);
}

test("a definition names the value in words and the file key beside it", () => {
	render(
		<DefinitionList
			items={[
				{ label: "Port", zonKey: "dns.port", value: "53" },
				{ label: "Authentication", value: "required" },
			]}
		/>,
	);

	const port = screen.getByText("Port");
	expect(port.tagName).toBe("DT");
	expect(port.textContent).toBe("Portdns.port");
	// A derived value has no key: inventing one would send the reader looking
	// for a line that is not in the file.
	expect(screen.getByText("Authentication").textContent).toBe("Authentication");
	expect(screen.getByText("required").tagName).toBe("DD");
});

test("the lock is silent when the database owns the configuration", async () => {
	renderIndicator(DATABASE);

	await waitFor(() => expect(screen.queryByText("Locked")).toBeNull());
});

test("under file authority the lock names the file, in words a reader hears", async () => {
	renderIndicator(MANAGED_FILE);

	// The reason is visible text beside the tag, not a title and not a label: a
	// tooltip reaches neither a keyboard nor a touch screen, and screen-reader-only
	// text is the same failure pointed the other way.
	const lock = await screen.findByText("Locked");
	await waitFor(() =>
		expect(screen.getByText(`Managed by ${CONFIG_PATH}; edit the file and restart nxdns`)).toBeTruthy(),
	);
	expect(lock.getAttribute("title")).toBeNull();
	expect(lock.getAttribute("aria-label")).toBeNull();
});

test("an unanswered status still locks, and says that is why", async () => {
	renderIndicator("failed");

	await screen.findByText("Locked");
	await waitFor(() => expect(screen.getByText(/^Configuration status unavailable/)).toBeTruthy());
});
