import React, { useRef, useEffect } from "react";
import { useFrame } from "@react-three/fiber";
import * as THREE from "three";
import { GLTF } from "three-stdlib";
import { Box3Helper } from "three";
import { SpawnedObject, ProcessData } from "./types";

interface ProcessObjectRendererProps {
  objectId: string;
  object: SpawnedObject;
  process: ProcessData;
  gltf: GLTF;
  showBoundingBox?: boolean;
}

export const ProcessObjectRenderer: React.FC<ProcessObjectRendererProps> = ({
  objectId,
  object,
  process,
  gltf,
  showBoundingBox = false,
}) => {
  const meshRef = useRef<THREE.Mesh>(null);
  const boxHelperRef = useRef<THREE.Box3Helper | null>(null);
  const boundingBoxRef = useRef<THREE.Box3>(new THREE.Box3());

  // Issue 1: Can't assign to ref.current as it's read-only
  useEffect(() => {
    if (object.ref && meshRef.current) {
      // Instead of direct assignment, we need to store the mesh reference another way
      // Option 1: If you can modify the SpawnedObject interface, add a setMesh method
      if (typeof (object as any).setMesh === 'function') {
        (object as any).setMesh(meshRef.current);
      }
      
      // Option 2: Store the mesh in a property that isn't ref.current
      // This requires modifying your SpawnedObject interface to include this property
      (object as any).meshInstance = meshRef.current;
      
      // Option 3: If you need to maintain compatibility, you could use Object.defineProperty
      // But this is a hack and not recommended
      // Object.defineProperty(object.ref, 'current', { value: meshRef.current, writable: true });
    }
  }, [object.ref]);

  // Create a bounding box helper for visualization
  useFrame(() => {
    if (meshRef.current && showBoundingBox) {
      // Update the bounding box to match the mesh position
      if (!boxHelperRef.current) {
        // Get the size of the mesh
        const size = new THREE.Vector3(1, 1, 1);
        
        // If the mesh has geometry, use its dimensions
        if (meshRef.current.geometry) {
          const box = new THREE.Box3().setFromObject(meshRef.current);
          box.getSize(size);
        }
        
        // Create a new bounding box centered on the mesh
        boundingBoxRef.current = new THREE.Box3().setFromCenterAndSize(
          meshRef.current.position,
          size
        );
        
        // Create a helper to visualize the box
        boxHelperRef.current = new Box3Helper(
          boundingBoxRef.current,
          new THREE.Color(0xff0000)
        );
        
        // Add the helper to the scene
        meshRef.current.parent?.add(boxHelperRef.current);
      } else {
        // Update the box position to match the mesh
        boundingBoxRef.current.setFromCenterAndSize(
          meshRef.current.position,
          boundingBoxRef.current.getSize(new THREE.Vector3())
        );
        
        // Force the helper to update
        boxHelperRef.current.updateMatrixWorld(true);
      }
    }
  });

  if (gltf?.scene) {
    return (
      <primitive
        ref={meshRef}
        object={gltf.scene.clone()}
        position={[0, 0, 0]}
        material={object.material}
      />
    );
  }

  // Issue 2: Material color type problem
  return (
    <mesh ref={meshRef}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial
        // Fix the color property access
        color={
          object.material && 'color' in object.material 
            ? (object.material as THREE.MeshStandardMaterial).color 
            : "#00ff00"
        }
        metalness={0.5}
        roughness={0.3}
      />
    </mesh>
  );
};