import { describe, expect, it } from "vitest";
import {
  buildAllocationMovedSnapshot,
  hasAllocationDateChange,
  requiresAllocationFragmentExtraction,
  shouldTreatAllocationDragAsClick,
} from "./timelineAllocationFinalize.js";

const baseDates = {
  allocationStartDate: new Date("2025-01-01T00:00:00.000Z"),
  allocationEndDate: new Date("2025-01-05T00:00:00.000Z"),
  originalStartDate: new Date("2025-01-01T00:00:00.000Z"),
  originalEndDate: new Date("2025-01-05T00:00:00.000Z"),
  currentStartDate: new Date("2025-01-01T00:00:00.000Z"),
  currentEndDate: new Date("2025-01-05T00:00:00.000Z"),
} as const;

describe("timelineAllocationFinalize", () => {
  it("treats missing dates as no change", () => {
    expect(
      hasAllocationDateChange({
        mode: "move",
        scope: "allocation",
        allocationId: "alloc-1",
        mutationAllocationId: null,
        projectName: "Alpha",
        allocationStartDate: null,
        allocationEndDate: null,
        originalStartDate: null,
        originalEndDate: baseDates.originalEndDate,
        currentStartDate: baseDates.currentStartDate,
        currentEndDate: baseDates.currentEndDate,
        pointerDeltaX: 0,
        daysDelta: 0,
      }),
    ).toBe(false);
  });

  it("detects start or end date changes", () => {
    expect(
      hasAllocationDateChange({
        mode: "move",
        scope: "allocation",
        allocationId: "alloc-1",
        mutationAllocationId: null,
        projectName: "Alpha",
        ...baseDates,
        currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
        pointerDeltaX: 0,
        daysDelta: 1,
      }),
    ).toBe(true);
  });

  it("treats only small move drags without day changes as clicks", () => {
    expect(
      shouldTreatAllocationDragAsClick(
        { mode: "move", daysDelta: 0, pointerDeltaX: -5 },
        5,
      ),
    ).toBe(true);
    expect(
      shouldTreatAllocationDragAsClick(
        { mode: "resize-end", daysDelta: 0, pointerDeltaX: 0 },
        5,
      ),
    ).toBe(false);
    expect(
      shouldTreatAllocationDragAsClick(
        { mode: "move", daysDelta: 1, pointerDeltaX: 2 },
        5,
      ),
    ).toBe(false);
  });

  it("requires extraction only for segment drags that no longer match allocation boundaries", () => {
    expect(
      requiresAllocationFragmentExtraction({
        scope: "segment",
        originalStartDate: baseDates.originalStartDate,
        originalEndDate: baseDates.originalEndDate,
        allocationStartDate: new Date("2024-12-31T00:00:00.000Z"),
        allocationEndDate: baseDates.allocationEndDate,
      }),
    ).toBe(true);

    expect(
      requiresAllocationFragmentExtraction({
        scope: "allocation",
        originalStartDate: baseDates.originalStartDate,
        originalEndDate: baseDates.originalEndDate,
        allocationStartDate: baseDates.allocationStartDate,
        allocationEndDate: baseDates.allocationEndDate,
      }),
    ).toBe(false);
  });

  it("returns null snapshots when required dates or ids are missing", () => {
    expect(
      buildAllocationMovedSnapshot({
        allocationId: null,
        mutationAllocationId: null,
        projectName: "Alpha",
        originalStartDate: baseDates.originalStartDate,
        originalEndDate: baseDates.originalEndDate,
        currentStartDate: baseDates.currentStartDate,
        currentEndDate: baseDates.currentEndDate,
      }),
    ).toBeNull();
  });

  it("builds a mutation snapshot with fallback mutation allocation ids", () => {
    expect(
      buildAllocationMovedSnapshot({
        allocationId: "alloc-1",
        mutationAllocationId: null,
        projectName: null,
        originalStartDate: baseDates.originalStartDate,
        originalEndDate: baseDates.originalEndDate,
        currentStartDate: new Date("2025-01-02T00:00:00.000Z"),
        currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
      }),
    ).toEqual({
      allocationId: "alloc-1",
      mutationAllocationId: "alloc-1",
      projectName: "",
      before: {
        startDate: new Date("2025-01-01T00:00:00.000Z"),
        endDate: new Date("2025-01-05T00:00:00.000Z"),
      },
      after: {
        startDate: new Date("2025-01-02T00:00:00.000Z"),
        endDate: new Date("2025-01-06T00:00:00.000Z"),
      },
    });
  });
});
