import { TRPCError } from "@trpc/server";
import { describe, expect, it } from "vitest";
import {
  assertTimelineDateRangeValid,
  buildTimelineAllocationEntryUpdate,
  buildTimelineAllocationMetadata,
  buildTimelineBatchShiftAuditChanges,
  buildTimelineQuickAssignAssignmentInput,
  buildTimelineQuickAssignMetadata,
  calculateTimelineAllocationPercentage,
  shiftTimelineAllocationWindow,
  validateTimelineAllocationDateRanges,
} from "../router/timeline-allocation-mutation-support.js";

describe("timeline allocation mutation support", () => {
  it("preserves existing metadata while updating includeSaturday", () => {
    const result = buildTimelineAllocationMetadata({
      existingMetadata: {
        recurrence: { frequency: "weekly", interval: 2 },
        includeSaturday: false,
      },
      includeSaturday: true,
    });

    expect(result).toEqual({
      metadata: {
        recurrence: { frequency: "weekly", interval: 2 },
        includeSaturday: true,
      },
      includeSaturday: true,
    });
  });

  it("rejects inverted date ranges", () => {
    expect(() =>
      assertTimelineDateRangeValid(
        new Date("2026-04-10T00:00:00.000Z"),
        new Date("2026-04-09T00:00:00.000Z"),
      )).toThrowError(TRPCError);
  });

  it("rounds allocation percentages and clamps them to 100", () => {
    expect(calculateTimelineAllocationPercentage(3.9)).toBe(49);
    expect(calculateTimelineAllocationPercentage(9)).toBe(100);
  });

  it("builds source metadata for quick assign operations", () => {
    expect(buildTimelineQuickAssignMetadata("quickAssign")).toEqual({ source: "quickAssign" });
    expect(buildTimelineQuickAssignMetadata("batchQuickAssign")).toEqual({ source: "batchQuickAssign" });
  });

  it("builds assignment create payloads for quick assign flows", () => {
    expect(
      buildTimelineQuickAssignAssignmentInput({
        resourceId: "resource_1",
        projectId: "project_1",
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-05T00:00:00.000Z"),
        hoursPerDay: 6,
        role: "Engineer",
        roleId: "role_1",
        status: "PROPOSED",
        source: "quickAssign",
      }),
    ).toEqual({
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-04-01T00:00:00.000Z"),
      endDate: new Date("2026-04-05T00:00:00.000Z"),
      hoursPerDay: 6,
      percentage: 75,
      role: "Engineer",
      roleId: "role_1",
      status: "PROPOSED",
      metadata: { source: "quickAssign" },
    });
  });

  it("shifts and clamps allocation windows for each batch-shift mode", () => {
    expect(
      shiftTimelineAllocationWindow({
        startDate: new Date("2026-04-10T00:00:00.000Z"),
        endDate: new Date("2026-04-12T00:00:00.000Z"),
        daysDelta: 2,
        mode: "move",
      }),
    ).toEqual({
      startDate: new Date("2026-04-12T00:00:00.000Z"),
      endDate: new Date("2026-04-14T00:00:00.000Z"),
    });

    expect(
      shiftTimelineAllocationWindow({
        startDate: new Date("2026-04-10T00:00:00.000Z"),
        endDate: new Date("2026-04-12T00:00:00.000Z"),
        daysDelta: 5,
        mode: "resize-start",
      }),
    ).toEqual({
      startDate: new Date("2026-04-12T00:00:00.000Z"),
      endDate: new Date("2026-04-12T00:00:00.000Z"),
    });

    expect(
      shiftTimelineAllocationWindow({
        startDate: new Date("2026-04-10T00:00:00.000Z"),
        endDate: new Date("2026-04-12T00:00:00.000Z"),
        daysDelta: -5,
        mode: "resize-end",
      }),
    ).toEqual({
      startDate: new Date("2026-04-10T00:00:00.000Z"),
      endDate: new Date("2026-04-10T00:00:00.000Z"),
    });
  });

  it("builds batch-shift audit payloads", () => {
    expect(
      buildTimelineBatchShiftAuditChanges({
        mode: "move",
        daysDelta: 3,
        count: 2,
      }),
    ).toEqual({
      operation: "batchShift",
      mode: "move",
      daysDelta: 3,
      count: 2,
    });
  });

  it("validates date ranges in bulk", () => {
    expect(() =>
      validateTimelineAllocationDateRanges([
        {
          startDate: new Date("2026-04-10T00:00:00.000Z"),
          endDate: new Date("2026-04-11T00:00:00.000Z"),
        },
        {
          startDate: new Date("2026-04-12T00:00:00.000Z"),
          endDate: new Date("2026-04-09T00:00:00.000Z"),
        },
      ])).toThrowError(TRPCError);
  });

  it("builds shared update payloads for demand and assignment changes", () => {
    expect(
      buildTimelineAllocationEntryUpdate({
        hoursPerDay: 7.5,
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-10T00:00:00.000Z"),
        metadata: { includeSaturday: true },
        dailyCostCents: 48000,
        role: "Architect",
      }),
    ).toEqual({
      demandRequirementUpdate: {
        hoursPerDay: 7.5,
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-10T00:00:00.000Z"),
        metadata: { includeSaturday: true },
        role: "Architect",
      },
      assignmentUpdate: {
        hoursPerDay: 7.5,
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-10T00:00:00.000Z"),
        dailyCostCents: 48000,
        metadata: { includeSaturday: true },
        role: "Architect",
      },
    });
  });
});
