import { describe, expect, it, vi } from "vitest";
import { listAssignmentBookings } from "../index.js";

describe("listAssignmentBookings", () => {
  it("returns assignments with cost metadata", async () => {
    const db = {
      assignment: {
        findMany: vi.fn().mockResolvedValue([
          {
            id: "asn_1",
            projectId: "proj_1",
            resourceId: "res_1",
            startDate: new Date("2026-03-01T00:00:00.000Z"),
            endDate: new Date("2026-03-02T00:00:00.000Z"),
            hoursPerDay: 6,
            dailyCostCents: 900,
            status: "CONFIRMED",
            project: {
              id: "proj_1",
              name: "Alpha",
              shortCode: "ALPHA",
              status: "ACTIVE",
              orderType: "CHARGEABLE",
              dynamicFields: null,
            },
            resource: {
              id: "res_1",
              displayName: "Alice",
              chapter: "CGI",
            },
          },
          {
            id: "asn_2",
            projectId: "proj_2",
            resourceId: "res_2",
            startDate: new Date("2026-03-03T00:00:00.000Z"),
            endDate: new Date("2026-03-03T00:00:00.000Z"),
            hoursPerDay: 4,
            dailyCostCents: 500,
            status: "PROPOSED",
            project: {
              id: "proj_2",
              name: "Bravo",
              shortCode: "BRAVO",
              status: "DRAFT",
              orderType: "INTERNAL",
              dynamicFields: null,
            },
            resource: {
              id: "res_2",
              displayName: "Bob",
              chapter: "Lighting",
            },
          },
        ]),
      },
    };

    const result = await listAssignmentBookings(db as never, {
      startDate: new Date("2026-03-01T00:00:00.000Z"),
      endDate: new Date("2026-03-31T00:00:00.000Z"),
    });

    expect(result).toEqual([
      {
        id: "asn_1",
        projectId: "proj_1",
        resourceId: "res_1",
        startDate: new Date("2026-03-01T00:00:00.000Z"),
        endDate: new Date("2026-03-02T00:00:00.000Z"),
        hoursPerDay: 6,
        dailyCostCents: 900,
        status: "CONFIRMED",
        project: {
          id: "proj_1",
          name: "Alpha",
          shortCode: "ALPHA",
          status: "ACTIVE",
          orderType: "CHARGEABLE",
          dynamicFields: null,
        },
        resource: {
          id: "res_1",
          displayName: "Alice",
          chapter: "CGI",
        },
      },
      {
        id: "asn_2",
        projectId: "proj_2",
        resourceId: "res_2",
        startDate: new Date("2026-03-03T00:00:00.000Z"),
        endDate: new Date("2026-03-03T00:00:00.000Z"),
        hoursPerDay: 4,
        dailyCostCents: 500,
        status: "PROPOSED",
        project: {
          id: "proj_2",
          name: "Bravo",
          shortCode: "BRAVO",
          status: "DRAFT",
          orderType: "INTERNAL",
          dynamicFields: null,
        },
        resource: {
          id: "res_2",
          displayName: "Bob",
          chapter: "Lighting",
        },
      },
    ]);
  });

  it("supports unbounded resource context queries when no date window is provided", async () => {
    const db = {
      assignment: {
        findMany: vi.fn().mockResolvedValue([]),
      },
    };

    await listAssignmentBookings(db as never, {
      resourceIds: ["res_1", "res_2"],
    });

    expect(db.assignment.findMany).toHaveBeenCalledWith({
      where: {
        status: { not: "CANCELLED" },
        resourceId: { in: ["res_1", "res_2"] },
      },
      select: {
        id: true,
        projectId: true,
        resourceId: true,
        startDate: true,
        endDate: true,
        hoursPerDay: true,
        dailyCostCents: true,
        status: true,
        project: {
          select: {
            id: true,
            name: true,
            shortCode: true,
            status: true,
            orderType: true,
            clientId: true,
            dynamicFields: true,
          },
        },
        resource: {
          select: { id: true, displayName: true, chapter: true },
        },
      },
    });
  });

  it("rejects partial date bounds", async () => {
    const db = {
      assignment: {
        findMany: vi.fn(),
      },
    };

    await expect(
      listAssignmentBookings(db as never, {
        startDate: new Date("2026-03-01T00:00:00.000Z"),
      }),
    ).rejects.toThrow("startDate and endDate must be provided together");

    expect(db.assignment.findMany).not.toHaveBeenCalled();
  });

  it("supports excluding explicit assignment ids", async () => {
    const db = {
      assignment: {
        findMany: vi.fn().mockResolvedValue([]),
      },
    };

    await listAssignmentBookings(db as never, {
      resourceIds: ["res_1"],
      excludeAssignmentIds: ["asn_1"],
    });

    expect(db.assignment.findMany).toHaveBeenCalledWith({
      where: {
        status: { not: "CANCELLED" },
        resourceId: { in: ["res_1"] },
        id: { notIn: ["asn_1"] },
      },
      select: {
        id: true,
        projectId: true,
        resourceId: true,
        startDate: true,
        endDate: true,
        hoursPerDay: true,
        dailyCostCents: true,
        status: true,
        project: {
          select: {
            id: true,
            name: true,
            shortCode: true,
            status: true,
            orderType: true,
            clientId: true,
            dynamicFields: true,
          },
        },
        resource: {
          select: { id: true, displayName: true, chapter: true },
        },
      },
    });
  });
});
