import { SystemRole } from "@capakraken/shared";
import { describe, expect, it, vi } from "vitest";
import { utilizationCategoryRouter } from "../router/utilization-category.js";
import { createCallerFactory } from "../trpc.js";

vi.mock("../lib/audit.js", () => ({
  createAuditEntry: vi.fn().mockResolvedValue(undefined),
}));

const createCaller = createCallerFactory(utilizationCategoryRouter);

function createAdminCaller(db: Record<string, unknown>) {
  return createCaller({
    session: {
      user: { email: "admin@example.com", name: "Admin", image: null },
      expires: "2099-01-01T00:00:00.000Z",
    },
    db: db as never,
    dbUser: {
      id: "admin_1",
      systemRole: SystemRole.ADMIN,
      permissionOverrides: null,
    },
    roleDefaults: null,
  });
}

describe("utilization category router", () => {
  it("lists utilization categories with normalized filters", async () => {
    const findMany = vi.fn().mockResolvedValue([
      {
        id: "util_1",
        code: "BILLABLE",
        name: "Billable",
        isActive: true,
        sortOrder: 1,
      },
    ]);
    const caller = createAdminCaller({
      utilizationCategory: {
        findMany,
      },
    });

    const result = await caller.list({ isActive: true });

    expect(result).toHaveLength(1);
    expect(findMany).toHaveBeenCalledWith({
      where: { isActive: true },
      orderBy: { sortOrder: "asc" },
    });
  });

  it("gets a utilization category by id including project counts", async () => {
    const findUnique = vi.fn().mockResolvedValue({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable",
      _count: { projects: 3 },
    });
    const caller = createAdminCaller({
      utilizationCategory: {
        findUnique,
      },
    });

    const result = await caller.getById({ id: "util_1" });

    expect(findUnique).toHaveBeenCalledWith({
      where: { id: "util_1" },
      include: { _count: { select: { projects: true } } },
    });
    expect(result).toMatchObject({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable",
      _count: { projects: 3 },
    });
  });

  it("creates a default category after unsetting previous defaults", async () => {
    const findUnique = vi.fn().mockResolvedValue(null);
    const updateMany = vi.fn().mockResolvedValue({ count: 1 });
    const create = vi.fn().mockResolvedValue({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable",
      isDefault: true,
    });
    const caller = createAdminCaller({
      utilizationCategory: {
        findUnique,
        updateMany,
        create,
      },
    });

    const result = await caller.create({
      code: "BILLABLE",
      name: "Billable",
      sortOrder: 1,
      isDefault: true,
    });

    expect(updateMany).toHaveBeenCalledWith({
      where: { isDefault: true },
      data: { isDefault: false },
    });
    expect(create).toHaveBeenCalledWith({
      data: {
        code: "BILLABLE",
        name: "Billable",
        sortOrder: 1,
        isDefault: true,
      },
    });
    expect(result).toMatchObject({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable",
      isDefault: true,
    });
  });

  it("updates a category and unsets other defaults when requested", async () => {
    const findUnique = vi
      .fn()
      .mockResolvedValueOnce({
        id: "util_1",
        code: "BILLABLE",
        name: "Billable",
        isDefault: false,
      })
      .mockResolvedValueOnce(null);
    const updateMany = vi.fn().mockResolvedValue({ count: 1 });
    const update = vi.fn().mockResolvedValue({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable Updated",
      isDefault: true,
    });
    const caller = createAdminCaller({
      utilizationCategory: {
        findUnique,
        updateMany,
        update,
      },
    });

    const result = await caller.update({
      id: "util_1",
      data: {
        name: "Billable Updated",
        isDefault: true,
      },
    });

    expect(updateMany).toHaveBeenCalledWith({
      where: {
        isDefault: true,
        id: { not: "util_1" },
      },
      data: { isDefault: false },
    });
    expect(update).toHaveBeenCalledWith({
      where: { id: "util_1" },
      data: {
        name: "Billable Updated",
        isDefault: true,
      },
    });
    expect(result).toMatchObject({
      id: "util_1",
      code: "BILLABLE",
      name: "Billable Updated",
      isDefault: true,
    });
  });
});
