import { computeDragDates, pixelsToDays } from "~/components/timeline/dragMath.js";

type DragPositionLike = {
  originalStartDate: Date | null;
  originalEndDate: Date | null;
  currentStartDate: Date | null;
  currentEndDate: Date | null;
  startMouseX: number;
  pointerDeltaX: number;
  daysDelta: number;
};

type DragMode = "move" | "resize-start" | "resize-end";

export type TimelineDragPositionResult<State> =
  | { handled: false }
  | { handled: true; nextState: State; pointerDeltaX: number; daysDelta: number; shouldSyncState: boolean };

function resolveDragPosition<State extends DragPositionLike>(
  state: State,
  clientX: number,
  cellWidth: number,
  mode: DragMode,
): TimelineDragPositionResult<State> {
  const pointerDeltaX = clientX - state.startMouseX;
  const daysDelta = pixelsToDays(pointerDeltaX, cellWidth);

  if (daysDelta === state.daysDelta) {
    return {
      handled: true,
      nextState: pointerDeltaX === state.pointerDeltaX ? state : { ...state, pointerDeltaX },
      pointerDeltaX,
      daysDelta,
      shouldSyncState: false,
    };
  }

  const { start, end } = computeDragDates(mode, state.originalStartDate!, state.originalEndDate!, daysDelta);
  return {
    handled: true,
    nextState: {
      ...state,
      currentStartDate: start,
      currentEndDate: end,
      pointerDeltaX,
      daysDelta,
    },
    pointerDeltaX,
    daysDelta,
    shouldSyncState: true,
  };
}

export function resolveProjectDragPosition<State extends DragPositionLike & { isDragging: boolean }>(
  drag: State,
  clientX: number,
  cellWidth: number,
): TimelineDragPositionResult<State> {
  if (!drag.isDragging || !drag.originalStartDate || !drag.originalEndDate) {
    return { handled: false };
  }

  return resolveDragPosition(drag, clientX, cellWidth, "move");
}

export function resolveAllocationDragPosition<
  State extends DragPositionLike & { isActive: boolean; mode: DragMode },
>(alloc: State, clientX: number, cellWidth: number): TimelineDragPositionResult<State> {
  if (!alloc.isActive || !alloc.originalStartDate || !alloc.originalEndDate) {
    return { handled: false };
  }

  return resolveDragPosition(alloc, clientX, cellWidth, alloc.mode);
}
