import { describe, expect, it, vi } from "vitest";
import { finalizeProjectDrag } from "./timelineProjectDragFinalize.js";

const BASE_DRAG = {
  isDragging: true,
  projectId: "project-1",
  currentStartDate: new Date("2025-01-12T00:00:00.000Z"),
  currentEndDate: new Date("2025-01-22T00:00:00.000Z"),
  daysDelta: 2,
};

describe("timelineProjectDragFinalize", () => {
  it("returns null without clearing when the drag is already inactive", () => {
    const updatePosition = vi.fn();
    const clearSession = vi.fn();

    expect(
      finalizeProjectDrag({
        clientX: 20,
        dragRef: { current: { ...BASE_DRAG, isDragging: false } },
        previewRef: { current: null },
        updatePosition,
        clearSession,
        mutate: vi.fn(),
        mutateAsync: vi.fn(),
      }),
    ).toBeNull();

    expect(updatePosition).toHaveBeenCalledWith(20);
    expect(clearSession).not.toHaveBeenCalled();
  });

  it("preserves preview, clears the session, and fires mutate for real drags", () => {
    const clearSession = vi.fn();
    const mutate = vi.fn();
    const cancelAnimationFrameSpy = vi.fn();
    vi.stubGlobal("cancelAnimationFrame", cancelAnimationFrameSpy);
    const previewRef = {
      current: {
        mode: "move" as const,
        cellWidth: 48,
        targets: [],
        pointerDeltaX: 0,
        daysDelta: 0,
        frame: 7,
      },
    };

    try {
      expect(
        finalizeProjectDrag({
          clientX: 24,
          dragRef: { current: BASE_DRAG },
          previewRef,
          updatePosition: vi.fn(),
          clearSession,
          mutate,
          mutateAsync: vi.fn(),
        }),
      ).toBeNull();

      expect(cancelAnimationFrameSpy).toHaveBeenCalledWith(7);
      expect(previewRef.current.frame).toBeNull();
      expect(clearSession).toHaveBeenCalledOnce();
      expect(mutate).toHaveBeenCalledWith({
        projectId: "project-1",
        newStartDate: new Date("2025-01-12T00:00:00.000Z"),
        newEndDate: new Date("2025-01-22T00:00:00.000Z"),
      });
    } finally {
      vi.unstubAllGlobals();
    }
  });

  it("clears but suppresses mutation for no-op drags", () => {
    const clearSession = vi.fn();
    const mutate = vi.fn();
    const mutateAsync = vi.fn();

    expect(
      finalizeProjectDrag({
        clientX: 30,
        dragRef: { current: { ...BASE_DRAG, daysDelta: 0 } },
        previewRef: { current: null },
        updatePosition: vi.fn(),
        clearSession,
        mutate,
        mutateAsync,
      }),
    ).toBeNull();

    expect(clearSession).toHaveBeenCalledOnce();
    expect(mutate).not.toHaveBeenCalled();
    expect(mutateAsync).not.toHaveBeenCalled();
  });

  it("returns the async mutation promise when requested", async () => {
    const result = { ok: true };
    const mutateAsync = vi.fn().mockResolvedValue(result);

    await expect(
      finalizeProjectDrag({
        clientX: 36,
        mode: "mutateAsync",
        dragRef: { current: BASE_DRAG },
        previewRef: { current: null },
        updatePosition: vi.fn(),
        clearSession: vi.fn(),
        mutate: vi.fn(),
        mutateAsync,
      }),
    ).resolves.toEqual(result);

    expect(mutateAsync).toHaveBeenCalledWith({
      projectId: "project-1",
      newStartDate: new Date("2025-01-12T00:00:00.000Z"),
      newEndDate: new Date("2025-01-22T00:00:00.000Z"),
    });
  });
});
