import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { OrbitControls, Grid, Environment, Text } from '@react-three/drei';
import * as THREE from 'three';
import SceneCanvas from '../SceneCanvas';
import FallbackDiagram from '../FallbackDiagram';

export interface Dynamics3DInput {
  /** Altura da estrutura (m) */
  height: number;
  /** Frequência natural f₁ (Hz) */
  freq: number;
  /** Velocidade do vento (m/s) */
  windSpeed: number;
  /** Número de Scruton */
  scruton: number;
  /** Tipo de seção */
  sectionShape: string;
  /** Tamanho da seção (m) */
  sectionSize: number;
  /** Mostrar rua de vórtices */
  showVortexStreet: boolean;
  /** Mostrar modo de oscilação */
  showModeShape: boolean;
}

const SCALE = 0.15;

function OscillatingBuilding({
  height,
  freq,
  scruton,
  sectionShape,
  sectionSize,
  showModeShape,
}: {
  height: number;
  freq: number;
  scruton: number;
  sectionShape: string;
  sectionSize: number;
  showModeShape: boolean;
}) {
  const groupRef = useRef<THREE.Group>(null);
  const timeRef = useRef(0);

  const hScaled = height * SCALE;
  const wScaled = sectionSize * SCALE;

  useFrame((_, delta) => {
    timeRef.current += delta;
    if (groupRef.current && showModeShape) {
      const amplitude = Math.min(0.3, 0.1 / Math.max(scruton, 0.1));
      const displacement = amplitude * Math.sin(2 * Math.PI * freq * timeRef.current);
      groupRef.current.position.x = displacement;
      groupRef.current.rotation.z = displacement * 0.02;
    }
  });

  const sectionColor = '#3b82f6';

  return (
    <group ref={groupRef}>
      {sectionShape === 'circle' ? (
        <mesh position={[0, hScaled / 2, 0]} castShadow>
          <cylinderGeometry args={[wScaled / 2, wScaled / 2, hScaled, 16]} />
          <meshStandardMaterial color={sectionColor} transparent opacity={0.7} />
        </mesh>
      ) : (
        <mesh position={[0, hScaled / 2, 0]} castShadow>
          <boxGeometry args={[wScaled, hScaled, wScaled]} />
          <meshStandardMaterial color={sectionColor} transparent opacity={0.7} />
        </mesh>
      )}

      {showModeShape && (
        <group>
          {[0, 0.25, 0.5, 0.75, 1].map((frac, i, arr) => {
            if (i === arr.length - 1) return null;
            const y0 = frac * hScaled;
            const y1 = arr[i + 1] * hScaled;
            const amp = 0.03;
            return (
              <mesh key={`mode-${i}`} position={[amp * Math.sin(frac * Math.PI), (y0 + y1) / 2, 0]}>
                <cylinderGeometry args={[0.01, 0.01, y1 - y0, 4]} />
                <meshStandardMaterial color="#ef4444" />
              </mesh>
            );
          })}
        </group>
      )}

      <mesh position={[-wScaled - 0.3, hScaled / 2, 0]}>
        <boxGeometry args={[0.02, hScaled, 0.02]} />
        <meshStandardMaterial color="#94a3b8" />
      </mesh>
    </group>
  );
}

function VortexStreet({
  windSpeed,
  height,
  sectionSize,
}: {
  windSpeed: number;
  height: number;
  sectionSize: number;
}) {
  const hScaled = height * SCALE;
  const wScaled = sectionSize * SCALE;

  return (
    <group>
      {Array.from({ length: 12 }).map((_, i) => {
        const x = wScaled / 2 + 0.5 + i * 0.5;
        const sign = i % 2 === 0 ? 1 : -1;
        const y = hScaled / 2 + sign * wScaled * 0.4 * (1 + i * 0.05);
        const opacity = Math.max(0.1, 0.8 - i * 0.06);
        return (
          <mesh key={`vortex-${i}`} position={[x, y, 0]}>
            <sphereGeometry args={[0.06, 8, 8]} />
            <meshStandardMaterial color="#a855f7" transparent opacity={opacity} />
          </mesh>
        );
      })}

      <mesh position={[windSpeed * SCALE * 0.5 + 1.5, hScaled / 2, 0]} rotation={[0, 0, -Math.PI / 2]}>
        <cylinderGeometry args={[0.03, 0.03, 2, 8]} />
        <meshStandardMaterial color="#22c55e" />
      </mesh>
      <mesh position={[windSpeed * SCALE * 0.5 + 2.5, hScaled / 2, 0]} rotation={[0, 0, -Math.PI / 2]}>
        <coneGeometry args={[0.08, 0.2, 8]} />
        <meshStandardMaterial color="#22c55e" />
      </mesh>
    </group>
  );
}

function DynamicsModel(props: Dynamics3DInput) {
  return (
    <group>
      <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.01, 0]} receiveShadow>
        <planeGeometry args={[20, 20]} />
        <meshStandardMaterial color="#94a3b8" transparent opacity={0.15} />
      </mesh>

      <OscillatingBuilding
        height={props.height}
        freq={props.freq}
        scruton={props.scruton}
        sectionShape={props.sectionShape}
        sectionSize={props.sectionSize}
        showModeShape={props.showModeShape}
      />

      {props.showVortexStreet && (
        <VortexStreet
          windSpeed={props.windSpeed}
          height={props.height}
          sectionSize={props.sectionSize}
        />
      )}
      <Text
        position={[0, props.height * SCALE + 0.8, 0]}
        fontSize={0.5}
        color="#1e40af"
        anchorX="center"
        anchorY="bottom"
      >
        h={props.height}m | f₁={props.freq}Hz | Sc={props.scruton.toFixed(1)}
      </Text>
    </group>
  );
}

export default function Dynamics3DViewer(props: Dynamics3DInput) {
  const cameraDistance = Math.max(props.height * SCALE * 2, 6);

  const fallback = (
    <FallbackDiagram
      type="dynamics"
      props={props}
    />
  );

  return (
    <SceneCanvas
      frameloop="always"
      shadows
      gl={{ preserveDrawingBuffer: true, antialias: true }}
      camera={{ position: [cameraDistance, cameraDistance * 0.5, cameraDistance], fov: 45 }}
      fallback={fallback}
    >
      <ambientLight intensity={0.6} />
      <directionalLight
        position={[10, 15, 10]}
        intensity={1.2}
        castShadow
        shadow-mapSize-width={1024}
        shadow-mapSize-height={1024}
      />
      <DynamicsModel {...props} />
      <Grid infiniteGrid fadeDistance={50} sectionColor="#94a3b8" cellColor="#cbd5e1" position={[0, -0.01, 0]} />
      <OrbitControls makeDefault minPolarAngle={0} maxPolarAngle={Math.PI / 2 - 0.05} />
      <Environment preset="city" />
    </SceneCanvas>
  );
}
