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 Dome3DInput {
  diameter: number;
  rise: number;
  wallHeight: number;
  cpi: number;
  cpeBarlavento: number;
  cpeTopo: number;
  cpeLateral: number;
}

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

function DomeModel({ diameter, rise, wallHeight, cpi, cpeBarlavento, cpeTopo, cpeLateral }: Dome3DInput) {
  const radius = diameter / 2;
  const segments = 64;

  // Cúpula (casca esférica) — gerada por segmentos de 0° a 360° para fechar o domo
  const domeGeoms = useMemo(() => {
    const arr: { startTheta: number; endTheta: number; color: THREE.Color }[] = [];
    // Divide a circunferência completa (360°) em 6 zonas (simétricas)
    // 0° a 60°: Barlavento
    // 60° a 120°: Topo
    // 120° a 180°: Lateral
    // 180° a 240°: Lateral (espelhado)
    // 240° a 300°: Topo (espelhado)
    // 300° a 360°: Barlavento (espelhado)
    const zones = [
      { fromDeg: 0, toDeg: 60, cpe: cpeBarlavento },
      { fromDeg: 60, toDeg: 120, cpe: cpeTopo },
      { fromDeg: 120, toDeg: 180, cpe: cpeLateral },
      { fromDeg: 180, toDeg: 240, cpe: cpeLateral },
      { fromDeg: 240, toDeg: 300, cpe: cpeTopo },
      { fromDeg: 300, toDeg: 360, cpe: cpeBarlavento },
    ];
    for (const z of zones) {
      arr.push({
        startTheta: (z.fromDeg * Math.PI) / 180,
        endTheta: (z.toDeg * Math.PI) / 180,
        color: domeColor(z.cpe, cpi),
      });
    }
    return arr;
  }, [cpeBarlavento, cpeTopo, cpeLateral, cpi]);

  // Raio da esfera da calota esférica baseada na flecha (rise) e raio da base (radius)
  const rSphere = useMemo(() => {
    return (radius * radius + rise * rise) / (2 * rise);
  }, [radius, rise]);

  return (
    <group>
      {/* Parede cilíndrica inferior */}
      <mesh position={[0, wallHeight / 2, 0]} castShadow receiveShadow>
        <cylinderGeometry args={[radius, radius, wallHeight, segments, 1, false]} />
        <meshStandardMaterial color="#cbd5e1" opacity={0.8} transparent roughness={0.4} />
      </mesh>
      
      {/* Detalhes de anéis metálicos nas bordas */}
      <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>
      <mesh position={[0, wallHeight, 0]} rotation={[-Math.PI / 2, 0, 0]}>
        <ringGeometry args={[radius - 0.03, radius + 0.03, segments]} />
        <meshStandardMaterial color="#2d3748" roughness={0.5} />
      </mesh>

      {/* Cúpula de cobertura (Spherical Cap) segmentada */}
      {domeGeoms.map((zone, idx) => {
        const phiSteps = 16;
        const segments2 = 16;
        const vertices: number[] = [];
        const normals: number[] = [];
        const indices: number[] = [];

        const phiStart = zone.startTheta;
        const phiRange = zone.endTheta - zone.startTheta;

        for (let i = 0; i <= phiSteps; i++) {
          const phi = phiStart + (i / phiSteps) * phiRange;
          for (let j = 0; j <= segments2; j++) {
            const t = j / segments2;
            const y = t * rise;
            // Equação da esfera da calota
            const yLocal = (rSphere - rise) + y;
            const r = Math.sqrt(Math.max(0, rSphere * rSphere - yLocal * yLocal));
            
            const x = r * Math.cos(phi);
            const z = r * Math.sin(phi);
            
            vertices.push(x, wallHeight + y, z);
            
            // Normal analítica perfeita da esfera
            normals.push(x / rSphere, yLocal / rSphere, z / rSphere);
          }
        }

        for (let i = 0; i < phiSteps; i++) {
          for (let j = 0; j < segments2; j++) {
            const a = i * (segments2 + 1) + j;
            const b = (i + 1) * (segments2 + 1) + j;
            const c = (i + 1) * (segments2 + 1) + (j + 1);
            const d = i * (segments2 + 1) + (j + 1);
            indices.push(a, b, c, a, c, d);
          }
        }

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

      {/* Seta indicativa de direção do vento */}
      <group position={[radius + 2.5, wallHeight / 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 informativo */}
      <Text
        position={[0, wallHeight + rise + 0.8, 0]}
        fontSize={Math.max(0.3, Math.min(0.6, diameter / 12))}
        color="#1a202c"
        anchorX="center"
        anchorY="bottom"
      >
        Diâm = {diameter}m | Flecha = {rise}m
      </Text>
    </group>
  );
}

export default function Dome3DViewer(props: Dome3DInput) {
  const fallback = (
    <FallbackDiagram
      type="dome"
      props={props}
    />
  );

  const maxDim = Math.max(props.diameter, props.wallHeight + props.rise);

  return (
    <SceneCanvas
      shadows
      gl={{ preserveDrawingBuffer: true, antialias: true }}
      camera={{ position: [props.diameter * 1.5, (props.wallHeight + props.rise) * 1.5, props.diameter * 1.5], fov: 40 }}
      fallback={fallback}
    >
      <ambientLight intensity={0.7} />
      <directionalLight
        position={[props.diameter * 1.5, (props.wallHeight + props.rise) * 2.5, props.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}
      />
      <DomeModel {...props} />
      <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>
  );
}