import { expect, test } from "bun:test";

import { rootPath } from "./config";
import { hwlabRuntimeLaneSpecForNode } from "./hwlab-node-lanes";
import { releaseAMonitorManifests, releaseAMonitorMigrationArtifactGaps, releaseAMonitorMigrationJob, releaseAMonitorMigrationPool } from "./hwlab-node-web-probe-monitor";
import { readYamlRecord } from "./platform-infra-ops-library";

const source = { sentinelId: "nc01-web-probe-sentinel", node: "NC01", lane: "v03", path: "/var/lib/web-probe-sentinel-nc01/index.sqlite", runtimeConfigRef: "config/hwlab-web-probe-sentinel/profiles.yaml#nodes.NC01.sentinels.nc01-web-probe-sentinel.runtime", stateRoot: "/var/lib/web-probe-sentinel-nc01", ownerPvc: "hwlab-web-probe-sentinel-nc01-state", artifactSources: [{ ownerPvc: "hwlab-web-probe-sentinel-nc01-state", mountPath: "/var/lib/web-probe-sentinel-nc01" }, { ownerPvc: "legacy-web-observe-workspace-nc01", mountPath: "/root/hwlab-v03", hostPath: "/root/hwlab-v03" }] };
const imageRef = "127.0.0.1:5000/hwlab/web-probe-sentinel-nc01:source-commit";

test("Release A live manifests exclude disabled migration Job and select only monitor service Pods", () => {
  const spec = hwlabRuntimeLaneSpecForNode("v03", "NC01");
  const manifests = releaseAMonitorManifests(spec, imageRef, source);
  const service = manifests.find((item) => item.kind === "Service") as any;
  const deployment = manifests.find((item) => item.kind === "Deployment") as any;
  expect(manifests.find((item) => item.kind === "Job")).toBeUndefined();
  expect(service.spec.type).toBe("ClusterIP");
  expect(service.spec.selector).toEqual({ "app.kubernetes.io/name": "hwlab-web-probe-monitor", "app.kubernetes.io/component": "monitor-service" });
  expect(deployment.spec.template.metadata.labels["app.kubernetes.io/component"]).toBe("monitor-service");
  expect(deployment.spec.template.spec.containers[0].image).toBe(imageRef);
  expect(deployment.spec.template.spec.containers[0].readinessProbe.httpGet.path).toBe("/health");
  expect(deployment.spec.template.spec.containers[0].env).toEqual(expect.arrayContaining([expect.objectContaining({ name: "DATABASE_URL", valueFrom: { secretKeyRef: { name: "hwlab-web-probe-monitor-db", key: "DATABASE_URL" } } }), { name: "MONITOR_CENTRAL_HOST", value: "0.0.0.0" }]));
  expect(releaseAMonitorMigrationPool(spec, source)).toEqual({ poolMax: 4, idleTimeoutSeconds: 30 });
  expect(releaseAMonitorManifests(spec, imageRef, source, { migrationJobEnabled: true }).map((item) => item.kind)).toEqual(["Service", "Deployment", "Job"]);
});

test("explicit migration helper renders ordered read-only export import verify Job", () => {
  const job = releaseAMonitorMigrationJob(hwlabRuntimeLaneSpecForNode("v03", "NC01"), imageRef, source, { enabled: true }) as any;
  expect(job.metadata.name).toContain("source-commit");
  expect(job.metadata.labels["app.kubernetes.io/component"]).toBe("migration");
  expect(job.spec.template.metadata.labels["app.kubernetes.io/component"]).toBe("migration");
  expect(job.spec.template.spec.initContainers.map((container: any) => container.name)).toEqual(["export", "import"]);
  expect(job.spec.template.spec.initContainers[0].args).toEqual(expect.arrayContaining(["export", "--snapshot", "/migration/snapshot.json"]));
  expect(job.spec.template.spec.initContainers[0].args).toContain("--json");
  expect(job.spec.template.spec.initContainers[0].args).not.toContain("--confirm");
  expect(job.spec.template.spec.initContainers[1].args).toEqual(expect.arrayContaining(["scripts/cli.ts", "import", "--snapshot", "/migration/snapshot.json", "--confirm"]));
  expect(job.spec.template.spec.initContainers[1].args).toContain("--json");
  expect(job.spec.template.spec.containers[0].args).toEqual(expect.arrayContaining(["scripts/cli.ts", "verify", "--snapshot", "/migration/snapshot.json"]));
  expect(job.spec.template.spec.containers[0].args).toContain("--json");
  for (const container of [...job.spec.template.spec.initContainers, ...job.spec.template.spec.containers]) {
    expect(container.volumeMounts).toEqual(expect.arrayContaining([expect.objectContaining({ name: "legacy-sqlite", mountPath: "/var/lib/web-probe-sentinel-nc01", readOnly: true }), expect.objectContaining({ name: "snapshot", mountPath: "/migration" })]));
  }
  expect(job.spec.template.spec.volumes).toEqual(expect.arrayContaining([{ name: "legacy-sqlite", persistentVolumeClaim: { claimName: "hwlab-web-probe-sentinel-nc01-state", readOnly: true } }, { name: "artifact-1", hostPath: { path: "/root/hwlab-v03", type: "Directory" } }, { name: "snapshot", emptyDir: {} }]));
  expect(job.spec.template.spec.containers[0].volumeMounts).toEqual(expect.arrayContaining([expect.objectContaining({ name: "artifact-1", mountPath: "/root/hwlab-v03", readOnly: true })]));
  expect(job.spec.template.spec.containers[0].env).toEqual(expect.arrayContaining([expect.objectContaining({ name: "DATABASE_URL", valueFrom: { secretKeyRef: { name: "hwlab-web-probe-monitor-db", key: "DATABASE_URL" } } }), expect.objectContaining({ name: "MONITOR_CENTRAL_PG_POOL_MAX", value: "4" })]));
});

test("one-shot migration helper accepts a unique control-plane suffix", () => {
  const job = releaseAMonitorMigrationJob(hwlabRuntimeLaneSpecForNode("v03", "NC01"), imageRef, source, { enabled: true, nameSuffix: "run-42" }) as any;
  expect(job.metadata.name).toContain("source-commit-run-42");
});

test("Release A declares exactly the two approved pre-migration artifact gaps", () => {
  const config = readYamlRecord<Record<string, any>>(rootPath("config/hwlab-web-probe-monitor/runtime.yaml"), "HwlabWebProbeMonitorRuntime");
  const declared = config.monitor.migration.legacyArtifactGaps;
  const resolved = releaseAMonitorMigrationArtifactGaps(hwlabRuntimeLaneSpecForNode("v03", "NC01"), source);
  expect(resolved).toEqual([...declared].sort((left: { runId: string }, right: { runId: string }) => left.runId.localeCompare(right.runId)));
  expect(resolved.every((gap) => gap.artifactCount > 0 && gap.stateDir.startsWith(".") && /^sha256:[a-f0-9]{64}$/u.test(gap.reportSha256))).toBe(true);
});

test("Release A declares the controlled NC01 monitor database Secret projection", () => {
  const config = readYamlRecord<Record<string, any>>(rootPath("config/secrets-distribution.yaml"), "unidesk-secret-distribution");
  expect(config.sources.files).toEqual(expect.arrayContaining([expect.objectContaining({ sourceRef: "hwlab/web-probe-monitor-db.env", type: "env", requiredKeys: ["DATABASE_URL"], createIfMissing: { enabled: false } })]));
  expect(config.kubernetesSecrets).toEqual(expect.arrayContaining([expect.objectContaining({ name: "hwlab-web-probe-monitor-db", targetId: "hwlab-nc01-v03", secretName: "hwlab-web-probe-monitor-db", data: [{ sourceRef: "hwlab/web-probe-monitor-db.env", sourceKey: "DATABASE_URL", targetKey: "DATABASE_URL" }] })]));
});
