import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { z } from "zod";

/**
 * Static host identity, read from the buildbox registry the workstation module owns.
 * READ-ONLY AND OFFLINE BY CONSTRUCTION: this module never pings, sshes, or otherwise
 * touches a host. Reachability here is whatever the registry file declares — a box can be
 * bricked and awaiting console recovery, and a probe from a dashboard poll is exactly the
 * thing that must never happen to it.
 */

/** Same resolution as the workstation module's own registry reader, env override included. */
export function hostsRegistryPath(env: Record<string, string | undefined> = process.env): string {
  return env.BUILDBOX_HOSTS_CONFIG || join(env.HOME || homedir(), ".claude", "buildbox-hosts.json");
}

const RegistrySchema = z.object({
  schema_version: z.literal(1),
  hosts: z.array(z.object({
    name: z.string().min(1),
    state: z.enum(["reachable", "unreachable", "bricked"]),
    roles: z.array(z.string()).optional(),
    notes: z.string().nullable().optional(),
  }).passthrough()),
}).passthrough();

export interface HostFacts {
  name: string;
  /** Registry-declared, never probed. `unknown` = absent from the registry. */
  reachability: "declared-enabled" | "declared-disabled" | "unknown";
  /** The registry's own word for the host's condition; null when it lists no host. */
  state: "reachable" | "unreachable" | "bricked" | null;
  notes: string | null;
}

export interface HostRegistrySnapshot {
  /** Host this collector runs on, from the kernel — the only host it can speak for. */
  localHost: string;
  hosts: HostFacts[];
  /** Path that was read, so the UI can name it when the registry is absent. */
  path: string;
  /** True when the registry file is missing or unparseable; hosts is then empty. */
  missing: boolean;
}

export function readHostRegistry(
  path = hostsRegistryPath(),
  readFileImpl: (p: string) => string = (p) => readFileSync(p, "utf8"),
): { hosts: HostFacts[]; missing: boolean } {
  let parsed: z.infer<typeof RegistrySchema>;
  try {
    parsed = RegistrySchema.parse(JSON.parse(readFileImpl(path)));
  } catch {
    return { hosts: [], missing: true };
  }
  return {
    hosts: parsed.hosts.map((host) => ({
      name: host.name,
      reachability: host.state === "reachable" ? "declared-enabled" as const : "declared-disabled" as const,
      state: host.state,
      notes: host.notes ?? null,
    })),
    missing: false,
  };
}

export function hostFactsFor(
  snapshot: HostRegistrySnapshot,
  name: string | null,
): HostFacts | null {
  if (!name) return null;
  return snapshot.hosts.find((host) => host.name === name)
    ?? { name, reachability: "unknown", state: null, notes: null };
}
