import { useRef, useMemo, useEffect } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import { useCanvasTheme } from '../../lib/theme';

export interface CylinderAirflowSystemProps {
  diameter: number;
  height: number;
}

export function CylinderAirflowSystem({ diameter, height }: CylinderAirflowSystemProps) {
  const isDark = useCanvasTheme() === 'dark';
  const count = 450;
  const meshRef = useRef<THREE.InstancedMesh>(null);
  const R = diameter / 2;

  const particles = useMemo(() => {
    const temp = [];
    const spanX = Math.max(15, R * 5);
    const spanZ = Math.max(10, R * 3.5);
    for (let i = 0; i < count; i++) {
      temp.push({
        position: new THREE.Vector3(
          (Math.random() - 0.5) * spanX * 2,
          Math.random() * (height * 1.3),
          (Math.random() - 0.5) * spanZ * 2
        ),
        baseSpeed: 0.12 + Math.random() * 0.08,
        wobbleSpeed: Math.random() * 0.05,
        wobbleOffset: Math.random() * Math.PI * 2,
        currentCpe: 0,
      });
    }
    return temp;
  }, [count, R, height]);

  const dummy = useMemo(() => new THREE.Object3D(), []);
  const colorObj = useMemo(() => new THREE.Color(), []);

  useEffect(() => {
    if (meshRef.current) {
      for (let i = 0; i < count; i++) {
        meshRef.current.setColorAt(i, new THREE.Color('#ffffff'));
      }
      if (meshRef.current.instanceColor) {
        meshRef.current.instanceColor.needsUpdate = true;
      }
    }
  }, [count]);

  useFrame((state) => {
    if (!meshRef.current) return;
    const time = state.clock.elapsedTime;
    const spanX = Math.max(15, R * 5);
    const spanZ = Math.max(10, R * 3.5);

    particles.forEach((p, i) => {
      let deflectX = 1.0;
      let deflectY = 0;
      let deflectZ = 0;

      const px = p.position.x;
      const py = p.position.y;
      const pz = p.position.z;

      const r = Math.sqrt(px * px + pz * pz);
      const safeR = Math.max(R + 0.3, r);

      // Proteção para não entrar no cilindro
      if (r < R + 0.25 && py <= height) {
        const angle = Math.atan2(pz, px);
        p.position.x = Math.cos(angle) * (R + 0.25);
        p.position.z = Math.sin(angle) * (R + 0.25);
      }

      // Cálculo aerodinâmico (escoamento potencial ao redor de cilindro)
      if (py <= height * 1.05 && r < R * 3.0) {
        const r2 = safeR * safeR;
        const R2 = R * R;
        // Velocidades de escoamento potencial em 2D ao redor do cilindro
        deflectX = 1 - (R2 * (px * px - pz * pz)) / (r2 * r2);
        deflectZ = -(2 * R2 * px * pz) / (r2 * r2);

        // Esteira turbulenta na região à jusante (+X)
        if (px > 0 && Math.abs(pz) < R * 1.3) {
          deflectZ += Math.sin(time * 5 + px * 0.8 + p.wobbleOffset) * 0.35;
          deflectX = Math.max(0.4, deflectX);
        }
      }

      // Determina coeficiente para cor da partícula
      if (py <= height && r < R * 2.2) {
        if (px < -R * 0.3 && Math.abs(pz) < R * 0.8) {
          p.currentCpe = 0.8; // Barlavento (pressão positiva)
        } else if (Math.abs(px) <= R * 0.6 && r < R * 1.5) {
          p.currentCpe = -1.2; // Laterais (forte sucção)
        } else if (px > R * 0.3 && Math.abs(pz) < R * 1.2) {
          p.currentCpe = 0.5; // Esteira (agora positivo para ficar vermelho)
        } else {
          p.currentCpe = 0;
        }
      } else {
        p.currentCpe = 0;
      }

      const moveVec = new THREE.Vector3(deflectX, deflectY, deflectZ).normalize();
      const currentSpeed = p.baseSpeed * Math.max(0.3, Math.min(1.5, deflectX));

      p.position.addScaledVector(moveVec, currentSpeed);

      // Reposição quando sai do volume
      if (p.position.x > spanX) {
        p.position.x = -spanX;
        p.position.y = Math.random() * (height * 1.3);
        p.position.z = (Math.random() - 0.5) * spanZ * 2;
      }

      dummy.position.copy(p.position);
      dummy.lookAt(p.position.clone().add(moveVec));
      dummy.rotateX(Math.PI / 2);
      dummy.scale.set(1, 1 + currentSpeed * 6, 1);
      dummy.updateMatrix();
      meshRef.current!.setMatrixAt(i, dummy.matrix);

      if (p.currentCpe > 0) {
        colorObj.set(isDark ? '#f87171' : '#ef4444'); // Vermelho (Turbulento/Pressão)
      } else if (p.currentCpe < 0) {
        const intensity = Math.min(1, Math.abs(p.currentCpe));
        colorObj.set(isDark ? '#c084fc' : '#a855f7').lerp(new THREE.Color(isDark ? '#7e22ce' : '#6b21a8'), intensity); // Roxo (Acelerado/Sucção)
      } else {
        colorObj.set(isDark ? '#60a5fa' : '#3b82f6'); // Azul (Corrente livre)
      }
      meshRef.current!.setColorAt(i, colorObj);
    });

    meshRef.current.instanceMatrix.needsUpdate = true;
    if (meshRef.current.instanceColor) {
      meshRef.current.instanceColor.needsUpdate = true;
    }
  });

  return (
    <instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
      <cylinderGeometry args={[0.01, 0.01, 1.5, 4]} />
      <meshBasicMaterial
        color="#ffffff"
        transparent
        opacity={isDark ? 0.6 : 0.8}
        blending={isDark ? THREE.AdditiveBlending : THREE.NormalBlending}
        depthWrite={false}
      />
    </instancedMesh>
  );
}
