/**
 * The five conditions `GET /api/health` reports, as facts.
 *
 * A pure projection of `Health` so the whole matrix — every state of every
 * condition, and every way out a degraded one offers — is testable without a
 * router or a fetch. `HealthStrip` only paints what this returns.
 *
 * A healthy fact is quiet: no badge, no panel, no green reassurance, so the one
 * condition that is not healthy is the thing the eye lands on.
 */

import { formatBytes, formatClock } from "@/lib/format";
import type { Health } from "@/lib/types";

export type FactTone = "ok" | "notice" | "warn" | "danger";

/**
 * Where a degraded fact sends the reader. A `filter` link stays on this page and
 * narrows it to the component that failed; a `route` link leaves for the surface
 * that can fix the condition.
 */
export type FactLink =
	| { kind: "route"; to: "/configuration/protection" | "/configuration/resolution"; label: string }
	| { kind: "filter"; component: string; label: string };

export interface HealthFact {
	key: "protection" | "upstreams" | "query_history" | "diagnostics" | "disk";
	label: string;
	tone: FactTone;
	/** The state, in the reader's words. Never colour alone. */
	value: string;
	detail?: string;
	link?: FactLink;
}

const numberFormat = new Intl.NumberFormat();

/** Kept out of the state rule: rows are lost whether or not the box is losing them now. */
function dropText(dropped: number, lastDrop: number | null, locale?: string, timeZone?: string): string | undefined {
	if (dropped <= 0) return undefined;
	const count = `${numberFormat.format(dropped)} ${dropped === 1 ? "query" : "queries"} dropped`;
	return lastDrop === null ? count : `${count}, last at ${formatClock(lastDrop, locale, timeZone)}`;
}

function protectionFact(protection: Health["protection"], locale?: string, timeZone?: string): HealthFact {
	if (protection.state === "unavailable") {
		return {
			key: "protection",
			label: "Protection",
			tone: "danger",
			value: "Unavailable",
			detail: "No filter snapshot is published, so queries are not being filtered.",
			link: { kind: "route", to: "/configuration/protection", label: "Blocklist sources" },
		};
	}
	if (protection.state === "paused") {
		return {
			key: "protection",
			label: "Protection",
			tone: "notice",
			value:
				protection.until === null
					? "Paused"
					: `Paused until ${formatClock(protection.until, locale, timeZone)}`,
		};
	}
	return { key: "protection", label: "Protection", tone: "ok", value: "Active" };
}

function queryHistoryFact(history: Health["query_history"], locale?: string, timeZone?: string): HealthFact {
	const detail = dropText(history.dropped_total, history.last_drop_s, locale, timeZone);
	if (history.state === "failed") {
		return {
			key: "query_history",
			label: "Query history",
			tone: "danger",
			value: "Writer failed",
			detail,
			link: { kind: "filter", component: "query_log", label: "Query log diagnostics" },
		};
	}
	if (history.state === "losing") {
		// The disk gate is what is holding the writes back, and it may be the only
		// thing that has reported: query_log itself need not have an episode open.
		return {
			key: "query_history",
			label: "Query history",
			tone: "danger",
			value: "Losing rows",
			detail,
			link: { kind: "filter", component: "disk", label: "Disk diagnostics" },
		};
	}
	return { key: "query_history", label: "Query history", tone: "ok", value: "Recording", detail };
}

export function healthFacts(health: Health, locale?: string, timeZone?: string): HealthFact[] {
	const { upstreams, diagnostics, disk } = health;
	return [
		protectionFact(health.protection, locale, timeZone),
		{
			key: "upstreams",
			label: "Upstreams",
			tone: upstreams.state === "unavailable" ? "danger" : "ok",
			value: upstreams.state === "unavailable" ? "None reachable" : "Available",
			detail: `${upstreams.available} of ${upstreams.total} enabled`,
			...(upstreams.state === "unavailable"
				? { link: { kind: "route", to: "/configuration/resolution", label: "Upstreams" } as FactLink }
				: {}),
		},
		queryHistoryFact(health.query_history, locale, timeZone),
		diagnostics.state === "unavailable"
			? {
					key: "diagnostics",
					label: "Diagnostics",
					tone: "danger",
					value: "Unavailable",
					// No link: the page it would filter is the thing that is broken.
					detail: "Diagnostics are not being recorded. Check free disk space and the configuration database's permissions.",
				}
			: { key: "diagnostics", label: "Diagnostics", tone: "ok", value: "Recording" },
		{
			key: "disk",
			label: "Storage",
			tone: disk.state === "critical" ? "danger" : disk.state === "low" ? "warn" : "ok",
			value: disk.state === "critical" ? "Critical" : disk.state === "low" ? "Low" : "OK",
			detail: `${formatBytes(disk.free_bytes)} free`,
			...(disk.state === "ok"
				? {}
				: { link: { kind: "filter", component: "disk", label: "Disk diagnostics" } as FactLink }),
		},
	];
}
