import type { DrawRect, DrawableShape } from './layoutDrawTypes';

export type SelectionRect = {
  x: number;
  y: number;
  width: number;
  height: number;
};

export function clampSelectionRect(startX: number, startY: number, endX: number, endY: number): SelectionRect {
  const x = Math.min(startX, endX);
  const y = Math.min(startY, endY);
  return {
    x,
    y,
    width: Math.abs(endX - startX),
    height: Math.abs(endY - startY),
  };
}

export function resolveGroupedShapeIds(shapes: DrawableShape[], shapeIds: Iterable<string>) {
  const seedIds = new Set(shapeIds);
  if (seedIds.size === 0) {
    return new Set<string>();
  }

  const matchedShapeIds = new Set(shapes.filter((shape) => seedIds.has(shape.id)).map((shape) => shape.id));
  if (matchedShapeIds.size === 0) {
    return seedIds;
  }

  const groupIds = new Set(
    shapes.filter((shape) => seedIds.has(shape.id) && shape.groupId).map((shape) => shape.groupId as string),
  );

  return new Set(
    shapes
      .filter((shape) => seedIds.has(shape.id) || (shape.groupId ? groupIds.has(shape.groupId) : false))
      .map((shape) => shape.id),
  );
}

function isRectIntersectingSelection(shape: DrawRect, selection: SelectionRect) {
  return !(
    shape.x + shape.width < selection.x ||
    shape.x > selection.x + selection.width ||
    shape.y + shape.height < selection.y ||
    shape.y > selection.y + selection.height
  );
}

function isLineIntersectingSelection(shape: DrawableShape, selection: SelectionRect) {
  if (shape.type !== 'line') {
    return false;
  }

  const minX = Math.min(shape.x1, shape.x2);
  const maxX = Math.max(shape.x1, shape.x2);
  const minY = Math.min(shape.y1, shape.y2);
  const maxY = Math.max(shape.y1, shape.y2);

  return !(
    maxX < selection.x ||
    minX > selection.x + selection.width ||
    maxY < selection.y ||
    minY > selection.y + selection.height
  );
}

export function findShapesInSelection(shapes: DrawableShape[], selection: SelectionRect) {
  return shapes.filter((shape) =>
    shape.type === 'rect' ? isRectIntersectingSelection(shape, selection) : isLineIntersectingSelection(shape, selection),
  );
}

export function rebaseShapesToComponentBlueprint(shapes: DrawableShape[]) {
  if (shapes.length === 0) {
    return [];
  }

  const minX = Math.min(...shapes.map((shape) => (shape.type === 'line' ? Math.min(shape.x1, shape.x2) : shape.x)));
  const minY = Math.min(...shapes.map((shape) => (shape.type === 'line' ? Math.min(shape.y1, shape.y2) : shape.y)));

  return shapes.map((shape) =>
    shape.type === 'line'
      ? {
          ...shape,
          x1: shape.x1 - minX,
          y1: shape.y1 - minY,
          x2: shape.x2 - minX,
          y2: shape.y2 - minY,
        }
      : {
          ...shape,
          x: shape.x - minX,
          y: shape.y - minY,
        },
  );
}
