import { describe, it, expect } from "vitest";
import {
  attachBrand,
  isInstrumented,
  isCaptured,
  isAudited,
} from "@/conformance/brand-runtime";

describe("brand-runtime", () => {
  it("attachBrand adds a non-enumerable property and returns the same reference", () => {
    const fn = () => {};
    const result = attachBrand(fn, "__instrumented");
    expect(result).toBe(fn);
    expect(isInstrumented(fn)).toBe(true);
    // Non-enumerable: must not show up in Object.keys
    expect(Object.keys(fn)).not.toContain("__instrumented");
  });

  it("predicates return false for unwrapped functions", () => {
    const fn = () => {};
    expect(isInstrumented(fn)).toBe(false);
    expect(isCaptured(fn)).toBe(false);
    expect(isAudited(fn)).toBe(false);
  });

  it("predicates discriminate between brands", () => {
    const instrumented = () => {};
    attachBrand(instrumented, "__instrumented");
    expect(isInstrumented(instrumented)).toBe(true);
    expect(isCaptured(instrumented)).toBe(false);
    expect(isAudited(instrumented)).toBe(false);

    const captured = () => {};
    attachBrand(captured, "__captured");
    expect(isInstrumented(captured)).toBe(false);
    expect(isCaptured(captured)).toBe(true);
    expect(isAudited(captured)).toBe(false);

    const audited = () => {};
    attachBrand(audited, "__audited");
    expect(isAudited(audited)).toBe(true);
  });

  it("composing brands stacks them on the same function", () => {
    const fn = () => {};
    attachBrand(fn, "__instrumented");
    attachBrand(fn, "__captured");
    attachBrand(fn, "__audited");
    expect(isInstrumented(fn)).toBe(true);
    expect(isCaptured(fn)).toBe(true);
    expect(isAudited(fn)).toBe(true);
  });

  it("attached brands are non-writable and non-configurable", () => {
    const fn = () => {};
    attachBrand(fn, "__instrumented");
    const desc = Object.getOwnPropertyDescriptor(fn, "__instrumented");
    expect(desc?.writable).toBe(false);
    expect(desc?.configurable).toBe(false);
    expect(desc?.enumerable).toBe(false);
    expect(desc?.value).toBe(true);
  });

  it("predicates return false for non-function inputs", () => {
    expect(isInstrumented(null)).toBe(false);
    expect(isInstrumented(undefined)).toBe(false);
    expect(isInstrumented(42)).toBe(false);
    expect(isInstrumented("string")).toBe(false);
    expect(isInstrumented({})).toBe(false);
  });
});
