import type { QueryContext } from "@tailor-platform/erp-kit/core";
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { ForbiddenError } from "../lib/errors.generated";
import { baseAllowedPreference, baseOptOutPreference } from "../testing/fixtures";
import { run } from "./listNotificationPreferences";

describe("listNotificationPreferences", () => {
  const ctx: QueryContext = {
    actorId: "user-1",
    permissions: [],
  };

  it("returns every persisted NotificationPreference row for the caller", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([{ ...baseAllowedPreference }, { ...baseOptOutPreference }]);

    const result = await run(mock.db, { userId: "user-1" }, ctx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(2);
    }
  });

  it("returns an empty list when the caller has no persisted rows (fully on defaults)", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([]);

    const result = await run(mock.db, { userId: "user-1" }, ctx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(0);
    }
  });

  it("defaults to the caller when no userId is supplied", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    mock.enqueueResults([{ ...baseAllowedPreference }]);

    const result = await run(mock.db, {}, ctx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.items).toHaveLength(1);
    }
  });

  it("accepts userId == caller.userId and returns the same result as omitting userId", async () => {
    const mock1 = createKyselyMock<Namespace[keyof Namespace]>();
    mock1.enqueueResults([{ ...baseAllowedPreference }]);
    const r1 = await run(mock1.db, {}, ctx);

    const mock2 = createKyselyMock<Namespace[keyof Namespace]>();
    mock2.enqueueResults([{ ...baseAllowedPreference }]);
    const r2 = await run(mock2.db, { userId: "user-1" }, ctx);

    expect(r1.ok).toBe(true);
    expect(r2.ok).toBe(true);
    if (r1.ok && r2.ok) {
      expect(r1.value.items).toEqual(r2.value.items);
    }
  });

  it("rejects userId != caller.userId with FORBIDDEN", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();

    const result = await run(mock.db, { userId: "user-other" }, ctx);

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(ForbiddenError);
    }
  });
});
