import { describe, it, expect, vi } from "vitest";
import { withSpan } from "@repo/core-shared/instrumentation";
import { withCapture } from "@repo/core-shared/instrumentation";
import { isInstrumented, isCaptured, isAudited } from "@repo/core-shared/conformance";
import { withAudit } from "@/with-audit";
import type { IAuditLog } from "@/audit-log.interface";
import type { ITracer, ISpan } from "@repo/core-shared/instrumentation";
import type { ILogger } from "@repo/core-shared/instrumentation";

function makeTracer(): ITracer {
  return {
    startSpan: vi.fn(async (_opts, fn) => {
      const span: ISpan = { setAttribute: () => {}, setStatus: () => {} };
      return fn(span);
    }),
  };
}

function makeLogger(): ILogger {
  return {
    captureException: vi.fn(),
    captureMessage: vi.fn(),
    addBreadcrumb: vi.fn(),
    setUser: vi.fn(),
  };
}

function makeAuditLog(): IAuditLog {
  return {
    record: vi.fn().mockResolvedValue(undefined),
    eraseSubject: vi.fn().mockResolvedValue(undefined),
  };
}

describe("brand propagation across the full wrapper chain", () => {
  it("withSpan(withCapture(withAudit(fn))) carries all three brands on the outer wrapper", () => {
    const tracer = makeTracer();
    const logger = makeLogger();
    const auditLog = makeAuditLog();
    const fn = async (input: { id: string }) => ({ ok: true, id: input.id });

    const wrapped = withSpan(
      tracer,
      { name: "test.chain", op: "use-case" },
      withCapture(
        logger,
        { feature: "test", layer: "use-case" },
        withAudit(auditLog, fn),
      ),
    );

    expect(isInstrumented(wrapped)).toBe(true);
    expect(isCaptured(wrapped)).toBe(true);
    expect(isAudited(wrapped)).toBe(true);
  });

  it("the full chain preserves input/output behaviour end-to-end", async () => {
    const tracer = makeTracer();
    const logger = makeLogger();
    const auditLog = makeAuditLog();
    const fn = async (input: { id: string }) => ({ ok: true, id: input.id });

    const wrapped = withSpan(
      tracer,
      { name: "test.chain", op: "use-case" },
      withCapture(
        logger,
        { feature: "test", layer: "use-case" },
        withAudit(auditLog, fn),
      ),
    );

    const result = await wrapped({ id: "abc" });
    expect(result).toEqual({ ok: true, id: "abc" });
  });
});
