import assert from "node:assert/strict";
import test from "node:test";
import { resolveBearer } from "../src/auth.mjs";
import { exactCandidate } from "../src/candidate.mjs";
import { createLabRuntime } from "../src/runtime.mjs";
import { ClaimsDenialService } from "../src/service.mjs";
import { SimulatedClaimsSystem } from "../src/sor.mjs";
import { TelemetryLedger } from "../src/telemetry.mjs";

const fde = resolveBearer("Bearer fde-demo-token");
const observer = resolveBearer("Bearer observer-demo-token");
const admin = resolveBearer("Bearer lab-admin-demo-token");

function request(overrides = {}) {
  return {
    principal: fde,
    caseId: "DENIAL-001",
    expectedCaseRevision: 7,
    candidateId: exactCandidate.candidateId,
    candidateDigest: exactCandidate.digest,
    idempotencyKey: "test-key-001",
    ...overrides,
  };
}

class MismatchedReadbackSystem {
  #system = new SimulatedClaimsSystem();

  getCase(...args) {
    return this.#system.getCase(...args);
  }

  writeRecommendation(...args) {
    return this.#system.writeRecommendation(...args);
  }

  getOperation(...args) {
    const operation = this.#system.getOperation(...args);
    return { ...operation, candidateDigest: "mismatched-readback-digest" };
  }

  recommendationCount(...args) {
    return this.#system.recommendationCount(...args);
  }
}

test("records one recommendation, reads it back, and traces exact cost and latency", async () => {
  const runtime = createLabRuntime();
  const result = await runtime.service.recommend(request());

  assert.equal(result.operationId, "op-0001");
  assert.equal(result.resultingCaseRevision, 8);
  assert.equal(result.candidateDigest, exactCandidate.digest);
  assert.match(result.authorityBoundary, /specialist retains approval and submission authority/i);
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 1);
  assert.equal(
    runtime.service.getOperation({ principal: fde, operationId: result.operationId }).candidateDigest,
    exactCandidate.digest,
  );

  const events = runtime.telemetry.list("aster-health");
  assert.equal(events.length, 1);
  assert.equal(events[0].outcome, "committed_and_read_back");
  assert.equal(events[0].estimatedCostCad, exactCandidate.estimatedCostCadPerRun);
  assert.equal(typeof events[0].latencyMs, "number");
  assert.ok(events[0].latencyMs >= 0);
});

test("fails closed on candidate mismatch before any write", async () => {
  const runtime = createLabRuntime();
  await assert.rejects(
    runtime.service.recommend(request({ candidateDigest: "wrong-digest" })),
    (error) => error.code === "candidate_mismatch" && error.status === 409,
  );
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 0);
});

test("fails closed when the caller lacks write permission", async () => {
  const runtime = createLabRuntime();
  await assert.rejects(
    runtime.service.recommend(request({ principal: observer })),
    (error) => error.code === "forbidden" && error.status === 403,
  );
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 0);
});

test("rejects stale state without overwriting the source record", async () => {
  const runtime = createLabRuntime();
  await assert.rejects(
    runtime.service.recommend(request({ expectedCaseRevision: 6 })),
    (error) =>
      error.code === "stale_case_revision" &&
      error.details.currentRevision === 7 &&
      error.details.expectedRevision === 6,
  );
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 0);
});

test("replays the same idempotent result and rejects key reuse for another request", async () => {
  const runtime = createLabRuntime();
  const first = await runtime.service.recommend(request());
  const replay = await runtime.service.recommend(request());

  assert.equal(replay.operationId, first.operationId);
  assert.equal(replay.idempotentReplay, true);
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 1);
  await assert.rejects(
    runtime.service.recommend(request({ caseId: "DENIAL-002", expectedCaseRevision: 3 })),
    (error) => error.code === "idempotency_key_reused",
  );
});

test("concurrent identical requests share one pending effect", async () => {
  const runtime = createLabRuntime();
  const [first, second] = await Promise.all([
    runtime.service.recommend(request()),
    runtime.service.recommend(request()),
  ]);

  assert.equal(first.operationId, second.operationId);
  assert.equal(first.idempotentReplay, false);
  assert.equal(second.idempotentReplay, true);
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 1);
});

test("recovers a lost response through readback and same-key retry without a duplicate", async () => {
  const runtime = createLabRuntime();
  let uncertain;
  try {
    await runtime.service.recommend(
      request({ principal: admin, failureMode: "after-write-before-response" }),
    );
  } catch (error) {
    uncertain = error;
  }

  assert.equal(uncertain?.code, "response_lost_after_commit");
  assert.equal(uncertain?.status, 503);
  assert.equal(uncertain?.details.operationId, "op-0001");
  assert.equal(
    runtime.service.getOperation({ principal: admin, operationId: "op-0001" }).effect,
    "recommendation_recorded",
  );

  const recovered = await runtime.service.recommend(request({ principal: fde }));
  assert.equal(recovered.operationId, "op-0001");
  assert.equal(recovered.idempotentReplay, true);
  assert.equal(runtime.system.recommendationCount("aster-health", "DENIAL-001"), 1);
  assert.ok(
    runtime.telemetry
      .list("aster-health")
      .some((event) => event.outcome === "uncertain_to_caller"),
  );
});

test("holds an unverified post-write effect in doubt and blocks blind re-execution", async () => {
  const system = new MismatchedReadbackSystem();
  const telemetry = new TelemetryLedger();
  const service = new ClaimsDenialService({ system, telemetry });

  await assert.rejects(
    service.recommend(request()),
    (error) =>
      error.code === "effect_state_in_doubt" &&
      error.status === 503 &&
      error.details.operationId === "op-0001",
  );
  assert.equal(system.recommendationCount("aster-health", "DENIAL-001"), 1);

  await assert.rejects(
    service.recommend(request()),
    (error) =>
      error.code === "effect_state_in_doubt" && error.details.operationId === "op-0001",
  );
  await assert.rejects(
    service.recommend(request({ expectedCaseRevision: 8 })),
    (error) => error.code === "idempotency_key_reused" && error.status === 409,
  );
  assert.equal(system.recommendationCount("aster-health", "DENIAL-001"), 1);

  assert.deepEqual(
    telemetry.list("aster-health").map((event) => event.outcome),
    ["effect_state_in_doubt", "replay_blocked_in_doubt"],
  );
});

test("scopes telemetry to the caller tenant", async () => {
  const runtime = createLabRuntime();
  await runtime.service.recommend(request());
  runtime.telemetry.record({
    operation: "recommendation",
    outcome: "other_tenant_fixture",
    tenantId: "northwind-health",
    caseId: "DENIAL-900",
    candidateDigest: exactCandidate.digest,
  });

  const asterEvents = runtime.service.getTelemetry({ principal: observer });
  const northwindEvents = runtime.service.getTelemetry({
    principal: {
      subject: "northwind-observer",
      tenantId: "northwind-health",
      permissions: ["telemetry:read"],
    },
  });

  assert.equal(asterEvents.length, 1);
  assert.ok(asterEvents.every((event) => event.tenantId === "aster-health"));
  assert.equal(northwindEvents.length, 1);
  assert.equal(northwindEvents[0].tenantId, "northwind-health");
});
