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

export interface Cylinder3DInput {
  diameter: number;
  height: number;
  /** Cpe profile ao longo da circunferência (0° a 180°) */
  cpeProfile: { angle: number; cpe: number }[];
  cpi: number;
}

function cylinderColor(cpe: number, cpi: number): THREE.Color {
  const p = cpe - cpi;
  const intensity = Math.min(1, Math.abs(p) / 1.2);
  if (p > 0) {
    return new THREE.Color(`hsl(${215 - intensity * 10}, ${70 + intensity * 25}%, ${Math.max(35, 65 - intensity * 25)}%)`);
  }
  return new THREE.Color(`hsl(0, ${70 + intensity * 25}%, ${Math.max(40, 65 - intensity * 20)}%)`);
}

function CylinderModel({ diameter, height, cpeProfile, cpi }: Cylinder3DInput) {
  const segments = 64;
  const radius = diameter / 2;

  // Espelha o cpeProfile para cobrir de 0° a 360°
  const fullCpeProfile = useMemo(() => {
    if (cpeProfile.length === 0) return [];
    const arr = [...cpeProfile];
    const step = cpeProfile.length > 1 ? cpeProfile[1].angle - cpeProfile[0].angle : 10;
    
    // Espelha de 180° a 360°
    for (let angle = 180 + step; angle < 360; angle += step) {
      const mirroredAngle = 360 - angle;
      const closest = cpeProfile.find(p => Math.abs(p.angle - mirroredAngle) < 0.1) || cpeProfile[cpeProfile.length - 1];
      arr.push({ angle, cpe: closest.cpe });
    }
    // Fecha o ciclo em 360° (igual a 0°)
    arr.push({ angle: 360, cpe: cpeProfile[0].cpe });
    return arr;
  }, [cpeProfile]);

  // Cria faces individuais com cor independente por ângulo
  const faces = useMemo(() => {
    const arr: { angle: number; cpe: number; color: THREE.Color }[] = [];
    for (let i = 0; i < fullCpeProfile.length - 1; i++) {
      const a = fullCpeProfile[i];
      const b = fullCpeProfile[i + 1];
      const angleMid = (a.angle + b.angle) / 2;
      const cpeMid = (a.cpe + b.cpe) / 2;
      arr.push({ angle: angleMid, cpe: cpeMid, color: cylinderColor(cpeMid, cpi) });
    }
    return arr;
  }, [fullCpeProfile, cpi]);

  return (
    <group>
      {/* Paredes Verticais do Cilindro */}
      {faces.map((face, idx) => {
        if (fullCpeProfile.length <= idx + 1) return null;
        const stepAngle = fullCpeProfile[1].angle - fullCpeProfile[0].angle;
        const a0 = (face.angle - stepAngle / 2) * Math.PI / 180;
        const a1 = (face.angle + stepAngle / 2) * Math.PI / 180;
        const x0 = Math.cos(a0) * radius;
        const z0 = Math.sin(a0) * radius;
        const x1 = Math.cos(a1) * radius;
        const z1 = Math.sin(a1) * radius;

        // Normais dos vértices
        const nx0 = Math.cos(a0);
        const nz0 = Math.sin(a0);
        const nx1 = Math.cos(a1);
        const nz1 = Math.sin(a1);

        // Array com os 6 vértices para formar dois triângulos (um quad completo)
        const vertices = new Float32Array([
          x0, 0, z0,
          x1, 0, z1,
          x1, height, z1,

          x0, 0, z0,
          x1, height, z1,
          x0, height, z0,
        ]);

        const normals = new Float32Array([
          nx0, 0, nz0,
          nx1, 0, nz1,
          nx1, 0, nz1,

          nx0, 0, nz0,
          nx1, 0, nz1,
          nx0, 0, nz0,
        ]);

        return (
          <mesh key={idx} castShadow receiveShadow>
            <bufferGeometry>
              <bufferAttribute
                attach="attributes-position"
                args={[vertices, 3]}
              />
              <bufferAttribute
                attach="attributes-normal"
                args={[normals, 3]}
              />
            </bufferGeometry>
            <meshStandardMaterial color={face.color} opacity={0.9} transparent roughness={0.4} side={THREE.DoubleSide} />
          </mesh>
        );
      })}

      {/* Tampa superior sólida */}
      <mesh position={[0, height, 0]} rotation={[-Math.PI / 2, 0, 0]} castShadow receiveShadow>
        <circleGeometry args={[radius, segments]} />
        <meshStandardMaterial color={cylinderColor(cpeProfile[cpeProfile.length - 1].cpe, cpi)} opacity={0.8} transparent side={THREE.DoubleSide} roughness={0.4} />
      </mesh>

      {/* Anéis de detalhe (bordas do cilindro) */}
      <mesh position={[0, height + 0.01, 0]} rotation={[-Math.PI / 2, 0, 0]}>
        <ringGeometry args={[radius - 0.03, radius + 0.03, segments]} />
        <meshStandardMaterial color="#2d3748" roughness={0.5} />
      </mesh>
      <mesh position={[0, 0.01, 0]} rotation={[-Math.PI / 2, 0, 0]}>
        <ringGeometry args={[radius - 0.03, radius + 0.03, segments]} />
        <meshStandardMaterial color="#2d3748" roughness={0.5} />
      </mesh>

      {/* Seta indicativa de direção do vento */}
      <group position={[-radius - 2.5, height / 2, 0]} rotation={[0, 0, -Math.PI / 2]}>
        <mesh castShadow>
          <coneGeometry args={[0.3, 0.8, 16]} />
          <meshStandardMaterial color="#3b82f6" roughness={0.3} />
        </mesh>
        <mesh position={[0, -0.6, 0]} castShadow>
          <cylinderGeometry args={[0.1, 0.1, 1.2, 16]} />
          <meshStandardMaterial color="#3b82f6" roughness={0.3} />
        </mesh>
        <Text
          position={[0, -1.5, 0]}
          rotation={[Math.PI / 2, 0, 0]}
          fontSize={0.4}
          color="#3b82f6"
          anchorX="center"
          anchorY="middle"
        >
          Vento
        </Text>
      </group>

      {/* Texto de Informação */}
      <Text
        position={[0, height + 0.8, 0]}
        fontSize={Math.max(0.3, Math.min(0.6, diameter / 10))}
        color="#1a202c"
        anchorX="center"
        anchorY="bottom"
      >
        Alt = {height}m | Diâm = {diameter}m
      </Text>
    </group>
  );
}

export default function Cylinder3DViewer({ diameter, height, cpeProfile, cpi }: Cylinder3DInput) {
  const fallback = (
    <FallbackDiagram
      type="cylinder"
      props={{ diameter, height, cpeProfile, cpi }}
    />
  );

  const maxDim = Math.max(diameter, height);

  return (
    <SceneCanvas
      shadows
      gl={{ preserveDrawingBuffer: true, antialias: true }}
      camera={{ position: [diameter * 1.5, height * 1.2, diameter * 1.5], fov: 40 }}
      fallback={fallback}
    >
      <ambientLight intensity={0.7} />
      <directionalLight
        position={[diameter * 1.5, height * 2.5, diameter * 1.5]}
        intensity={1.2}
        castShadow
        shadow-mapSize-width={1024}
        shadow-mapSize-height={1024}
        shadow-camera-far={maxDim * 10}
        shadow-camera-left={-maxDim}
        shadow-camera-right={maxDim}
        shadow-camera-top={maxDim}
        shadow-camera-bottom={-maxDim}
      />
      <CylinderModel diameter={diameter} height={height} cpeProfile={cpeProfile} cpi={cpi} />
      <Grid infiniteGrid fadeDistance={maxDim * 5} sectionColor="#94a3b8" cellColor="#cbd5e1" position={[0, -0.01, 0]} />
      <OrbitControls makeDefault minPolarAngle={0} maxPolarAngle={Math.PI / 2 - 0.05} />
      <Environment preset="city" />
    </SceneCanvas>
  );
}