#pragma once

#include <array>
#include <extra2d/spatial/spatial_index.h>

namespace extra2d {

class QuadTree : public ISpatialIndex {
public:
  static constexpr int MAX_OBJECTS = 10;
  static constexpr int MAX_LEVELS = 5;

  struct QuadTreeNode {
    Rect bounds;
    int level;
    std::vector<std::pair<Node *, Rect>> objects;
    std::array<std::unique_ptr<QuadTreeNode>, 4> children;

    QuadTreeNode(const Rect &bounds, int level);
    bool contains(const Rect &rect) const;
    bool intersects(const Rect &rect) const;
  };

  explicit QuadTree(const Rect &worldBounds);
  ~QuadTree() override = default;

  void insert(Node *node, const Rect &bounds) override;
  void remove(Node *node) override;
  void update(Node *node, const Rect &newBounds) override;

  std::vector<Node *> query(const Rect &area) const override;
  std::vector<Node *> query(const Vec2 &point) const override;
  std::vector<std::pair<Node *, Node *>> queryCollisions() const override;

  void clear() override;
  size_t size() const override;
  bool empty() const override;

  void rebuild() override;

private:
  void split(QuadTreeNode *node);
  void insertIntoNode(QuadTreeNode *node, Node *object, const Rect &bounds);
  void queryNode(const QuadTreeNode *node, const Rect &area,
                 std::vector<Node *> &results) const;
  void queryNode(const QuadTreeNode *node, const Vec2 &point,
                 std::vector<Node *> &results) const;
  void
  collectCollisions(const QuadTreeNode *node,
                    std::vector<std::pair<Node *, Node *>> &collisions) const;
  bool removeFromNode(QuadTreeNode *node, Node *object);

  /**
   * @brief 使用扫描线算法检测节点内对象的碰撞
   * @param objects 对象列表
   * @param collisions 输出碰撞对
   */
  void detectCollisionsInNode(
      const std::vector<std::pair<Node *, Rect>> &objects,
      std::vector<std::pair<Node *, Node *>> &collisions) const;

  std::unique_ptr<QuadTreeNode> root_;
  Rect worldBounds_;
  size_t objectCount_ = 0;

  // 碰撞检测用的临时缓冲区，避免重复分配
  mutable std::vector<std::pair<Node *, Rect>> collisionBuffer_;
};

} // namespace extra2d
