import assert from "node:assert/strict";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, it } from "node:test";

import {
  releaseRecoveryFence,
  tryAcquireRecoveryFence,
} from "../RecoveryFence.ts";

describe("RecoveryFence", () => {
  it("allows one recovery owner for a task/agent snapshot", async () => {
    const root = await mkdtemp(join(tmpdir(), "codeflowmu-recovery-fence-"));
    try {
      const first = tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-001",
        agentId: "DEV-01",
        attemptId: "attempt-1",
        leaseId: "lease-expired-1",
      });
      assert.ok(first);
      const second = tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-001",
        agentId: "DEV-01",
        attemptId: "attempt-1",
        leaseId: "lease-expired-1",
      });
      assert.equal(second, null);
      assert.equal(releaseRecoveryFence(first), true);
      assert.ok(tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-001",
        agentId: "DEV-01",
        attemptId: "attempt-1",
        leaseId: "lease-expired-1",
      }));
    } finally {
      await rm(root, { recursive: true, force: true }).catch(() => undefined);
    }
  });

  it("takes over an expired fence without deleting the new owner", async () => {
    const root = await mkdtemp(join(tmpdir(), "codeflowmu-recovery-fence-stale-"));
    try {
      const expired = tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-002",
        agentId: "DEV-01",
        now: new Date("2026-08-10T00:00:00.000Z"),
        ttlMs: 10_000,
      });
      assert.ok(expired);
      const owner = tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-002",
        agentId: "DEV-01",
        now: new Date("2026-08-10T00:01:00.000Z"),
      });
      assert.ok(owner);
      const contender = tryAcquireRecoveryFence({
        projectRoot: root,
        taskId: "TASK-20260810-002",
        agentId: "DEV-01",
        now: new Date("2026-08-10T00:01:01.000Z"),
      });
      assert.equal(contender, null);
      assert.equal(releaseRecoveryFence(owner), true);
    } finally {
      await rm(root, { recursive: true, force: true }).catch(() => undefined);
    }
  });
});
