import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";

import {
  getRegistryPath,
  loadRegistry,
  registerWatchdogManifest,
  restartWatchdogService,
  validateWatchdogManifest,
  validateWatchdogService,
} from "./watchdog-registry.js";

function withTempRegistry(fn) {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clauth-watchdog-"));
  const old = process.env.CLAUTH_WATCHDOG_DIR;
  process.env.CLAUTH_WATCHDOG_DIR = dir;
  try {
    return fn(dir);
  } finally {
    if (old === undefined) delete process.env.CLAUTH_WATCHDOG_DIR;
    else process.env.CLAUTH_WATCHDOG_DIR = old;
    fs.rmSync(dir, { recursive: true, force: true });
  }
}

test("validateWatchdogService accepts a localhost HTTP service", () => {
  const service = validateWatchdogService({
    id: "codeflow-explorer",
    label: "CodeFlow Explorer",
    owner: "codeflow",
    kind: "http",
    health: { url: "http://127.0.0.1:3109/health" },
    restart: { cmd: "pnpm", args: ["--filter", "@regen/codeflow-explorer", "dev"] },
  });
  assert.equal(service.id, "codeflow-explorer");
  assert.equal(service.approvalRequired, true);
});

test("validateWatchdogService rejects non-local health URLs and shell syntax commands", () => {
  assert.throws(() => validateWatchdogService({
    id: "bad",
    label: "Bad",
    kind: "http",
    health: { url: "https://example.com/health" },
  }), /localhost-only/);

  assert.throws(() => validateWatchdogService({
    id: "bad",
    label: "Bad",
    kind: "process",
    restart: { cmd: "cmd.exe & del" },
  }), /not shell syntax/);
});

test("registerWatchdogManifest upserts services by id", () => withTempRegistry(() => {
  const manifest = validateWatchdogManifest({
    source: "test",
    services: [
      { id: "clauth", label: "clauth", kind: "http", health: { url: "http://127.0.0.1:52437/ping" } },
      { id: "codeflow", label: "CodeFlow", kind: "http", health: { url: "http://localhost:3109/health" } },
    ],
  });
  const result = registerWatchdogManifest(manifest);
  assert.equal(result.registered, 2);
  assert.ok(fs.existsSync(getRegistryPath()));
  assert.deepEqual(loadRegistry().services.map((service) => service.id), ["clauth", "codeflow"]);

  registerWatchdogManifest({
    services: [
      { id: "codeflow", label: "CodeFlow Updated", kind: "http", health: { url: "http://localhost:3109/health" } },
    ],
  });
  const registry = loadRegistry();
  assert.equal(registry.services.length, 2);
  assert.equal(registry.services.find((service) => service.id === "codeflow").label, "CodeFlow Updated");
}));

test("restartWatchdogService rejects missing and unapproved services", () => withTempRegistry(() => {
  assert.deepEqual(restartWatchdogService("missing"), { ok: false, error: "service_not_registered" });
  registerWatchdogManifest({
    services: [
      { id: "dev-center", label: "Dev Center", kind: "process", restart: { cmd: "node", args: ["--version"] } },
    ],
  });
  assert.deepEqual(restartWatchdogService("dev-center"), { ok: false, error: "approval_required" });
}));
