import { readConfig } from "./src/config";
import { extractHostPathEntries, parseContainerCreatingReport, parseProcMounts, runD601RecoveryGuardrails, type RecoveryGuardrailsFixture } from "./src/recovery-guardrails";

type JsonRecord = Record<string, unknown>;

function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
  if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}

const malformedProcMounts = [
  "proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0",
  "drvfs /Docker/host 9p rw,dirsync,aname=drvfs;path=C:\\Program Files\\Docker\\Docker Desktop\\host 0 0",
].join("\n");

const manifest = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: code-queue-scheduler-dev
  namespace: unidesk-dev
spec:
  template:
    spec:
      volumes:
        - name: repo
          hostPath:
            path: /home/ubuntu/unidesk-dev-code-queue-deploy/code-queue
            type: Directory
        - name: state
          hostPath:
            path: /home/ubuntu/unidesk-dev-code-queue-deploy/state/code-queue
            type: DirectoryOrCreate
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mdtodo-dev
  namespace: unidesk-dev
spec:
  template:
    spec:
      volumes:
        - name: workspace
          hostPath:
            path: /home/ubuntu/unidesk-dev-mdtodo-workspace
            type: Directory
        - name: logs
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/mdtodo-dev/logs
            type: DirectoryOrCreate
`;

const kubectlPods = {
  items: [
    {
      metadata: { namespace: "unidesk-dev", name: "code-queue-scheduler-dev-abc" },
      status: {
        containerStatuses: [{
          name: "code-queue",
          state: {
            waiting: {
              reason: "ContainerCreating",
              message: "MountVolume.SetUp failed for volume \"repo\": hostPath type check failed: /home/ubuntu/unidesk-dev-code-queue-deploy/code-queue is not a directory",
            },
          },
        }],
      },
    },
    {
      metadata: { namespace: "unidesk-dev", name: "mdtodo-dev-def" },
      status: {
        containerStatuses: [{
          name: "mdtodo",
          state: { waiting: { reason: "ContainerCreating", message: "" } },
        }],
      },
    },
  ],
};

const staleCriPods = {
  items: [
    {
      id: "sandbox-stale",
      metadata: { name: "code-queue-scheduler-dev-abc", namespace: "unidesk-dev" },
      state: "SANDBOX_NOTREADY",
      createdAt: "2026-05-23T09:00:00.000Z",
    },
  ],
};

export function runD601RecoveryGuardrailsContract(): JsonRecord {
  const procMounts = parseProcMounts(malformedProcMounts, "fixture:/proc/mounts");
  assertCondition(procMounts.ok === false, "malformed /proc/mounts fixture should fail", procMounts);
  assertCondition(procMounts.malformedLines.length === 1, "one malformed mount line expected", procMounts);
  assertCondition(procMounts.malformedLines[0]?.dockerDesktopHost9p === true, "malformed line should be classified as Docker Desktop /Docker/host 9p", procMounts);

  const entries = extractHostPathEntries("fixture.k8s.yaml", manifest);
  assertCondition(entries.some((entry) => entry.hostPath === "/home/ubuntu/unidesk-dev-code-queue-deploy/code-queue"), "hostPath parser should extract repo path", entries);
  assertCondition(entries.some((entry) => entry.hostPath === "/home/ubuntu/unidesk-dev-mdtodo-workspace"), "hostPath parser should extract MDTODO workspace path", entries);

  const fixture: RecoveryGuardrailsFixture = {
    observedAt: "2026-05-23T10:00:00.000Z",
    procMountsText: malformedProcMounts,
    criPodsJsonText: JSON.stringify(staleCriPods),
    kubectlPodsJsonText: JSON.stringify(kubectlPods),
    deployWorktreePath: "/home/ubuntu/unidesk-code-queue-deploy",
    compatibilitySymlinkPath: "/home/ubuntu/cq-deploy",
    manifestPaths: ["fixture.k8s.yaml"],
    manifestTexts: { "fixture.k8s.yaml": manifest },
    pathStates: {
      "/home/ubuntu/unidesk-code-queue-deploy": { kind: "missing" },
      "/home/ubuntu/cq-deploy": { kind: "symlink", target: "/home/ubuntu/unidesk-code-queue-deploy", targetExists: false },
      "/home/ubuntu/unidesk-dev-code-queue-deploy/code-queue": { kind: "missing" },
      "/home/ubuntu/unidesk-dev-code-queue-deploy/state/code-queue": { kind: "missing" },
      "/home/ubuntu/unidesk-dev-mdtodo-workspace": { kind: "missing" },
      "/home/ubuntu/cq-deploy/.state/mdtodo-dev/logs": { kind: "missing" },
    },
  };
  const result = runD601RecoveryGuardrails(readConfig(), fixture);
  assertCondition(result.scope.liveMutationAllowed === false && result.mutation === false, "guardrail result must be read-only", result.scope);
  assertCondition(result.ok === false, "fixture should produce red guardrails", result.redlineSummary);
  assertCondition(result.redlineSummary.requiresManualHostHotfix.includes("proc-mounts-malformed-kubelet-risk"), "malformed mount risk should require manual host hotfix", result.redlineSummary);
  assertCondition(result.redlineSummary.requiresManualHostHotfix.includes("code-queue-deploy-worktree-not-ready"), "missing worktree/symlink target should require manual host hotfix", result.redlineSummary);
  assertCondition(result.redlineSummary.requiresManualHostHotfix.includes("required-hostpaths-not-ready"), "missing hostPath should require manual host hotfix", result.redlineSummary);
  assertCondition(result.redlineSummary.requiresManualHostHotfix.includes("opaque-containercreating-hostpath-risk"), "ContainerCreating hostPath risk should require manual host hotfix", result.redlineSummary);
  assertCondition(result.checks.codeQueueDeployWorktree.canonicalPath.exists === false, "canonical deploy worktree should report missing", result.checks.codeQueueDeployWorktree);
  assertCondition(result.checks.codeQueueDeployWorktree.compatibilitySymlink.isSymlink === true, "compat symlink should be visible", result.checks.codeQueueDeployWorktree);
  assertCondition(result.checks.codeQueueDeployWorktree.compatibilitySymlink.targetExists === false, "compat symlink target should report missing", result.checks.codeQueueDeployWorktree);
  assertCondition(result.checks.hostPaths.missing.some((problem) => problem.entry.hostPath === "/home/ubuntu/unidesk-dev-code-queue-deploy/code-queue"), "missing Directory hostPath should be red", result.checks.hostPaths.missing);
  assertCondition(result.checks.hostPaths.directoryOrCreateMissing.some((problem) => problem.entry.hostPath === "/home/ubuntu/unidesk-dev-code-queue-deploy/state/code-queue"), "DirectoryOrCreate missing should be surfaced separately", result.checks.hostPaths.directoryOrCreateMissing);
  assertCondition(result.checks.mdtodoAdjacentHostPaths.opaqueRisk === true, "MDTODO adjacent hostPath readiness should be opaque when workspace/logs missing", result.checks.mdtodoAdjacentHostPaths);
  assertCondition(result.checks.criSandboxes.staleNotReadyCount === 1, "stale CRI sandbox should be counted", result.checks.criSandboxes);
  assertCondition(result.checks.containerCreating.hostPathContainerCreating.length === 1, "explicit hostPath ContainerCreating should be classified", result.checks.containerCreating);
  assertCondition(result.checks.containerCreating.opaqueContainerCreating.length === 1, "empty-message ContainerCreating should be classified as opaque when hostPaths are missing", result.checks.containerCreating);
  assertCondition(result.redlineSummary.forbiddenAutomaticActions.includes("crictl rmp"), "CRI deletion should be explicitly forbidden", result.redlineSummary);
  assertCondition(result.redlineSummary.forbiddenAutomaticActions.includes("systemctl restart k3s"), "k3s restart should be explicitly forbidden", result.redlineSummary);

  const containerCreatingOnly = parseContainerCreatingReport(JSON.stringify(kubectlPods), result.checks.hostPaths, "fixture", null);
  assertCondition(containerCreatingOnly.ok === false, "ContainerCreating parser should fail when opaque/hostPath findings exist", containerCreatingOnly);

  return {
    ok: true,
    checks: [
      "malformed /proc/mounts Docker Desktop /Docker/host 9p line detected",
      "missing Code Queue worktree symlink and target reported",
      "missing hostPath and DirectoryOrCreate readiness reported",
      "opaque and explicit hostPath ContainerCreating classified",
      "stale CRI sandbox count reported without cleanup",
      "destructive prune/reset/restart/delete actions forbidden",
    ],
  };
}

if (import.meta.main) {
  process.stdout.write(`${JSON.stringify(runD601RecoveryGuardrailsContract(), null, 2)}\n`);
}
