class Quadtree {
    constructor(boundary, capacity) {
      // Boundary is the bounding box of the area this quadtree node covers
      // Capacity is the maximum number of curves a node can hold before subdividing
      this.boundary = boundary; // {x: {min: <value>, max: <value>}, y: {min: <value>, max: <value>}}
      this.capacity = capacity;
      this.curveIndexes = [];
      this.curves = [];
      this.divided = false;
  
      this.nw = null; // Northwest quadrant
      this.ne = null; // Northeast quadrant
      this.sw = null; // Southwest quadrant
      this.se = null; // Southeast quadrant
    }
    
  
    // Check if a bounding box intersects with the boundary of this quadtree node
    intersects(bbox) {
      return !(bbox.x.max < this.boundary.x.min || bbox.x.min > this.boundary.x.max ||
               bbox.y.max < this.boundary.y.min || bbox.y.min > this.boundary.y.max);
    }
  
    // Subdivide this quadtree node into 4 quadrants
    subdivide() {
      const xMid = (this.boundary.x.min + this.boundary.x.max) / 2;
      const yMid = (this.boundary.y.min + this.boundary.y.max) / 2;
  
      const nwBoundary = { x: { min: this.boundary.x.min, max: xMid }, y: { min: this.boundary.y.min, max: yMid }};
      const neBoundary = { x: { min: xMid, max: this.boundary.x.max }, y: { min: this.boundary.y.min, max: yMid }};
      const swBoundary = { x: { min: this.boundary.x.min, max: xMid }, y: { min: yMid, max: this.boundary.y.max }};
      const seBoundary = { x: { min: xMid, max: this.boundary.x.max }, y: { min: yMid, max: this.boundary.y.max }};
  
      this.nw = new Quadtree(nwBoundary, this.capacity);
      this.ne = new Quadtree(neBoundary, this.capacity);
      this.sw = new Quadtree(swBoundary, this.capacity);
      this.se = new Quadtree(seBoundary, this.capacity);
  
      this.divided = true;
    }

    insert (curve, curveIdx) {
        const bbox = curve.bbox()
        const isOutside = bbox.x.min < this.boundary.x.min || 
                      bbox.x.max > this.boundary.x.max ||
                      bbox.y.min < this.boundary.y.min || 
                      bbox.y.max > this.boundary.y.max;
        if (isOutside) {
            let newNode = new Quadtree(this.boundary, this.capacity)
            newNode.curveIndexes = this.curveIndexes;
            newNode.curves = this.curves;
            newNode.divided = this.divided;

            newNode.nw = this.nw;
            newNode.ne = this.ne;
            newNode.sw = this.sw;
            newNode.se = this.se;

            this.curveIndexes = [];
            this.curves = [];
            this.subdivide()
            if (bbox.x.max < this.boundary.x.max) {
                if (bbox.y.max < this.boundary.y.max) {
                    this.boundary.x.min -= this.boundary.x.max - this.boundary.x.min
                    this.boundary.y.min -= this.boundary.y.max - this.boundary.y.min
                    this.nw = newNode
                } else {
                    this.boundary.x.min -= this.boundary.x.max - this.boundary.x.min
                    this.boundary.y.max += this.boundary.y.max - this.boundary.y.min
                    this.sw = newNode
                }
            } else {
                if (bbox.y.max < this.boundary.y.max) {
                    this.boundary.x.max += this.boundary.x.max - this.boundary.x.min
                    this.boundary.y.min -= this.boundary.y.max - this.boundary.y.min
                    this.ne = newNode
                } else {
                    this.boundary.x.max += this.boundary.x.max - this.boundary.x.min
                    this.boundary.y.max += this.boundary.y.max - this.boundary.y.min
                    this.se = newNode
                }
            }
            return this.insert(curve, curveIdx)
        } else {
            return this._insert(curve, curveIdx)
        }
    }
  
    // Insert a curve into the quadtree, subdividing if necessary
    _insert(curve, curveIdx) {
      if (curve.points[0].x==381.703125) {
        console.log(this.intersects(curve.bbox()))
        console.log(this.boundary)
      }
      // If the curve's bounding box doesn't intersect this node's boundary, do nothing
      if (!this.intersects(curve.bbox())) {
        return false;
      }
  
      // If the node has space, insert the curve here
      if (this.curves.length < this.capacity) {

        if (curve.points[0].x==381.703125) {
          "inserting"
        }
        this.curves.push(curve);
        this.curveIndexes.push(curveIdx)
        return true;
      }

      if (curve.points[0].x==381.703125) {
        console.log("going down a level")
      }
  
      // Otherwise, subdivide and insert the curve into the appropriate quadrant
      if (!this.divided) {
        this.subdivide();
      }
  
      const resultNw = this.nw._insert(curve, curveIdx);
      const resultNe = this.ne._insert(curve, curveIdx);
      const resultSw = this.sw._insert(curve, curveIdx);
      const resultSe = this.se._insert(curve, curveIdx);

      // Return true if any of the insert operations returned true
      return resultNw || resultNe || resultSw || resultSe;
    }
  
    // Query all curves that intersect with a given bounding box
    query(range, found = []) {
      // If the range doesn't intersect with this node's boundary, return
      if (!this.intersects(range)) {
        return found;
      }
  
    // Check the curves in this node
    for (let i = 0; i < this.curves.length; i++) {
        if (this.bboxIntersect(this.curves[i].bbox(), range)) {
          found.push(this.curveIndexes[i]);  // Return the curve index instead of the curve
        }
      }
  
      // If the node is subdivided, check the child quadrants
      if (this.divided) {
        this.nw.query(range, found);
        this.ne.query(range, found);
        this.sw.query(range, found);
        this.se.query(range, found);
      }
  
      return found;
    }
  
    // Helper method to check if two bounding boxes intersect
    bboxIntersect(bbox1, bbox2) {
      return !(bbox1.x.max < bbox2.x.min || bbox1.x.min > bbox2.x.max ||
               bbox1.y.max < bbox2.y.min || bbox1.y.min > bbox2.y.max);
    }

    clear() {
        this.curveIndexes = [];
        this.curves = [];
        this.divided = false;
    
        this.nw = null; // Northwest quadrant
        this.ne = null; // Northeast quadrant
        this.sw = null; // Southwest quadrant
        this.se = null; // Southeast quadrant
    }
    draw(ctx) {
        // Debug visualization
        ctx.save()
        ctx.strokeStyle = "red"
        ctx.lineWidth = 1
        ctx.beginPath()
        ctx.rect(
            this.boundary.x.min,
            this.boundary.y.min,
            this.boundary.x.max-this.boundary.x.min,
            this.boundary.y.max-this.boundary.y.min
        )
        ctx.stroke()
        if (this.divided) {
            this.nw.draw(ctx)
            this.ne.draw(ctx)
            this.sw.draw(ctx)
            this.se.draw(ctx)
        }
        ctx.restore()
    }
  }

  export { Quadtree };