import { describe, expect, it } from "vitest";
import { GET, createUnconfiguredStatusReport } from "../../api/v3/protocol-status";
import {
  assertV3Envelope,
  createV3EnvelopeResponse,
  readV3Envelope,
  v3EnvelopeHttpStatus,
} from "../../compat/v3-envelope";

const context = {
  chainId: 8453,
  contractAddress: "0x1111111111111111111111111111111111111111" as const,
  contractStatus: "active" as const,
  blockNumber: 123n,
  blockHash: `0x${"22".repeat(32)}` as const,
  finality: "safe" as const,
  observedAt: "2026-08-20T00:00:00.000Z",
};

describe("V3 versioned API envelope", () => {
  it("requires provenance, version, status, finality, and schema fields for a healthy response", async () => {
    const envelope = await readV3Envelope(context, async () => ({ balance: "0" }));
    expect(envelope).toMatchObject({
      chainId: 8453,
      contractAddress: context.contractAddress,
      protocolVersion: "v3",
      contractStatus: "active",
      status: "ok",
      blockNumber: "123",
      blockHash: context.blockHash,
      observedAt: context.observedAt,
      finality: "safe",
      dataSourceErrors: [],
      schemaVersion: "1.0.0",
      data: { balance: "0" },
    });
    expect(v3EnvelopeHttpStatus(envelope)).toBe(200);
    expect(() => assertV3Envelope(envelope)).not.toThrow();
  });

  it("fails closed on an RPC error instead of returning default-zero data", async () => {
    const envelope = await readV3Envelope(context, async () => { throw new Error("RPC HTTP 503"); });
    expect(envelope).toMatchObject({
      chainId: null,
      contractAddress: null,
      status: "degraded",
      blockNumber: null,
      blockHash: null,
      finality: null,
      dataSourceErrors: ["RPC HTTP 503"],
      data: null,
    });
    const response = createV3EnvelopeResponse(envelope);
    expect(response.status).toBe(503);
    expect(await response.json()).toMatchObject({ data: null, dataSourceErrors: ["RPC HTTP 503"] });
  });

  it("rejects an apparently healthy response that omits required source context", () => {
    expect(() => assertV3Envelope({
      protocolVersion: "v3", status: "ok", dataSourceErrors: [], schemaVersion: "1.0.0", data: {},
    })).toThrow("omitted chainId");
  });

  it("makes the shipped status route fail closed until a live reader is configured", async () => {
    const report = createUnconfiguredStatusReport(new Date(context.observedAt));
    expect(v3EnvelopeHttpStatus(report)).toBe(503);
    const response = await GET(new Request("https://example.test/api/v3/protocol/status"));
    expect(response.status).toBe(503);
    expect(await response.json()).toMatchObject({
      protocolVersion: "v3", status: "degraded", data: null, dataSourceErrors: ["live-status-reader-unconfigured"],
    });
  });
});
