import { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import { Edges } from '@react-three/drei';
import * as THREE from 'three';

interface ResizableBox3DProps {
  l1: number;
  l2: number;
  h: number;
}

function WindParticles({ l1, l2, h }: { l1: number, l2: number, h: number }) {
  const count = 40;
  const meshRef = useRef<THREE.InstancedMesh>(null);
  
  // Create dummy object to compute matrix for each instance
  const dummy = useMemo(() => new THREE.Object3D(), []);
  
  // Generate random starting positions
  const particles = useMemo(() => {
    const temp = [];
    for (let i = 0; i < count; i++) {
      temp.push({
        x: (Math.random() - 0.5) * (l1 * 3), // Spread wider than the building
        y: Math.random() * (h * 1.5),        // Spread higher than the building
        z: (Math.random() * 40) + l2 / 2 + 5, // Start in front of the building
        speed: 10 + Math.random() * 15,       // Random speeds
        offset: Math.random() * 100           // Phase offset
      });
    }
    return temp;
  }, [l1, l2, h, count]);

  useFrame((_state, delta) => {
    if (!meshRef.current) return;
    
    particles.forEach((particle, i) => {
      // Move particle along Z axis (wind direction)
      particle.z -= particle.speed * delta;
      
      // If particle passed the building, reset it to the front
      if (particle.z < -l2 - 10) {
        particle.z = (Math.random() * 20) + l2 / 2 + 10;
        particle.x = (Math.random() - 0.5) * (l1 * 3);
        particle.y = Math.random() * (h * 1.5);
      }

      // Simple avoidance / turbulence effect around the building
      let currentX = particle.x;
      let currentY = particle.y;
      
      // If particle is close to the front face, push it out
      if (particle.z > -l2/2 && particle.z < l2/2 + 2) {
        const isHittingFront = Math.abs(particle.x) < l1/2 + 0.5 && particle.y < h + 0.5;
        if (isHittingFront) {
          // Push to the sides or up
          if (Math.abs(particle.x) > (l1/2) * 0.7) {
             currentX += Math.sign(particle.x) * (20 * delta);
          } else {
             currentY += 20 * delta;
          }
        }
      }

      dummy.position.set(currentX, currentY, particle.z);
      dummy.scale.set(0.05, 0.05, Math.max(0.5, particle.speed * 0.1)); // Stretch by speed
      dummy.updateMatrix();
      meshRef.current!.setMatrixAt(i, dummy.matrix);
    });
    
    meshRef.current.instanceMatrix.needsUpdate = true;
  });

  return (
    <instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
      <cylinderGeometry args={[1, 1, 1, 8]} />
      <meshBasicMaterial color="#60a5fa" transparent opacity={0.4} />
    </instancedMesh>
  );
}

export function ResizableBox3D({ l1, l2, h }: ResizableBox3DProps) {
  const meshRef = useRef<THREE.Mesh>(null);
  
  // Create target scale and position based on inputs
  const targetScale = useMemo(() => new THREE.Vector3(l1, h, l2), [l1, l2, h]);

  useFrame((_state, delta) => {
    if (meshRef.current) {
      // Smoothly animate the scale
      meshRef.current.scale.lerp(targetScale, delta * 5);
      // Smoothly animate the position to keep the base on the ground
      meshRef.current.position.lerp(
        new THREE.Vector3(0, meshRef.current.scale.y / 2, 0),
        delta * 5
      );
    }
  });

  return (
    <group>
      {/* Ground plane for reference */}
      <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0, 0]} receiveShadow>
        <planeGeometry args={[100, 100]} />
        <meshStandardMaterial color="#333" depthWrite={false} transparent opacity={0.2} />
      </mesh>
      <gridHelper args={[100, 40, '#666', '#444']} position={[0, 0.01, 0]} />
      
      {/* The Animated Box */}
      <mesh ref={meshRef} castShadow receiveShadow>
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="#4f46e5" transparent opacity={0.7} roughness={0.2} metalness={0.8} />
        <Edges scale={1} threshold={15} color="#818cf8" />
      </mesh>

      {/* Wind Flow Animation */}
      <WindParticles l1={l1} l2={l2} h={h} />
    </group>
  );
}
