#include "rectangletree.hpp"
#include "godot_cpp/core/class_db.hpp"
#include "godot_cpp/variant/packed_int32_array.hpp"
#include "godot_cpp/variant/packed_vector2_array.hpp"
#include "godot_cpp/variant/vector2.hpp"

RectangleTree::RectangleTree() {}

void RectangleTree::_bind_methods() {
  ClassDB::bind_method(
      godot::D_METHOD("add", "min_bound", "max_bound", "polygon_index"),
      &RectangleTree::add);
  ClassDB::bind_method(godot::D_METHOD("remove", "point"),
                       &RectangleTree::remove);
  ClassDB::bind_method(godot::D_METHOD("query", "point"),
                       &RectangleTree::query);
  ClassDB::bind_method(godot::D_METHOD("nearest", "point", "number"),
                       &RectangleTree::nearest);
  ClassDB::bind_method(godot::D_METHOD("query_rect", "min", "max"),
                       &RectangleTree::query_rect);
}

void RectangleTree::add(const Vector2 &min_bound, const Vector2 &max_bound,
                        const int &polygon_index) {
  // convert into c++ types from godot types
  Rect rect = Rect(min_bound.x, min_bound.y, max_bound.x, max_bound.y);

  tree.Insert(rect.min, rect.max, polygon_index);
}

void RectangleTree::remove(const int &polygon_index) {
  tree.Remove(polygon_index);
}

PackedInt32Array RectangleTree::query(const Vector2 &point) {
  Rect rect = Rect(point.x, point.y, point.x, point.y);

  PackedInt32Array return_value;
  auto callbackLambda = [&return_value](int index) {
    return_value.push_back(index);
    return true;
  };

  tree.Search(rect.min, rect.max, callbackLambda);

  return return_value;
}

PackedInt32Array RectangleTree::nearest(const Vector2 &point,
                                        const int &number) {
  Rect rect = Rect(point.x, point.y, point.x, point.y);

  PackedInt32Array return_value;
  auto callbackLambda = [&return_value, &number](int index, float) {
    return_value.push_back(index);
    return return_value.size() < number;
  };

  tree.NNSearch(rect.min, rect.max, callbackLambda);

  return return_value;
}

PackedInt32Array RectangleTree::query_rect(const Vector2 &min,
                                           const Vector2 &max) {
  Rect rect = Rect(min.x, min.y, max.x, max.y);

  PackedInt32Array return_value;
  auto callbackLambda = [&return_value](int index) {
    return_value.push_back(index);
    return true;
  };

  tree.Search(rect.min, rect.max, callbackLambda);

  return return_value;
}
