export class BoundingBox {
  static empty() {
    return { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
  }

  static fromPoints(points = []) {
    const box = BoundingBox.empty();
    points.forEach((point) => BoundingBox.includePoint(box, point));
    return BoundingBox.isValid(box) ? box : null;
  }

  static includePoint(box, point) {
    if (!point || !Number.isFinite(point.x) || !Number.isFinite(point.y)) {
      return box;
    }

    box.minX = Math.min(box.minX, point.x);
    box.minY = Math.min(box.minY, point.y);
    box.maxX = Math.max(box.maxX, point.x);
    box.maxY = Math.max(box.maxY, point.y);
    return box;
  }

  static includeBox(box, other) {
    if (!BoundingBox.isValid(other)) {
      return box;
    }

    box.minX = Math.min(box.minX, other.minX);
    box.minY = Math.min(box.minY, other.minY);
    box.maxX = Math.max(box.maxX, other.maxX);
    box.maxY = Math.max(box.maxY, other.maxY);
    return box;
  }

  static isValid(box) {
    return box
      && Number.isFinite(box.minX)
      && Number.isFinite(box.minY)
      && Number.isFinite(box.maxX)
      && Number.isFinite(box.maxY)
      && box.maxX >= box.minX
      && box.maxY >= box.minY;
  }

  static inflate(box, amount) {
    if (!BoundingBox.isValid(box)) {
      return null;
    }

    return {
      minX: box.minX - amount,
      minY: box.minY - amount,
      maxX: box.maxX + amount,
      maxY: box.maxY + amount
    };
  }

  static intersects(a, b) {
    return BoundingBox.isValid(a)
      && BoundingBox.isValid(b)
      && a.minX <= b.maxX
      && a.maxX >= b.minX
      && a.minY <= b.maxY
      && a.maxY >= b.minY;
  }

  static containsPoint(box, point) {
    return BoundingBox.isValid(box)
      && point.x >= box.minX
      && point.x <= box.maxX
      && point.y >= box.minY
      && point.y <= box.maxY;
  }

  static toRect(box) {
    if (!BoundingBox.isValid(box)) {
      return null;
    }

    return {
      x: box.minX,
      y: box.minY,
      width: box.maxX - box.minX,
      height: box.maxY - box.minY
    };
  }
}
