import type { DashboardWidget, GridCellMetrics } from './types.js';

export interface PointerPosition {
  clientX: number;
  clientY: number;
}

export interface DragComputationArgs {
  pointer: PointerPosition;
  containerRect: DOMRect;
  metrics: GridCellMetrics;
  columns: number;
  widget: DashboardWidget;
  rtl: boolean;
  dragOffsetX?: number;
  dragOffsetY?: number;
}

export const computeGridCoordinates = ({
  pointer,
  containerRect,
  metrics,
  columns,
  widget,
  rtl,
  dragOffsetX = 0,
  dragOffsetY = 0,
}: DragComputationArgs): { x: number; y: number } => {
  const relativeX = pointer.clientX - containerRect.left - dragOffsetX;
  const relativeY = pointer.clientY - containerRect.top - dragOffsetY;

  const marginX = metrics.marginHorizontalPx;
  const marginY = metrics.marginVerticalPx;
  const cellWidth = metrics.cellWidthPx;
  const cellHeight = metrics.cellHeightPx;

  const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));

  const adjustedX = clamp(relativeX - marginX, 0, containerRect.width - marginX);
  const adjustedY = clamp(relativeY - marginY, 0, Number.POSITIVE_INFINITY);

  const cellPlusMarginX = cellWidth + marginX;
  const cellPlusMarginY = cellHeight + marginY;

  let gridX = Math.round(adjustedX / cellPlusMarginX);
  if (rtl) {
    gridX = columns - widget.w - gridX;
  }
  gridX = clamp(gridX, 0, columns - widget.w);

  const gridY = clamp(Math.round(adjustedY / cellPlusMarginY), 0, Number.MAX_SAFE_INTEGER);

  return { x: gridX, y: gridY };
};

export interface ResizeComputationArgs {
  pointer: PointerPosition;
  containerRect: DOMRect;
  metrics: GridCellMetrics;
  startWidth: number;
  startHeight: number;
  startPointer: PointerPosition;
  handler: 'e' | 's' | 'se';
  widget: DashboardWidget;
  columns: number;
}

export const computeResizeDimensions = ({
  pointer,
  containerRect,
  metrics,
  startWidth,
  startHeight,
  startPointer,
  handler,
  widget,
  columns,
}: ResizeComputationArgs): { width: number; height: number } => {
  const deltaX = pointer.clientX - startPointer.clientX;
  const deltaY = pointer.clientY - startPointer.clientY;

  let width = startWidth;
  let height = startHeight;

  const cellPlusMarginX = metrics.cellWidthPx + metrics.marginHorizontalPx;
  const cellPlusMarginY = metrics.cellHeightPx + metrics.marginVerticalPx;

  if (handler.includes('e')) {
    const deltaCols = Math.round(deltaX / cellPlusMarginX);
    width = startWidth + deltaCols;
  }

  if (handler.includes('s')) {
    const deltaRows = Math.round(deltaY / cellPlusMarginY);
    height = startHeight + deltaRows;
  }

  const clampedWidth = Math.max(widget.minW || 1, Math.min(width, widget.maxW || columns - widget.x));
  const clampedHeight = Math.max(widget.minH || 1, Math.min(height, widget.maxH || Number.MAX_SAFE_INTEGER));

  return {
    width: clampedWidth,
    height: clampedHeight,
  };
};
