import assert from "node:assert/strict";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { createFoundryAgentStore } from "./foundry-agent-store.mjs";

test("Foundry agent setup issues separate durable credentials and revoke closes both", async () => {
  const dataRoot = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-agent-store-"));
  let currentTime = Date.parse("2026-07-18T12:00:00.000Z");
  const store = createFoundryAgentStore({ dataRoot, now: () => currentTime });
  try {
    const created = await store.createAgent({
      ownerId: "user_root",
      ownerKey: "dcctouch@gmail.com",
      name: "Foundry Codex",
    });
    assert.equal(created.status, "active");
    assert.equal(created.deviceCount, 0);
    assert.equal((await store.listAgents("another@nodedc.local")).length, 0);

    const setup = await store.issueSetupCode("dcctouch@gmail.com", created.id);
    const redeemed = await store.redeemSetupCode(setup.code, "Mac Pro Codex Desktop");
    assert.match(redeemed.foundryToken, /^fnda_/);
    assert.match(redeemed.ontologyToken, /^fndo_/);
    assert.notEqual(redeemed.foundryToken, redeemed.ontologyToken);
    assert.equal(redeemed.device.revokedAt, null);
    assert.equal(Object.hasOwn(redeemed.device, "foundryTokenHash"), false);
    assert.equal(Object.hasOwn(redeemed.device, "ontologyTokenHash"), false);

    await assert.rejects(
      () => store.redeemSetupCode(setup.code, "Replay"),
      /setup_code_already_redeemed/,
    );

    const foundrySession = await store.authenticateFoundryToken(redeemed.foundryToken, { check: true });
    const ontologySession = await store.authenticateOntologyToken(redeemed.ontologyToken, { check: true });
    assert.equal(foundrySession.actor.actorId, "user_root");
    assert.equal(ontologySession.actor.ownerKey, "dcctouch@gmail.com");
    assert.equal(await store.authenticateFoundryToken(redeemed.ontologyToken), null);
    assert.equal(await store.authenticateOntologyToken(redeemed.foundryToken), null);

    currentTime += 3 * 365 * 24 * 60 * 60_000;
    assert.ok(await store.authenticateFoundryToken(redeemed.foundryToken));
    assert.ok(await store.authenticateOntologyToken(redeemed.ontologyToken));

    const revoked = await store.revokeAgent("dcctouch@gmail.com", created.id);
    assert.equal(revoked.status, "revoked");
    assert.equal(await store.authenticateFoundryToken(redeemed.foundryToken), null);
    assert.equal(await store.authenticateOntologyToken(redeemed.ontologyToken), null);

    const persisted = await readFile(path.join(dataRoot, "agents.json"), "utf8");
    assert.equal(persisted.includes(redeemed.foundryToken), false);
    assert.equal(persisted.includes(redeemed.ontologyToken), false);
  } finally {
    await rm(dataRoot, { recursive: true, force: true });
  }
});

test("Foundry setup codes expire and cannot cross owner boundaries", async () => {
  const dataRoot = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-agent-expiry-"));
  let currentTime = Date.parse("2026-07-18T12:00:00.000Z");
  const store = createFoundryAgentStore({ dataRoot, now: () => currentTime });
  try {
    const agent = await store.createAgent({ ownerId: "user_root", ownerKey: "owner@nodedc.local", name: "Owner agent" });
    await assert.rejects(() => store.issueSetupCode("other@nodedc.local", agent.id), /foundry_agent_not_found/);
    const setup = await store.issueSetupCode("owner@nodedc.local", agent.id);
    currentTime += 16 * 60_000;
    await assert.rejects(() => store.redeemSetupCode(setup.code, "Late device"), /setup_code_expired/);
  } finally {
    await rm(dataRoot, { recursive: true, force: true });
  }
});
