import { THREE } from 'expo-three';

export interface Plane {
  id: string;
  center: THREE.Vector3;
  normal: THREE.Vector3;
  extent: {
    width: number;
    length: number;
  };
  confidence: number;
}

export class PlaneDetection {
  private scene: THREE.Scene | null = null;
  private camera: THREE.Camera | null = null;
  private planes: Map<string, Plane> = new Map();
  private planeMeshes: Map<string, THREE.Mesh> = new Map();
  private planeMaterial: THREE.MeshBasicMaterial;

  constructor() {
    this.planeMaterial = new THREE.MeshBasicMaterial({
      color: 0x00ff00,
      transparent: true,
      opacity: 0.3,
      side: THREE.DoubleSide
    });
  }

  setScene(scene: THREE.Scene) {
    this.scene = scene;
  }

  setCamera(camera: THREE.Camera) {
    this.camera = camera;
  }

  async detectPlanes(): Promise<Plane[]> {
    if (!this.scene || !this.camera) {
      throw new Error('Scene and camera must be set before detecting planes');
    }

    try {
      // Simulate plane detection with sample data
      // In a real implementation, this would process camera frames and use
      // computer vision algorithms to detect planes
      const detectedPlanes = this.simulatePlaneDetection();
      this.updatePlanes(detectedPlanes);
      return Array.from(this.planes.values());
    } catch (error) {
      console.error('Error detecting planes:', error);
      throw error;
    }
  }

  private simulatePlaneDetection(): Plane[] {
    // This is a placeholder implementation
    // In a real app, this would use actual plane detection algorithms
    return [
      {
        id: 'plane1',
        center: new THREE.Vector3(0, -1, -3),
        normal: new THREE.Vector3(0, 1, 0),
        extent: { width: 2, length: 2 },
        confidence: 0.9
      }
    ];
  }

  private updatePlanes(detectedPlanes: Plane[]) {
    // Remove planes that are no longer detected
    const currentPlaneIds = new Set(detectedPlanes.map(plane => plane.id));
    for (const [id, mesh] of this.planeMeshes) {
      if (!currentPlaneIds.has(id)) {
        this.scene!.remove(mesh);
        this.planeMeshes.delete(id);
        this.planes.delete(id);
      }
    }

    // Update or add new planes
    for (const plane of detectedPlanes) {
      this.planes.set(plane.id, plane);
      
      let planeMesh = this.planeMeshes.get(plane.id);
      if (!planeMesh) {
        // Create new mesh for newly detected plane
        const geometry = new THREE.PlaneGeometry(plane.extent.width, plane.extent.length);
        planeMesh = new THREE.Mesh(geometry, this.planeMaterial);
        this.planeMeshes.set(plane.id, planeMesh);
        this.scene!.add(planeMesh);
      }

      // Update mesh position and rotation
      planeMesh.position.copy(plane.center);
      planeMesh.lookAt(plane.center.clone().add(plane.normal));
    }
  }

  getDetectedPlanes(): Plane[] {
    return Array.from(this.planes.values());
  }

  clear() {
    // Remove all plane meshes from the scene
    for (const mesh of this.planeMeshes.values()) {
      this.scene?.remove(mesh);
    }
    this.planeMeshes.clear();
    this.planes.clear();
  }
}