/**
 * 대시보드 위젯 충돌 감지 및 자동 재배치 유틸리티
 */

import { DashboardElement } from "./types";

export interface Rectangle {
  x: number;
  y: number;
  width: number;
  height: number;
}

/**
 * 두 사각형이 겹치는지 확인 (여유있는 충돌 감지)
 * @param rect1 첫 번째 사각형
 * @param rect2 두 번째 사각형
 * @param cellSize 한 그리드 칸의 크기 (기본: 130px)
 */
export function isColliding(rect1: Rectangle, rect2: Rectangle, cellSize: number = 130): boolean {
  // 겹친 영역 계산
  const overlapX = Math.max(
    0,
    Math.min(rect1.x + rect1.width, rect2.x + rect2.width) - Math.max(rect1.x, rect2.x)
  );
  const overlapY = Math.max(
    0,
    Math.min(rect1.y + rect1.height, rect2.y + rect2.height) - Math.max(rect1.y, rect2.y)
  );

  // 큰 그리드의 절반(cellSize/2 ≈ 65px) 이상 겹쳐야 충돌로 간주
  const collisionThreshold = Math.floor(cellSize / 2);
  return overlapX >= collisionThreshold && overlapY >= collisionThreshold;
}

/**
 * 특정 위젯과 충돌하는 다른 위젯들을 찾기
 */
export function findCollisions(
  element: DashboardElement,
  allElements: DashboardElement[],
  cellSize: number = 130,
  excludeId?: string
): DashboardElement[] {
  const elementRect: Rectangle = {
    x: element.position.x,
    y: element.position.y,
    width: element.size.width,
    height: element.size.height,
  };

  return allElements.filter((other) => {
    if (other.id === element.id || other.id === excludeId) {
      return false;
    }

    const otherRect: Rectangle = {
      x: other.position.x,
      y: other.position.y,
      width: other.size.width,
      height: other.size.height,
    };

    return isColliding(elementRect, otherRect, cellSize);
  });
}

/**
 * 충돌을 해결하기 위해 위젯을 아래로 이동
 */
export function resolveCollisionVertically(
  movingElement: DashboardElement,
  collidingElement: DashboardElement,
  gridSize: number = 10
): { x: number; y: number } {
  // 충돌하는 위젯 아래로 이동
  const newY = collidingElement.position.y + collidingElement.size.height + gridSize;
  
  return {
    x: collidingElement.position.x,
    y: Math.round(newY / gridSize) * gridSize, // 그리드에 스냅
  };
}

/**
 * 여러 위젯의 충돌을 재귀적으로 해결
 */
export function resolveAllCollisions(
  elements: DashboardElement[],
  movedElementId: string,
  subGridSize: number = 10,
  canvasWidth: number = 1560,
  cellSize: number = 130,
  maxIterations: number = 50
): DashboardElement[] {
  let result = [...elements];
  let iterations = 0;

  // 이동한 위젯부터 시작
  const movedIndex = result.findIndex((el) => el.id === movedElementId);
  if (movedIndex === -1) return result;

  // Y 좌표로 정렬 (위에서 아래로 처리)
  const sortedIndices = result
    .map((el, idx) => ({ el, idx }))
    .sort((a, b) => a.el.position.y - b.el.position.y)
    .map((item) => item.idx);

  while (iterations < maxIterations) {
    let hasCollision = false;

    for (const idx of sortedIndices) {
      const element = result[idx];
      const collisions = findCollisions(element, result, cellSize);

      if (collisions.length > 0) {
        hasCollision = true;

        // 첫 번째 충돌만 처리 (가장 위에 있는 것)
        const collision = collisions.sort((a, b) => a.position.y - b.position.y)[0];
        
        // 충돌하는 위젯을 아래로 이동
        const collisionIdx = result.findIndex((el) => el.id === collision.id);
        if (collisionIdx !== -1) {
          const newY = element.position.y + element.size.height + subGridSize;
          
          result[collisionIdx] = {
            ...result[collisionIdx],
            position: {
              ...result[collisionIdx].position,
              y: Math.round(newY / subGridSize) * subGridSize,
            },
          };
        }
      }
    }

    if (!hasCollision) break;
    iterations++;
  }

  return result;
}

/**
 * 위젯이 캔버스 경계를 벗어나지 않도록 제한
 */
export function constrainToCanvas(
  element: DashboardElement,
  canvasWidth: number,
  canvasHeight: number,
  gridSize: number = 10
): { x: number; y: number } {
  const maxX = canvasWidth - element.size.width;
  const maxY = canvasHeight - element.size.height;

  return {
    x: Math.max(0, Math.min(Math.round(element.position.x / gridSize) * gridSize, maxX)),
    y: Math.max(0, Math.min(Math.round(element.position.y / gridSize) * gridSize, maxY)),
  };
}

