import "reflect-metadata";
import { describe, it, expect } from "vitest";
import { Container } from "inversify";
import { bindAudit } from "./bind-audit";
import { AUDIT_SYMBOLS } from "./symbols";
import { NoopAuditLog } from "../noop-audit-log";
import { StdoutJsonAuditLog } from "../stdout-json-audit-log";
import { PayloadAuditLog } from "../payload-audit-log";
import { MultiSinkAuditLog } from "../multi-sink-audit-log";
import { TraceIdEnrichingAuditLog } from "../trace-id-enriching-audit-log";
import type { IAuditLog } from "../audit-log.interface";

describe("bindAudit", () => {
  it("defaults to MultiSinkAuditLog([payload, stdout]) when payloadConfig is provided", () => {
    const container = new Container();
    bindAudit(container, { payloadConfig: {} as never });
    const auditLog = container.get<IAuditLog>(AUDIT_SYMBOLS.IAuditLog);
    expect(auditLog).toBeInstanceOf(TraceIdEnrichingAuditLog);
    expect((auditLog as unknown as { inner: unknown }).inner).toBeInstanceOf(MultiSinkAuditLog);
  });

  it("returns StdoutJsonAuditLog alone when payloadConfig omitted + default sinks", () => {
    const container = new Container();
    bindAudit(container, {});
    const auditLog = container.get<IAuditLog>(AUDIT_SYMBOLS.IAuditLog);
    expect(auditLog).toBeInstanceOf(TraceIdEnrichingAuditLog);
    expect((auditLog as unknown as { inner: unknown }).inner).toBeInstanceOf(StdoutJsonAuditLog);
  });

  it("returns NoopAuditLog when sinks=[]", () => {
    const container = new Container();
    bindAudit(container, { sinks: [] });
    const auditLog = container.get<IAuditLog>(AUDIT_SYMBOLS.IAuditLog);
    expect(auditLog).toBeInstanceOf(TraceIdEnrichingAuditLog);
    expect((auditLog as unknown as { inner: unknown }).inner).toBeInstanceOf(NoopAuditLog);
  });

  it("returns PayloadAuditLog when sinks=['payload'] only", () => {
    const container = new Container();
    bindAudit(container, { payloadConfig: {} as never, sinks: ["payload"] });
    const auditLog = container.get<IAuditLog>(AUDIT_SYMBOLS.IAuditLog);
    expect(auditLog).toBeInstanceOf(TraceIdEnrichingAuditLog);
    expect((auditLog as unknown as { inner: unknown }).inner).toBeInstanceOf(PayloadAuditLog);
  });

  it("validates AUDIT_PSEUDONYM_SALT in production", () => {
    const env = process.env as Record<string, string | undefined>;
    const oldEnv = env["NODE_ENV"];
    const oldSalt = env["AUDIT_PSEUDONYM_SALT"];
    env["NODE_ENV"] = "production";
    delete env["AUDIT_PSEUDONYM_SALT"];
    expect(() => bindAudit(new Container(), { sinks: ["stdout"] })).toThrow(
      /AUDIT_PSEUDONYM_SALT/,
    );
    env["NODE_ENV"] = oldEnv;
    if (oldSalt) env["AUDIT_PSEUDONYM_SALT"] = oldSalt;
  });
});
