/**
 * @typedef {"up" | "down" | "left" | "right"} Direction
 */

/**
 * @typedef {object} Rect
 * @property {string} id
 * @property {number} x
 * @property {number} y
 * @property {number} width
 * @property {number} height
 */

/**
 * @param {Rect} rect
 * @returns {{ x: number, y: number }}
 */
export function getRectCenter(rect) {
  return {
    x: rect.x + rect.width / 2,
    y: rect.y + rect.height / 2
  };
}

/**
 * Filter candidates to those that are in the requested direction.
 * @param {Rect} current
 * @param {Rect[]} candidates
 * @param {Direction} direction
 * @returns {Rect[]}
 */
export function getDirectionalCandidates(current, candidates, direction) {
  const currentCenter = getRectCenter(current);
  return candidates.filter((candidate) => {
    const center = getRectCenter(candidate);
    switch (direction) {
      case "up":
        return center.y < currentCenter.y;
      case "down":
        return center.y > currentCenter.y;
      case "left":
        return center.x < currentCenter.x;
      case "right":
        return center.x > currentCenter.x;
      default:
        return false;
    }
  });
}

/**
 * Pick the nearest candidate in a direction using a weighted distance.
 * @param {Rect} current
 * @param {Rect[]} candidates
 * @param {Direction} direction
 * @returns {Rect | null}
 */
export function pickBestCandidate(current, candidates, direction) {
  const currentCenter = getRectCenter(current);
  let best = null;
  let bestScore = Number.POSITIVE_INFINITY;

  for (const candidate of getDirectionalCandidates(current, candidates, direction)) {
    const center = getRectCenter(candidate);
    const dx = center.x - currentCenter.x;
    const dy = center.y - currentCenter.y;
    const primary = direction === "left" || direction === "right" ? Math.abs(dx) : Math.abs(dy);
    const secondary = direction === "left" || direction === "right" ? Math.abs(dy) : Math.abs(dx);
    const score = primary * 1.25 + secondary;

    if (score < bestScore) {
      bestScore = score;
      best = candidate;
    }
  }

  return best;
}
