/**
 * WP-08 delivery_unknown semantics — no blind redelivery for high risk.
 */

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

import {
  AgentHostRegistry,
  FactToDoorbellBridge,
  HostSwitchboard,
  InMemoryHostAdapter,
  SwitchboardPaths,
  WorkerBindingStore,
  type ActiveAuthorization,
} from "../index.ts";
import type { WorkerBindingRevision } from "../contracts/WorkerBinding.ts";

async function tempPaths(): Promise<SwitchboardPaths> {
  const root = await mkdtemp(join(tmpdir(), "sb-wp08-du-"));
  const persistDir = join(root, ".codeflowmu", "state");
  await mkdir(persistDir, { recursive: true });
  return new SwitchboardPaths({ persistDir });
}

const auth: ActiveAuthorization = {
  approved: true,
  decisionRef: "GATE-B-TEST",
  approvedAt: new Date().toISOString(),
  approvedBy: "ADMIN",
};

async function seedBinding(
  paths: SwitchboardPaths,
  workerId: string,
  hostId: string,
): Promise<void> {
  const store = new WorkerBindingStore(paths);
  const rev: WorkerBindingRevision = {
    schema: "codeflowmu.worker-binding/v1",
    bindingId: `bind-${workerId}`,
    revision: 1,
    workerId,
    host: {
      hostId,
      externalSessionId: `mem-session-${workerId}`,
      mode: "local",
    },
    state: "ready",
    createdAt: new Date().toISOString(),
    createdBy: "wp08-test",
  };
  await store.append(rev);
}

describe("WP-08 delivery_unknown", () => {
  it("marks delivery_unknown when crash after Host accept; never auto-redelivers high risk", async () => {
    const paths = await tempPaths();
    const host = new InMemoryHostAdapter({ hostId: "host-mem" });
    const registry = new AgentHostRegistry();
    registry.register(host);
    await seedBinding(paths, "DEV-01", "host-mem");

    const bridge = new FactToDoorbellBridge({ paths, mode: "shadow" });
    const enq = await bridge.enqueueFromAdmittedWork({
      workerId: "DEV-01",
      summary: "risky work",
      dedupeKey: "dk-risk-1",
      sourceFactRefs: ["TASK-RISK"],
      admission: { decision: "allow", reason: "allowed" },
      riskLevel: "irreversible",
      priority: "P0",
    });
    assert.equal(enq.status, "enqueued");

    const board = new HostSwitchboard({
      paths,
      registry,
      mode: "shadow",
      afterHostAcceptedBeforeRunningWrite: () => {
        throw new Error("simulated crash after host accept");
      },
    });

    const wake = await board.wakeWorker({
      workerId: "DEV-01",
      doorbellId: enq.doorbellId!,
    });
    assert.equal(wake.status, "delivery_unknown");
    if (wake.status !== "delivery_unknown") return;
    assert.equal(wake.autoRedeliver, false);

    const resolved = await board.resolveDeliveryUnknown({
      workerId: "DEV-01",
      runId: wake.runId,
    });
    // InMemory inspect sees completed events already written by startRun —
    // recovery may resolve to completed, but autoRedeliver stays false.
    assert.equal(resolved.autoRedeliver, false);
    assert.match(resolved.reason, /inspect=|auto_redeliver/);

    const failed = await board.mailbox.list("DEV-01", "failed");
    assert.equal(failed.length, 1);
    assert.equal(failed[0]?.riskLevel, "irreversible");
  });

  it("active without auth cannot wake even if doorbell exists", async () => {
    const paths = await tempPaths();
    const registry = new AgentHostRegistry();
    registry.register(new InMemoryHostAdapter({ hostId: "host-mem" }));
    await seedBinding(paths, "QA-01", "host-mem");
    const bridge = new FactToDoorbellBridge({ paths, mode: "shadow" });
    const enq = await bridge.enqueueFromAdmittedWork({
      workerId: "QA-01",
      summary: "qa",
      dedupeKey: "dk-qa",
      sourceFactRefs: ["TASK-QA"],
      admission: { decision: "allow", reason: "allowed" },
    });
    assert.equal(enq.status, "enqueued");

    // Construct in shadow then try to escalate without token.
    const board = new HostSwitchboard({ paths, registry, mode: "shadow" });
    assert.throws(() => board.setMode("active"));
    void auth;
  });
});
