/**
 * Protection, as the interface reads it: one view model derived from
 * `Health.protection`, shared by the sidebar Pause control, the related action
 * on a blocked query's detail, and the Diagnostics health strip.
 *
 * There is deliberately no second source. `GET /api/pause` answers the same
 * question, but two polled copies of one fact can disagree, and the row that
 * says "Paused" beside a button that says "Pause" is exactly the contradiction
 * this milestone set out to remove.
 */

import { useEffect } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { healthQuery, queryKeys } from "@/lib/queries";
import type { Health } from "@/lib/types";

/**
 * `unknown` is its own state, never folded into `active`: health has not
 * answered yet, or the last poll failed, and claiming filtering is in force on
 * no evidence is the one reading that could get a household bitten.
 */
export type ProtectionView =
	{ state: "unknown" } | { state: "active" } | { state: "paused"; until: number | null } | { state: "unavailable" };

export function protectionViewOf(protection: Health["protection"] | undefined): ProtectionView {
	if (protection === undefined) return { state: "unknown" };
	if (protection.state === "unavailable") return { state: "unavailable" };
	if (protection.state === "paused") return { state: "paused", until: protection.until };
	return { state: "active" };
}

function nowSeconds(): number {
	return Math.floor(Date.now() / 1000);
}

/**
 * Protection now, with the expiry of a timed pause scheduled.
 *
 * Health polls every ten seconds, so without the timer a pause that ended
 * three seconds ago still reads "Paused until 14:05" — a stale claim about the
 * one fact the indicator exists to state. The timeout fires a second past
 * `until` so the server's own expiry rule, not the browser's clock, decides.
 */
export function useProtection(): ProtectionView {
	const queryClient = useQueryClient();
	const { data, isError } = useQuery(healthQuery());
	// A failed poll leaves the last body in the cache, and that body is a
	// reading, not the current state: the query this view answers is "is
	// filtering in force right now", and a stale yes is the same lie as an
	// invented one. The Diagnostics health strip may still render the cached
	// conditions, because it marks them stale in the same breath; this view has
	// no such caption, so a failure is `unknown`.
	const view = isError ? ({ state: "unknown" } as const) : protectionViewOf(data?.protection);
	const until = view.state === "paused" ? view.until : null;

	useEffect(() => {
		if (until === null) return;
		const delay = Math.max(0, until - nowSeconds() + 1) * 1000;
		const timer = setTimeout(() => void queryClient.invalidateQueries({ queryKey: queryKeys.health }), delay);
		return () => clearTimeout(timer);
	}, [until, queryClient]);

	return view;
}
