import { describe, expect, test } from "bun:test";
import { mkdtempSync, readFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { FetchLike } from "../adapter";
import { CollectorState } from "../state";
import { Journal } from "../journal";
import { CollectorFatalError } from "../errors";
import { ControllerStatusSchema, createOffloadAdapter } from "./offload";
import { RegistryUnavailableError, type BuildboxRegistry } from "../buildbox-registry";

const FIXTURE_DIR = join(import.meta.dir, "../../test/fixtures/offload");

/** Isolates the state's journal from this machine's real, possibly enormous,
 * `~/.local/state/overdeck/items.jsonl` — `buildState()` reads that ambient file. */
function buildTestState(now: () => number): CollectorState {
  const dir = mkdtempSync(join(tmpdir(), "overdeck-offload-test-"));
  return new CollectorState(new Journal(join(dir, "items.jsonl")), now);
}
const CONTROLLER_URL = "http://127.0.0.1:8787";
const METRICS_URL = "http://127.0.0.1:8787";
const TOKEN = "test-offload-token";
const NOW_MS = 1_752_800_000_000; // 2026-07-18T00:00:00.000Z

function loadJson<T>(name: string): T {
  return JSON.parse(readFileSync(join(FIXTURE_DIR, name), "utf8")) as T;
}

function createMockFetch(opts: {
  statusFile?: string;
  status?: unknown;
  metricsFile?: string;
  metrics?: Record<string, unknown>;
  metricsOverrides?: Record<string, unknown>;
  statusError?: Error;
  metricsError?: Error;
}): FetchLike {
  const status = opts.status ?? (opts.statusFile ? loadJson<unknown>(opts.statusFile) : null);
  const metrics = opts.metrics
    ? opts.metrics
    : opts.metricsFile
      ? ({
          ...loadJson<Record<string, unknown>>(opts.metricsFile),
          ...opts.metricsOverrides,
        } as Record<string, unknown>)
      : null;

  return async (input: string | URL | Request, init?: RequestInit) => {
    const url = new URL(String(input));
    const path = url.pathname;
    const query = url.searchParams.get("query") ?? "";

    if (path === "/status") {
      if (opts.statusError) throw opts.statusError;
      if (!status) {
        return new Response("not found", { status: 404 });
      }
      const headers = new Headers(init?.headers);
      expect(headers.get("authorization")).toBe(`Bearer ${TOKEN}`);
      return new Response(JSON.stringify(status), { status: 200 });
    }

    if (path === "/api/v1/query") {
      if (opts.metricsError) throw opts.metricsError;
      const body = metrics?.[query];
      if (body === undefined) {
        throw new Error(`unmocked offload metrics query: ${query}`);
      }
      return new Response(JSON.stringify(body), { status: 200 });
    }

    return new Response("not found", { status: 404 });
  };
}

// Pinned so the panel does not depend on whichever registry this machine happens to carry.
const REGISTRY_FIXTURE = {
  schema_version: 1,
  source: "test-fixture",
  orders: { build: ["debian1"] },
  hosts: [
    {
      name: "debian1",
      ssh_alias: "debian1",
      state: "reachable",
      machine_id: null,
      roles: ["builder"],
      access: {},
      rustdesk: "28888072",
      notes: "fixture",
    },
    {
      name: "debian9",
      ssh_alias: "debian9",
      state: "unreachable",
      machine_id: null,
      roles: ["builder"],
      access: {},
      rustdesk: null,
      notes: "declared but never enrolled",
    },
  ],
} as unknown as BuildboxRegistry;

// Parity comes from a file on the machine running the tests, so it is injected here or the
// suite reads whatever verdict this workstation's convergence timer last wrote.
const NO_PARITY_FILE = () => {
  throw new Error("ENOENT: no such file or directory");
};

function makeAdapter(
  fetchImpl: FetchLike,
  loadRegistry: () => Promise<BuildboxRegistry> = async () => REGISTRY_FIXTURE,
  readFileImpl: (path: string) => string = NO_PARITY_FILE,
) {
  return createOffloadAdapter({
    fetchImpl,
    controllerUrl: CONTROLLER_URL,
    metricsUrl: METRICS_URL,
    token: TOKEN,
    interval: 30_000,
    now: () => NOW_MS,
    loadRegistry,
    readFileImpl,
  });
}

describe("createOffloadAdapter", () => {
  test("requires an injected fetch implementation", () => {
    expect(() =>
      createOffloadAdapter({
        token: TOKEN,
        controllerUrl: CONTROLLER_URL,
      } as Parameters<typeof createOffloadAdapter>[0]),
    ).toThrow("fetchImpl is required");
  });

  test("empty token throws TOKEN_EMPTY before any controller request", () => {
    let fetchCalls = 0;
    const fetchImpl: FetchLike = async () => {
      fetchCalls += 1;
      return new Response("{}", { status: 200 });
    };
    expect(() =>
      createOffloadAdapter({
        fetchImpl,
        controllerUrl: CONTROLLER_URL,
        metricsUrl: METRICS_URL,
        token: "",
      }),
    ).toThrow(CollectorFatalError);
    expect(fetchCalls).toBe(0);
  });

  test("emits the four offload panels on a healthy poll", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metricsFile: "metrics-normal-temp.json",
      }),
    );
    const result = await adapter.poll();

    expect(result.panels.map((p) => p.id).sort()).toEqual([
      "cluster-queue",
      "fleet",
      "offload-control",
      "remote-jobs",
    ]);
    for (const panel of result.panels) {
      expect((panel.data as { stale?: boolean }).stale).toBe(false);
    }
  });

  test("a field the controller added that the deck does not know keeps the fleet visible", async () => {
    // Rejecting the whole status for one unknown key emptied the Cluster page: the
    // controller grew landConduct and deployWatcher, and every poll threw until the
    // schema caught up. Additive fields must degrade to ignored, never to blank.
    const status = loadJson<Record<string, unknown>>("status-normal-temp.json");
    status.landConduct = {
      "/home/user/Projects/overdeck": {
        lastPassAt: "2026-08-15T09:03:12.387Z",
        lastOk: true,
        lastDetail: "",
        consecutiveFailures: 0,
      },
    };
    status.deployWatcher = {
      targetSha: "7e31ace591a3a63bdfe60ed84f6d89d0a6657db2",
      attempts: 2,
      lastStatus: "deployed-docs-only",
      lastDetail: "",
      lastAt: "2026-08-15T08:56:31.478Z",
      lastOk: true,
      failureClass: "transient",
      nextRetryAt: "2026-08-15T09:01:31.478Z",
    };
    status.somethingLandedTomorrow = { anything: true };

    const adapter = makeAdapter(createMockFetch({ status, metricsFile: "metrics-normal-temp.json" }));
    const result = await adapter.poll();

    const fleet = result.panels.find((panel) => panel.id === "fleet");
    expect(fleet).toBeDefined();
    expect((fleet?.data as { stale?: boolean; hosts?: unknown[] }).stale).toBe(false);
    expect(((fleet?.data as { hosts?: unknown[] }).hosts ?? []).length).toBeGreaterThan(0);
  });

  test("rejects unknown deploy watcher fields while accepting the controller contract", async () => {
    const status = loadJson<Record<string, unknown>>("status-normal-temp.json");
    status.deployWatcher = {
      targetSha: "7e31ace591a3a63bdfe60ed84f6d89d0a6657db2",
      attempts: 2,
      lastStatus: "failed",
      lastDetail: "retry scheduled",
      lastAt: "2026-08-15T08:56:31.478Z",
      lastOk: false,
      failureClass: "transient",
      nextRetryAt: null,
      unexpectedPolicy: "ignored-would-be-unsafe",
    };

    const adapter = makeAdapter(createMockFetch({ status, metricsFile: "metrics-normal-temp.json" }));

    await expect(adapter.poll()).rejects.toThrow("Unrecognized key(s) in object: 'unexpectedPolicy'");
  });

  test("plumbs structured controller KPI samples and derives longest observed pull-back", async () => {
    const status = loadJson<Record<string, unknown>>("status-normal-temp.json");
    status.kpis = {
      remote24h: 12,
      remoteSuccessPct: 75,
      exit127: { count: 2, hosts: ["debian1"] },
    };
    status.jobs = [{
      id: "pulled", repo: "owner/repo", snapshot: "abc", stage: "completed",
      host: "debian1", rc: 0, pullDurationSeconds: 6.4,
    }];
    const fetchImpl = createMockFetch({
      metricsFile: "metrics-normal-temp.json",
      metrics: undefined,
    });
    const adapter = makeAdapter(async (input, init) => {
      if (new URL(String(input)).pathname === "/status") {
        return new Response(JSON.stringify(status), { status: 200 });
      }
      return fetchImpl(input, init);
    });
    const result = await adapter.poll();
    const panel = result.panels.find((candidate) => candidate.id === "cluster-queue");
    expect((panel?.data as { kpis: unknown }).kpis).toEqual({
      remote24h: 12,
      remoteSuccessPct: 75,
      exit127: { count: 2, hosts: ["debian1"] },
      longestPullMs: 6400,
    });
  });

  test("a lifetime exit counter with no open circuit raises no capability item", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metricsFile: "metrics-normal-temp.json",
        metricsOverrides: {
          'build_offload_exit_total{host!="",command!="",code=~"126|127"}': {
            status: "success",
            data: {
              resultType: "vector",
              result: [{
                metric: { host: "debian1", command: "bash", code: "127" },
                value: [1_752_800_000, "9"],
              }],
            },
          },
        },
      }),
    );
    const result = await adapter.poll();
    expect(
      result.items.filter((item) => item.id.startsWith("offload:capability-missing")),
    ).toEqual([]);
  });

  test("2026-07-18 incident: exactly remote-idle-queue-stalled + capability-missing with job links", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-incident-2026-07-18.json",
        metricsFile: "metrics-incident-2026-07-18.json",
      }),
    );
    const result = await adapter.poll();

    expect(result.items).toHaveLength(2);
    expect(result.items.map((item) => item.id).sort()).toEqual([
      "offload:capability-missing:debian1:playwright browsers",
      "offload:remote-idle-queue-stalled",
    ]);

    const stalled = result.items.find((item) => item.id === "offload:remote-idle-queue-stalled");
    expect(stalled?.kind).toBe("build");
    expect(stalled?.severity).toBe("act");
    expect(stalled?.actions.some((action) => action.verb === "admission-reconcile")).toBe(true);
    expect(stalled?.detail).toContain("6 builds waiting");

    const capability = result.items.find(
      (item) => item.id === "offload:capability-missing:debian1:playwright browsers",
    );
    expect(capability?.kind).toBe("build");
    expect(capability?.severity).toBe("act");
    expect(capability?.detail).toContain("rb-4e77b0");
    expect(capability?.detail).toContain("rb-3d66a1");
    expect(capability?.actions).toEqual([
      {
        verb: "host-quarantine",
        args: {
          host: "debian1",
          command: "playwright browsers",
          expectedRevision: "4192",
        },
        label: "Quarantine host",
        recommended: true,
      },
    ]);
  });

  test("controller-down: one controller-down item and all panels stale", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusError: new Error("connect ECONNREFUSED 127.0.0.1:8787"),
      }),
    );
    const result = await adapter.poll();

    expect(result.items).toHaveLength(1);
    expect(result.items[0]).toMatchObject({
      id: "offload:controller-down",
      kind: "build",
      severity: "act",
      title: "Build controller unreachable",
    });
    expect(result.panels).toHaveLength(4);
    for (const panel of result.panels) {
      expect((panel.data as { stale: boolean }).stale).toBe(true);
    }
  });

  test("controller-down: Bun connection-refused (no ECONNREFUSED substring) still models controller-down", async () => {
    const bunError = Object.assign(
      new Error("Unable to connect. Is the computer able to access the url?"),
      { code: "ConnectionRefused" },
    );
    const adapter = makeAdapter(createMockFetch({ statusError: bunError }));
    const result = await adapter.poll();

    expect(result.items).toHaveLength(1);
    expect(result.items[0]).toMatchObject({ id: "offload:controller-down", kind: "build" });
    expect(result.panels).toHaveLength(4);
    for (const panel of result.panels) {
      expect((panel.data as { stale: boolean }).stale).toBe(true);
    }
  });

  test("normal-temp fixture emits no cpu-temp-critical item", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metricsFile: "metrics-normal-temp.json",
      }),
    );
    const result = await adapter.poll();
    expect(result.items.filter((item) => item.id.includes("cpu-temp-critical"))).toHaveLength(0);
  });

  test("crit-temp fixture emits exactly one cpu-temp-critical item", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-crit-temp.json",
        metricsFile: "metrics-crit-temp.json",
      }),
    );
    const result = await adapter.poll();

    const tempItems = result.items.filter((item) => item.id.includes("cpu-temp-critical"));
    expect(tempItems).toHaveLength(1);
    expect(tempItems[0]).toMatchObject({
      id: "offload:cpu-temp-critical:debian1",
      kind: "build",
      severity: "act",
    });
    expect(tempItems[0]?.detail).toContain("96°C");
    expect(tempItems[0]?.actions[0]?.verb).toBe("box-drain");
  });

  test("reachable controller with malformed status rejects the poll", async () => {
    const fetchImpl: FetchLike = async (input) => {
      const url = new URL(String(input));
      if (url.pathname === "/status") {
        return new Response("not-json", { status: 200 });
      }
      throw new Error("metrics should not be fetched when status parse fails");
    };
    const adapter = makeAdapter(fetchImpl);
    await expect(adapter.poll()).rejects.toThrow();
  });

  test("reachable controller with wrong-shaped status rejects the poll", async () => {
    const fetchImpl: FetchLike = async (input) => {
      const url = new URL(String(input));
      if (url.pathname === "/status") {
        return new Response(JSON.stringify({ revision: "not-a-number" }), { status: 200 });
      }
      throw new Error("metrics should not be fetched when status validation fails");
    };
    const adapter = makeAdapter(fetchImpl);
    await expect(adapter.poll()).rejects.toThrow();
  });

  test("reachable controller with malformed metric vector rejects the poll", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metricsFile: "metrics-normal-temp.json",
        metricsOverrides: {
          "build_offload_queue_depth": {
            status: "success",
            data: { resultType: "matrix", result: [] },
          },
        },
      }),
    );
    await expect(adapter.poll()).rejects.toThrow();
  });

  test("malformed status after success retains last-good snapshot", async () => {
    const goodFetch = createMockFetch({
      statusFile: "status-normal-temp.json",
      metricsFile: "metrics-normal-temp.json",
    });
    const adapter = makeAdapter(goodFetch);
    const state = buildTestState(() => NOW_MS);
    state.registerAdapter("offload", 30_000);

    const good = await adapter.poll();
    state.recordSuccess("offload", NOW_MS, good.items, good.panels);
    const fleetBefore = state.getPanels().find((panel) => panel.id === "fleet");
    expect((fleetBefore?.data as { stale?: boolean }).stale).toBe(false);

    const badFetch: FetchLike = async (input) => {
      const url = new URL(String(input));
      if (url.pathname === "/status") {
        return new Response(JSON.stringify({ revision: "bad" }), { status: 200 });
      }
      throw new Error("metrics should not be fetched when status validation fails");
    };
    const badAdapter = makeAdapter(badFetch);
    await expect(badAdapter.poll()).rejects.toThrow();
    state.recordFailure("offload", NOW_MS + 1, new Error("status shape mismatch"));

    const fleetAfter = state.getPanels().find((panel) => panel.id === "fleet");
    expect(fleetAfter).toEqual(fleetBefore);
  });

  test("two-mount disk metrics pair free and size bytes per mountpoint", async () => {
    const baseMetrics = loadJson<Record<string, unknown>>("metrics-normal-temp.json");
    const metrics = {
      ...baseMetrics,
      'build_offload_host_disk_free_bytes{host!=""}': {
        status: "success",
        data: {
          resultType: "vector",
          result: [
            {
              metric: { host: "debian1", mountpoint: "/" },
              value: [NOW_MS / 1000, "100000000000"],
            },
            {
              metric: { host: "debian1", mountpoint: "/home" },
              value: [NOW_MS / 1000, "200000000000"],
            },
          ],
        },
      },
      'build_offload_host_disk_size_bytes{host!=""}': {
        status: "success",
        data: {
          resultType: "vector",
          result: [
            {
              metric: { host: "debian1", mountpoint: "/" },
              value: [NOW_MS / 1000, "500000000000"],
            },
            {
              metric: { host: "debian1", mountpoint: "/home" },
              value: [NOW_MS / 1000, "600000000000"],
            },
          ],
        },
      },
    };

    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metrics,
      }),
    );
    const result = await adapter.poll();
    const fleet = result.panels.find((panel) => panel.id === "fleet");
    const hosts = (fleet?.data as { hosts: Array<{ disk: Array<{ mountpoint: string; freeBytes: number; sizeBytes: number }> }> })
      .hosts;
    expect(hosts[0]?.disk).toEqual([
      { mountpoint: "/", freeBytes: 100_000_000_000, sizeBytes: 500_000_000_000 },
      { mountpoint: "/home", freeBytes: 200_000_000_000, sizeBytes: 600_000_000_000 },
    ]);
  });

  test("publishes the recorded ~/.claude parity verdict per host", async () => {
    const state = JSON.stringify({
      schemaVersion: 1,
      probedAt: "2026-07-18T00:00:00.000Z",
      lastConvergeAt: null,
      hosts: {
        debian1: {
          verdict: "drifted",
          detail: "drifted config=87819cd0867f67bb/want=b057be1cca654a1b",
          probedAt: "2026-07-18T00:00:00.000Z",
        },
      },
      announced: { debian1: "bad" },
    });
    const adapter = makeAdapter(
      createMockFetch({ statusFile: "status-normal-temp.json", metricsFile: "metrics-normal-temp.json" }),
      async () => REGISTRY_FIXTURE,
      () => state,
    );
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; parity: { verdict: string } | null }>;
    };
    expect(data.hosts.find((host) => host.host === "debian1")?.parity?.verdict).toBe("drifted");
    // Absent from the state file is not converged: a host the timer never probed says nothing.
    expect(data.hosts.find((host) => host.host !== "debian1")?.parity).toBeNull();
  });

  // The timer may not have run on this machine at all; the poll must still produce a panel.
  test("an unreadable parity state leaves every host's verdict unrecorded", async () => {
    const adapter = makeAdapter(
      createMockFetch({ statusFile: "status-normal-temp.json", metricsFile: "metrics-normal-temp.json" }),
      async () => REGISTRY_FIXTURE,
      () => "{ not json",
    );
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ parity: unknown }>;
    };
    expect(data.hosts.length).toBeGreaterThan(0);
    expect(data.hosts.every((host) => host.parity === null)).toBe(true);
  });

  test("a controller host absent from the registry reaches neither the fleet nor capability", async () => {
    const base = createMockFetch({
      statusFile: "status-normal-temp.json",
      metricsFile: "metrics-normal-temp.json",
    });
    const status = loadJson<{ hosts: Record<string, unknown> }>("status-normal-temp.json");
    status.hosts.rogue = {
      role: "builder",
      state: "available",
      primary: false,
      capability: { probes: [{ name: "tsc", ok: true }] },
    };
    const adapter = makeAdapter(async (input, init) => {
      if (new URL(String(input)).pathname === "/status") {
        return new Response(JSON.stringify(status), { status: 200 });
      }
      return base(input, init);
    });

    const result = await adapter.poll();
    const fleet = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string }>;
    };
    const control = result.panels.find((panel) => panel.id === "offload-control")?.data as {
      capabilityByHost: Record<string, unknown>;
    };
    expect(fleet.hosts.map((host) => host.host)).not.toContain("rogue");
    expect(Object.keys(control.capabilityByHost)).toEqual(["debian1"]);
  });

  test("a registry host the controller never enrolled is listed, not dropped", async () => {
    const adapter = makeAdapter(
      createMockFetch({ statusFile: "status-normal-temp.json", metricsFile: "metrics-normal-temp.json" }),
    );
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{
        host: string;
        enrolled: boolean;
        state: string | null;
        registryState: string | null;
        rustdesk: string | null;
      }>;
      registryError: string | null;
    };
    expect(data.hosts.map((host) => host.host)).toEqual(["debian1", "debian9"]);
    expect(data.registryError).toBeNull();

    const enrolled = data.hosts[0]!;
    expect(enrolled.enrolled).toBe(true);
    expect(enrolled.rustdesk).toBe("28888072");

    const declaredOnly = data.hosts[1]!;
    expect(declaredOnly.enrolled).toBe(false);
    expect(declaredOnly.registryState).toBe("unreachable");
    // Nothing observed it, so nothing is claimed about it.
    expect(declaredOnly.state).toBeNull();
  });

  test("an unreadable registry fails closed before contacting the controller", async () => {
    let contactedController = false;
    const adapter = makeAdapter(
      async () => {
        contactedController = true;
        throw new Error("controller must not be contacted without a registry");
      },
      async () => {
        throw new RegistryUnavailableError("no such file");
      },
    );
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string }>;
      registryError: string | null;
    };
    expect(data.registryError).toContain("no such file");
    expect(data.hosts).toEqual([]);
    expect(contactedController).toBe(false);
  });

  test("a controller outage leaves the declared hosts listed and marked stale", async () => {
    const adapter = makeAdapter(
      createMockFetch({ statusError: new Error("connect ECONNREFUSED 127.0.0.1:8787") }),
    );
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      stale: boolean;
      hosts: Array<{ host: string; enrolled: boolean | null }>;
    };
    expect(data.stale).toBe(true);
    expect(data.hosts.map((host) => host.host)).toEqual(["debian1", "debian9"]);
    expect(data.hosts.every((host) => host.enrolled === null)).toBe(true);
  });

  test("reachable controller but metrics failure rejects the poll", async () => {
    const adapter = makeAdapter(
      createMockFetch({
        statusFile: "status-normal-temp.json",
        metricsError: new Error("metrics query transport failed"),
      }),
    );
    await expect(adapter.poll()).rejects.toThrow("metrics query transport failed");
  });
});

const STALL_QUERY = 'build_offload_host_memory_stall_percent{host!="",window!=""}';
const TMP_USED_QUERY = 'build_offload_host_tmp_used_bytes{host!=""}';
const TMP_SIZE_QUERY = 'build_offload_host_tmp_size_bytes{host!=""}';
const OOM_QUERY = 'build_offload_host_work_slice_oom_kills_total{host!="",slice!=""}';
const SLICE_PIDS_QUERY = 'build_offload_host_work_slice_pids{host!="",slice!=""}';
const SLICE_MEM_QUERY = 'build_offload_host_work_slice_memory_bytes{host!="",slice!=""}';
const SESSIONS_QUERY = 'build_offload_host_sessions{host!=""}';
const REMOTE_WORK_QUERY = 'build_offload_host_remote_work{host!="",kind!=""}';

function vector(samples: Array<{ metric: Record<string, string>; value: number }>) {
  return {
    status: "success",
    data: {
      resultType: "vector",
      result: samples.map(({ metric, value }) => ({ metric, value: [0, String(value)] })),
    },
  };
}

function guardFetch(overrides: Record<string, unknown>) {
  return createMockFetch({
    statusFile: "status-normal-temp.json",
    metricsFile: "metrics-normal-temp.json",
    metricsOverrides: overrides,
  });
}

function guardItems(items: Awaited<ReturnType<ReturnType<typeof makeAdapter>["poll"]>>["items"]) {
  return items.filter((item) => /:(oom-kill|tmp-full|memory-stall):/.test(item.id));
}

describe("offload box-side guard telemetry", () => {
  test("publishes a host's reported live sessions and leaves an unavailable series unknown", async () => {
    const reported = await makeAdapter(guardFetch({
      [SESSIONS_QUERY]: vector([{ metric: { host: "debian1" }, value: 3 }]),
    })).poll();
    const reportedFleet = reported.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; sessions: number | null }>;
    };
    expect(reportedFleet.hosts.find((host) => host.host === "debian1")?.sessions).toBe(3);

    const unavailable = await makeAdapter(guardFetch({})).poll();
    const unavailableFleet = unavailable.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; sessions: number | null }>;
    };
    expect(unavailableFleet.hosts.find((host) => host.host === "debian1")?.sessions).toBeNull();
  });

  test("carries the box's own per-path work counts, and leaves an absent split unknown", async () => {
    const reported = await makeAdapter(guardFetch({
      [REMOTE_WORK_QUERY]: vector([
        { metric: { host: "debian1", kind: "agent_seat" }, value: 2 },
        { metric: { host: "debian1", kind: "remote_build_job" }, value: 1 },
        { metric: { host: "debian1", kind: "offload_shell" }, value: 0 },
      ]),
    })).poll();
    const reportedFleet = reported.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; remoteWork: unknown }>;
    };
    expect(reportedFleet.hosts.find((host) => host.host === "debian1")?.remoteWork).toEqual({
      agentSeats: 2,
      remoteBuildJobs: 1,
      offloadShells: 0,
    });

    // A split missing a kind cannot be summed into an honest total, so it is unknown, not partial.
    const partial = await makeAdapter(guardFetch({
      [REMOTE_WORK_QUERY]: vector([{ metric: { host: "debian1", kind: "agent_seat" }, value: 2 }]),
    })).poll();
    const partialFleet = partial.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; remoteWork: unknown }>;
    };
    expect(partialFleet.hosts.find((host) => host.host === "debian1")?.remoteWork).toBeNull();

    const absent = await makeAdapter(guardFetch({})).poll();
    const absentFleet = absent.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; remoteWork: unknown }>;
    };
    expect(absentFleet.hosts.find((host) => host.host === "debian1")?.remoteWork).toBeNull();
  });

  test("publishes stall, tmpfs and work-slice facts per host on the fleet panel", async () => {
    const adapter = makeAdapter(guardFetch({
      [STALL_QUERY]: vector([
        { metric: { host: "debian1", window: "some60" }, value: 4.5 },
        { metric: { host: "debian1", window: "full60" }, value: 1.5 },
        { metric: { host: "debian1", window: "full300" }, value: 0.5 },
      ]),
      [TMP_USED_QUERY]: vector([{ metric: { host: "debian1" }, value: 69_464_064 }]),
      [TMP_SIZE_QUERY]: vector([{ metric: { host: "debian1" }, value: 16_714_129_408 }]),
      [SLICE_MEM_QUERY]: vector([{ metric: { host: "debian1", slice: "agent.slice" }, value: 2_048 }]),
      [SLICE_PIDS_QUERY]: vector([{ metric: { host: "debian1", slice: "agent.slice" }, value: 12 }]),
      [OOM_QUERY]: vector([{ metric: { host: "debian1", slice: "agent.slice" }, value: 3 }]),
    }));

    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; guard: unknown }>;
    };
    expect(data.hosts.find((host) => host.host === "debian1")?.guard).toEqual({
      stall: { some60: 4.5, full60: 1.5, full300: 0.5 },
      tmpUsedBytes: 69_464_064,
      tmpSizeBytes: 16_714_129_408,
      workSlices: [
        { slice: "agent.slice", memoryBytes: 2_048, pidsCurrent: 12, oomKillTotal: 3 },
      ],
    });
  });

  test("a host with no guard series reports nulls and an empty slice list, never invented numbers", async () => {
    const adapter = makeAdapter(guardFetch({}));
    const result = await adapter.poll();
    const data = result.panels.find((panel) => panel.id === "fleet")?.data as {
      hosts: Array<{ host: string; guard: unknown }>;
    };
    expect(data.hosts[0]?.guard).toEqual({
      stall: { some60: null, full60: null, full300: null },
      tmpUsedBytes: null,
      tmpSizeBytes: null,
      workSlices: [],
    });
  });

  test("an OOM-kill total already on the clock at startup never alerts; only a fresh kill does", async () => {
    let total = 3;
    const fetchImpl = guardFetch({});
    const adapter = createOffloadAdapter({
      fetchImpl: async (input, init) => {
        const url = new URL(String(input));
        if (url.searchParams.get("query") === OOM_QUERY) {
          return new Response(
            JSON.stringify(vector([{ metric: { host: "debian1", slice: "agent.slice" }, value: total }])),
            { status: 200 },
          );
        }
        return fetchImpl(input, init);
      },
      controllerUrl: CONTROLLER_URL,
      metricsUrl: METRICS_URL,
      token: TOKEN,
      now: () => NOW_MS,
      loadRegistry: async () => REGISTRY_FIXTURE,
    });

    expect(guardItems((await adapter.poll()).items)).toHaveLength(0);
    expect(guardItems((await adapter.poll()).items)).toHaveLength(0);

    total = 5;
    const alerted = guardItems((await adapter.poll()).items);
    expect(alerted).toHaveLength(1);
    expect(alerted[0]).toMatchObject({
      id: "offload:oom-kill:debian1:agent.slice:5",
      severity: "act",
    });
    expect(alerted[0]?.detail).toContain("2 kill(s) since the last check");

    // The episode is over: the next poll must not repeat it.
    expect(guardItems((await adapter.poll()).items)).toHaveLength(0);
  });

  test("a full tmpfs alerts because writes are already failing; a merely busy one does not", async () => {
    const busy = makeAdapter(guardFetch({
      [TMP_USED_QUERY]: vector([{ metric: { host: "debian1" }, value: 900 }]),
      [TMP_SIZE_QUERY]: vector([{ metric: { host: "debian1" }, value: 1_000 }]),
    }));
    expect(guardItems((await busy.poll()).items)).toHaveLength(0);

    const full = makeAdapter(guardFetch({
      [TMP_USED_QUERY]: vector([{ metric: { host: "debian1" }, value: 1_000 }]),
      [TMP_SIZE_QUERY]: vector([{ metric: { host: "debian1" }, value: 1_000 }]),
    }));
    const items = guardItems((await full.poll()).items);
    expect(items).toHaveLength(1);
    expect(items[0]).toMatchObject({ id: "offload:tmp-full:debian1", severity: "act" });
  });

  test("a stalled box alerts on lack of forward progress, not on how much memory is in use", async () => {
    const heavyButProgressing = makeAdapter(guardFetch({
      [STALL_QUERY]: vector([
        { metric: { host: "debian1", window: "some60" }, value: 92 },
        { metric: { host: "debian1", window: "full300" }, value: 1 },
      ]),
    }));
    expect(guardItems((await heavyButProgressing.poll()).items)).toHaveLength(0);

    const stalled = makeAdapter(guardFetch({
      [STALL_QUERY]: vector([{ metric: { host: "debian1", window: "full300" }, value: 42 }]),
    }));
    const items = guardItems((await stalled.poll()).items);
    expect(items).toHaveLength(1);
    expect(items[0]).toMatchObject({ id: "offload:memory-stall:debian1", severity: "act" });
    expect(items[0]?.detail).toContain("Nothing was killed");
  });
});
