import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { RoleNotFoundError } from "../lib/errors.generated";
import { activeUser, baseRole, inactiveUser, pendingUser } from "../testing/fixtures";
import { run } from "./listUsersByRole";

describe("listUsersByRole", () => {
  it("returns all users currently assigned to the role with status ACTIVE", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([baseRole], [activeUser]);

    const result = await run(mock.db, { roleId: baseRole.id });
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.users).toEqual([activeUser]);
    }
  });

  it("excludes PENDING users from the result", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    // The mock returns whatever rows we pass — the SQL filter would have
    // excluded PENDING upstream, so the returned set contains only ACTIVE.
    // We verify the where clause is applied via the recorded query.
    mock.enqueueResults([baseRole], [activeUser]);

    const result = await run(mock.db, { roleId: baseRole.id });
    expect(result.ok).toBe(true);
    // The pending user must not appear in the result (filter is at SQL level)
    if (result.ok) {
      const ids = result.value.users.map((u) => u.id);
      expect(ids).not.toContain(pendingUser.id);
    }
    // Verify the ACTIVE filter was applied
    const usersQuery = mock.selects[1];
    expect(usersQuery.sql).toMatch(/"User"."status"/);
    expect(usersQuery.parameters).toContain("ACTIVE");
  });

  it("excludes INACTIVE users from the result", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([baseRole], [activeUser]);

    const result = await run(mock.db, { roleId: baseRole.id });
    expect(result.ok).toBe(true);
    if (result.ok) {
      const ids = result.value.users.map((u) => u.id);
      expect(ids).not.toContain(inactiveUser.id);
    }
  });

  it("returns an empty array when the role exists but has no ACTIVE assignments", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([baseRole], []);

    const result = await run(mock.db, { roleId: baseRole.id });
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.users).toEqual([]);
    }
  });

  it("returns ROLE_NOT_FOUND when the role does not exist", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([]);

    const result = await run(mock.db, { roleId: "nonexistent-role" });
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(RoleNotFoundError);
    }
  });
});
