import { afterEach, describe, expect, it, vi } from "vitest";
import { getAnonymizationConfig, getAnonymizationDirectory } from "../lib/anonymization.js";

describe("anonymization directory", () => {
  afterEach(() => {
    vi.unstubAllEnvs();
  });

  it("persists aliases so existing resources keep the same identity when new resources appear", async () => {
    let storedAliases: Record<string, { displayName: string; eid: string }> = {
      resource_a: {
        displayName: "Iron Man",
        eid: "iron.man",
      },
    };

    const resourcesRoundOne = [
      {
        id: "resource_a",
        eid: "alice",
        displayName: "Alice",
        email: "alice@example.com",
        lcrCents: 14000,
      },
      {
        id: "resource_b",
        eid: "bob",
        displayName: "Bob",
        email: "bob@example.com",
        lcrCents: 11000,
      },
    ];

    const resourcesRoundTwo = [
      ...resourcesRoundOne,
      {
        id: "resource_c",
        eid: "carol",
        displayName: "Carol",
        email: "carol@example.com",
        lcrCents: 12500,
      },
    ];

    const db = {
      systemSettings: {
        findUnique: vi.fn(async () => ({
          anonymizationEnabled: true,
          anonymizationDomain: "superhartmut.de",
          anonymizationSeed: "stable-seed",
          anonymizationMode: "global",
          anonymizationAliases: storedAliases,
        })),
        update: vi.fn(async ({ data }: { data: { anonymizationAliases: typeof storedAliases } }) => {
          storedAliases = data.anonymizationAliases;
          return {};
        }),
      },
      resource: {
        findMany: vi
          .fn()
          .mockResolvedValueOnce(resourcesRoundOne)
          .mockResolvedValueOnce(resourcesRoundTwo),
      },
    };

    const firstDirectory = await getAnonymizationDirectory(db as never);
    const secondDirectory = await getAnonymizationDirectory(db as never);

    expect(firstDirectory?.byResourceId.get("resource_a")).toMatchObject({
      displayName: "Iron Man",
      eid: "iron.man",
      email: "iron.man@superhartmut.de",
    });
    expect(firstDirectory?.byResourceId.get("resource_b")).toBeDefined();
    expect(secondDirectory?.byResourceId.get("resource_a")).toMatchObject({
      displayName: "Iron Man",
      eid: "iron.man",
      email: "iron.man@superhartmut.de",
    });
    expect(secondDirectory?.byResourceId.get("resource_b")).toEqual(
      firstDirectory?.byResourceId.get("resource_b"),
    );
    expect(secondDirectory?.byResourceId.get("resource_c")).toBeDefined();
    expect(db.systemSettings.update).toHaveBeenCalledTimes(2);
  });

  it("regenerates legacy aliases with digits into stable aliases without numeric characters", async () => {
    let storedAliases: Record<string, { displayName: string; eid: string }> = {
      resource_a: {
        displayName: "Baloo 16",
        eid: "baloo.16",
      },
    };

    const db = {
      systemSettings: {
        findUnique: vi.fn(async () => ({
          anonymizationEnabled: true,
          anonymizationDomain: "superhartmut.de",
          anonymizationSeed: "stable-seed",
          anonymizationMode: "global",
          anonymizationAliases: storedAliases,
        })),
        update: vi.fn(async ({ data }: { data: { anonymizationAliases: typeof storedAliases } }) => {
          storedAliases = data.anonymizationAliases;
          return {};
        }),
      },
      resource: {
        findMany: vi.fn().mockResolvedValue([
          {
            id: "resource_a",
            eid: "alice",
            displayName: "Alice",
            email: "alice@example.com",
            lcrCents: 6000,
          },
        ]),
      },
    };

    const directory = await getAnonymizationDirectory(db as never);
    const alias = directory?.byResourceId.get("resource_a");

    expect(alias).toBeDefined();
    expect(alias?.displayName).not.toContain("16");
    expect(alias?.eid).not.toContain("16");
    expect(alias?.displayName).toMatch(/^[A-Za-z]+(?: [A-Za-z]+)*$/);
    expect(alias?.eid).toMatch(/^[a-z]+(?:\.[a-z]+)*$/);
    expect(db.systemSettings.update).toHaveBeenCalledTimes(1);
  });

  it("prefers the anonymization seed from the environment at runtime", async () => {
    vi.stubEnv("ANONYMIZATION_SEED", "env-seed");

    const config = await getAnonymizationConfig({
      systemSettings: {
        findUnique: vi.fn(async () => ({
          anonymizationEnabled: true,
          anonymizationDomain: "example.test",
          anonymizationSeed: "db-seed",
          anonymizationMode: "global",
        })),
      },
    } as never);

    expect(config.seed).toBe("env-seed");
  });
});
