import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
import metadata from "../../compat/compatibility-discovery-v2-v3.json" assert { type: "json" };
import registry from "../../generated/route-registry.json" assert { type: "json" };

const root = resolve(import.meta.dirname, "../../..");

describe("evidence-bound V2-to-V3 compatibility inventory", () => {
  it("is reproducible from the pinned evidence inputs", () => {
    const source = resolve(root, "pr7/compat/build-v2-v3-compatibility-matrix.py");
    // The executable check is run by the npm script; retaining a source check
    // here makes the provenance dependency explicit to TypeScript readers.
    expect(readFileSync(source, "utf8")).toContain("vaultfire.v2-v3-compatibility-discovery.v1");
  });

  it("keeps V2 as the default and V3 as an explicit, fail-closed allowlist", () => {
    expect(metadata.operatingPolicy).toMatchObject({
      defaultProtocolVersion: "v2",
      v3Access: "explicit-opt-in-allowlist-only",
      v2ToV3WriteRedirect: "forbidden",
      v3ToV2MoneyFallback: "forbidden",
      v3DefaultState: "fail-closed",
    });
    const v3 = metadata.x402AndDiscoveryRoutes.filter((route) => route.version === "v3") as Array<any>;
    expect(v3).toHaveLength(20);
    expect(v3.map((route) => `${route.method} ${route.path}`)).toEqual(
      registry.routes.filter((route) => route.version === "v3").map((route) => `${route.method} ${route.path}`),
    );
    expect(v3.every((route) => route.compatibility.v3Access === "explicit-opt-in-only")).toBe(true);
  });

  it("does not conflate contract protocol, x402 payment, and Bazaar resource versions", () => {
    expect(metadata.versionConcepts.contractProtocolVersion.values).toEqual(["v2", "v3"]);
    expect(metadata.versionConcepts.x402PaymentRailVersion.value).toBe(2);
    expect(metadata.versionConcepts.bazaarResourceVersion.value).toBe("v2");
    const v3Priced = metadata.x402AndDiscoveryRoutes.filter((route) => route.version === "v3" && !route.free) as Array<any>;
    expect(v3Priced).toHaveLength(0);
    expect(metadata.discoveryPublication.protocolCounts).toEqual({ v2: 76 });
    expect(metadata.discoveryPublication.resourceMetadataEqualsWellKnown).toBe(true);
  });

  it("covers every recorded V2 API route and preserves unresolved response evidence", () => {
    const inventory = readFileSync(resolve(root, "baseline/extracted/v2_api_routes.txt"), "utf8")
      .split("\n").filter(Boolean);
    expect(metadata.v2ApiInventory.map((route) => route.path)).toEqual(inventory);
    expect(metadata.v2ApiInventory).toHaveLength(132);
    expect(metadata.responseEvidenceRules).toMatchObject({ exactFixtures: 1, unresolvedFixtures: 131 });
    expect(metadata.v2ApiInventory.filter((route) => route.responseFixture.fixtureStatus === "exact").map((route) => route.path))
      .toEqual(["/api/contracts"]);
    expect(metadata.v2ApiInventory.filter((route) => route.responseFixture.fixtureStatus === "unresolved")
      .every((route) => route.responseFixture.responseSchema === null && route.responseFixture.method === null)).toBe(true);
  });

  it("covers every V2 contract instance and binds the recovered public alias to exact source provenance", () => {
    expect(metadata.contracts).toHaveLength(134);
    expect(metadata.contracts.every((contract) => contract.protocolVersion === "v2")).toBe(true);
    const unresolved = metadata.contracts.filter((contract) => contract.abi.status === "blocked-unresolved") as Array<any>;
    expect(unresolved).toHaveLength(0);
    const recovered = metadata.contracts.filter((contract) => contract.name === "VaultfireTrustAttestation") as Array<any>;
    expect(recovered).toHaveLength(4);
    expect(recovered.every((contract) => contract.abi.status === "provenance-backed")).toBe(true);
    expect(recovered.every((contract) => contract.abi.file === "legacy/v2/abis/VaultfireTrustAttestation.json")).toBe(true);
    expect(recovered.every((contract) => contract.abi.provenance.sourceContract === "TrustPortabilityExtension")).toBe(true);
    expect(recovered.every((contract) =>
      contract.abi.provenance.compilerInput.runtimeBytecodeBinding.compiledRuntime.sha256
        === "d76f00942be66a3ed6d0153f397f628ce15103f0c86b14f84117728349f1a81e",
    )).toBe(true);
  });

  it("is aligned to the current generated registry rather than a hand-maintained route list", () => {
    expect(metadata.x402AndDiscoveryRoutes).toEqual(registry.routes.map((route) => expect.objectContaining({
      id: route.id,
      method: route.method,
      path: route.path,
      version: route.version,
    })));
  });
});
