import { describe, it, expect } from "vitest";
import { RecordingConsent } from "./recording-consent";

describe("RecordingConsent.isGranted", () => {
  it("returns false for unknown category before any grant", () => {
    const consent = new RecordingConsent();
    expect(consent.isGranted("analytics")).toBe(false);
  });

  it("returns true after grant and false after withdraw", async () => {
    const consent = new RecordingConsent();
    await consent.grant("analytics");
    expect(consent.isGranted("analytics")).toBe(true);
    await consent.withdraw("analytics");
    expect(consent.isGranted("analytics")).toBe(false);
  });
});

describe("RecordingConsent.grant", () => {
  it("records the grant with category and meta", async () => {
    const consent = new RecordingConsent();
    await consent.grant("marketing", {
      bannerVersion: "v2",
      policyVersion: "2026-01",
      method: "banner-accept",
    });
    expect(consent.grants).toHaveLength(1);
    expect(consent.grants[0]!.category).toBe("marketing");
    expect(consent.grants[0]!.meta?.bannerVersion).toBe("v2");
    expect(consent.grants[0]!.meta?.policyVersion).toBe("2026-01");
    expect(consent.grants[0]!.meta?.method).toBe("banner-accept");
  });

  it("records grant without meta when none provided", async () => {
    const consent = new RecordingConsent();
    await consent.grant("necessary");
    expect(consent.grants[0]!.meta).toBeUndefined();
  });

  it("preserves withdrawnAt on regrant", async () => {
    const consent = new RecordingConsent();
    await consent.grant("analytics");
    await consent.withdraw("analytics");
    const before = consent
      .getCategories()
      .find((c) => c.category === "analytics");
    const withdrawnAt = before?.withdrawnAt;

    await consent.grant("analytics");
    const after = consent
      .getCategories()
      .find((c) => c.category === "analytics");
    expect(after?.withdrawnAt).toEqual(withdrawnAt);
  });
});

describe("RecordingConsent.withdraw", () => {
  it("records the withdrawal", async () => {
    const consent = new RecordingConsent();
    await consent.grant("analytics");
    await consent.withdraw("analytics");
    expect(consent.withdrawals).toContain("analytics");
  });

  it("sets state to denied and records withdrawnAt", async () => {
    const consent = new RecordingConsent();
    await consent.grant("functional");
    await consent.withdraw("functional");
    const cats = consent.getCategories();
    const entry = cats.find((c) => c.category === "functional");
    expect(entry?.state).toBe("denied");
    expect(entry?.withdrawnAt).toBeInstanceOf(Date);
  });
});

describe("RecordingConsent.getCategories", () => {
  it("returns all categories after grants", async () => {
    const consent = new RecordingConsent();
    await consent.grant("necessary");
    await consent.grant("analytics");
    const cats = consent.getCategories();
    expect(cats).toHaveLength(2);
  });

  it("reflects withdrawn state", async () => {
    const consent = new RecordingConsent();
    await consent.grant("marketing");
    await consent.withdraw("marketing");
    const cats = consent.getCategories();
    expect(cats[0]!.state).toBe("denied");
  });
});

describe("RecordingConsent.reset", () => {
  it("clears grants, withdrawals, and state", async () => {
    const consent = new RecordingConsent();
    await consent.grant("analytics");
    await consent.withdraw("analytics");
    consent.reset();
    expect(consent.grants).toHaveLength(0);
    expect(consent.withdrawals).toHaveLength(0);
    expect(consent.getCategories()).toHaveLength(0);
    expect(consent.isGranted("analytics")).toBe(false);
  });
});
