export interface BoundingBox {
  x: number;
  y: number;
  width: number;
  height: number;
}

export interface TrackedObject {
  id: number;
  bbox: BoundingBox;
  centroid: { x: number; y: number };
  age: number;
  hits: number;
  suit?: string;
  value?: number;
  confidence?: number;
}

export class CentroidTracker {
  private nextObjectId = 0;
  private objects: Map<number, TrackedObject> = new Map();
  private maxDisappeared = 5; // Frames to keep object after losing it
  private maxDistance = 100;   // Max distance to match centroids

  private getCentroid(bbox: BoundingBox) {
    return {
      x: bbox.x + bbox.width / 2,
      y: bbox.y + bbox.height / 2,
    };
  }

  private distance(p1: { x: number; y: number }, p2: { x: number; y: number }) {
    return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
  }

  update(rects: BoundingBox[]): TrackedObject[] {
    if (rects.length === 0) {
      // Deregister objects that have disappeared for too long
      for (const [id, obj] of this.objects.entries()) {
        obj.age++;
        if (obj.age > this.maxDisappeared) {
          this.objects.delete(id);
        }
      }
      return Array.from(this.objects.values());
    }

    const inputCentroids = rects.map(r => this.getCentroid(r));
    const existingObjects = Array.from(this.objects.values());

    if (existingObjects.length === 0) {
      // Initialize objects
      rects.forEach((rect, i) => {
        const id = this.nextObjectId++;
        this.objects.set(id, {
          id,
          bbox: rect,
          centroid: inputCentroids[i],
          age: 0,
          hits: 1
        });
      });
    } else {
      // Match existing objects to new centroids
      const objectCentroids = existingObjects.map(obj => obj.centroid);
      const usedInput = new Set<number>();
      const usedObject = new Set<number>();

      // Simple greedy matching based on distance
      for (let i = 0; i < existingObjects.length; i++) {
        let minDist = this.maxDistance;
        let matchIdx = -1;

        for (let j = 0; j < inputCentroids.length; j++) {
          if (usedInput.has(j)) continue;
          const d = this.distance(objectCentroids[i], inputCentroids[j]);
          if (d < minDist) {
            minDist = d;
            matchIdx = j;
          }
        }

        if (matchIdx !== -1) {
          const obj = existingObjects[i];
          obj.bbox = rects[matchIdx];
          obj.centroid = inputCentroids[matchIdx];
          obj.age = 0;
          obj.hits++;
          usedInput.add(matchIdx);
          usedObject.add(obj.id);
        }
      }

      // Update age for missed objects
      for (const [id, obj] of this.objects.entries()) {
        if (!usedObject.has(id)) {
          obj.age++;
          if (obj.age > this.maxDisappeared) {
            this.objects.delete(id);
          }
        }
      }

      // Register new objects
      inputCentroids.forEach((centroid, i) => {
        if (!usedInput.has(i)) {
          const id = this.nextObjectId++;
          this.objects.set(id, {
            id,
            bbox: rects[i],
            centroid,
            age: 0,
            hits: 1
          });
        }
      });
    }

    return Array.from(this.objects.values());
  }
}
