import { describe, expect, it, vi } from "vitest";
import { beginProjectDragSession } from "./timelineProjectDragSession.js";

describe("timelineProjectDragSession", () => {
  it("starts the session, forwards movement, and finalizes on mouseup", () => {
    const previousCleanup = vi.fn();
    const setState = vi.fn();
    const updatePosition = vi.fn();
    const finalize = vi.fn();
    const state = { projectId: "project-1", isDragging: true };
    const cleanupRef = { current: previousCleanup as (() => void) | null };
    const stateRef = { current: { projectId: null, isDragging: false } };
    const handlers: {
      move?: (event: MouseEvent) => void;
      up?: (event: MouseEvent) => void;
    } = {};

    const attachDrag = vi.fn((_: Document, onMove: (event: MouseEvent) => void, onUp: (event: MouseEvent) => void) => {
      handlers.move = onMove;
      handlers.up = onUp;
      return vi.fn();
    });

    beginProjectDragSession({
      state,
      cleanupRef,
      stateRef,
      setState,
      documentTarget: {} as Document,
      attachDrag,
      updatePosition,
      finalize,
    });

    expect(previousCleanup).toHaveBeenCalledOnce();
    expect(stateRef.current).toBe(state);
    expect(setState).toHaveBeenCalledWith(state);

    handlers.move?.({ clientX: 42 } as MouseEvent);
    expect(updatePosition).toHaveBeenCalledWith(42);

    const preventDefault = vi.fn();
    const attachedCleanup = cleanupRef.current;
    handlers.up?.({ clientX: 54, preventDefault } as unknown as MouseEvent);

    expect(attachedCleanup).toHaveBeenCalledOnce();
    expect(cleanupRef.current).toBeNull();
    expect(finalize).toHaveBeenCalledWith(54);
    expect(preventDefault).toHaveBeenCalledOnce();
  });

  it("works when no prior cleanup is registered", () => {
    const setState = vi.fn();
    const updatePosition = vi.fn();
    const finalize = vi.fn().mockResolvedValue(undefined);
    const cleanupRef = { current: null as (() => void) | null };
    const stateRef = { current: { projectId: null, isDragging: false } };
    let upHandler: ((event: MouseEvent) => void) | undefined;

    beginProjectDragSession({
      state: { projectId: "project-2", isDragging: true },
      cleanupRef,
      stateRef,
      setState,
      documentTarget: {} as Document,
      attachDrag: (_documentTarget, _onMove, onUp) => {
        upHandler = onUp;
        return vi.fn();
      },
      updatePosition,
      finalize,
    });

    upHandler?.({ clientX: 12, preventDefault() {} } as MouseEvent);

    expect(updatePosition).not.toHaveBeenCalled();
    expect(finalize).toHaveBeenCalledWith(12);
    expect(cleanupRef.current).toBeNull();
  });
});
