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

export interface Tower3DInput {
  /** Forma da seção */
  section: 'square' | 'triangular';
  /** Tipo de barras */
  barType: 'flat' | 'circular';
  /** Largura da base (m) */
  baseWidth: number;
  /** Altura total (m) */
  height: number;
  /** Número de tramos verticais (modulos) */
  panels: number;
  /** Índice de área exposta φ */
  phi: number;
  /** Ângulo de incidência do vento (graus) */
  alphaWind: 0 | 45 | 90;
  /** Força total estimada na torre (kN) */
  forceKN: number;
}

/**
 * Gera os vértices (nós) e barras de uma torre reticulada proceduralmente.
 *
 * Para torre quadrada: 4 montantes + diagonais em X + travessas horizontais.
 * Para torre triangular: 3 montantes + diagonais em cada face.
 */
interface TowerGeometry {
  nodes: THREE.Vector3[];
  members: { start: number; end: number; type: 'leg' | 'diagonal' | 'horizontal' }[];
}

function buildTowerGeometry(
  section: 'square' | 'triangular',
  panels: number,
  baseWidth: number,
  totalHeight: number,
): TowerGeometry {
  const halfW = baseWidth / 2;
  const panelH = totalHeight / panels;
  const nodes: THREE.Vector3[] = [];
  const members: TowerGeometry['members'] = [];

  // Base ring (nível 0)
  const baseCorners =
    section === 'square'
      ? [
          [-halfW, -halfW],
          [halfW, -halfW],
          [halfW, halfW],
          [-halfW, halfW],
        ]
      : [
          [0, -halfW],
          [halfW * Math.cos(Math.PI / 6), halfW * Math.sin(Math.PI / 6)],
          [-halfW * Math.cos(Math.PI / 6), halfW * Math.sin(Math.PI / 6)],
        ];

  baseCorners.forEach(([x, z]) => {
    nodes.push(new THREE.Vector3(x, 0, z));
  });
  const baseNodeCount = baseCorners.length;

  // Níveis superiores
  for (let p = 1; p <= panels; p++) {
    baseCorners.forEach(([x, z]) => {
      nodes.push(new THREE.Vector3(x, p * panelH, z));
    });
  }

  // Montantes (legs) — conectam cada canto em todos os níveis
  for (let corner = 0; corner < baseNodeCount; corner++) {
    for (let p = 0; p < panels; p++) {
      members.push({
        start: p * baseNodeCount + corner,
        end: (p + 1) * baseNodeCount + corner,
        type: 'leg',
      });
    }
  }

  // Travessas horizontais em cada nível
  for (let p = 0; p <= panels; p++) {
    for (let i = 0; i < baseNodeCount; i++) {
      members.push({
        start: p * baseNodeCount + i,
        end: p * baseNodeCount + ((i + 1) % baseNodeCount),
        type: 'horizontal',
      });
    }
  }

  // Diagonais em cada painel
  for (let p = 0; p < panels; p++) {
    for (let i = 0; i < baseNodeCount; i++) {
      members.push({
        start: p * baseNodeCount + i,
        end: (p + 1) * baseNodeCount + ((i + 1) % baseNodeCount),
        type: 'diagonal',
      });
      members.push({
        start: p * baseNodeCount + ((i + 1) % baseNodeCount),
        end: (p + 1) * baseNodeCount + i,
        type: 'diagonal',
      });
    }
  }

  return { nodes, members };
}

function pressureColor(phi: number, forceKN: number): THREE.Color {
  const intensity = Math.min(1, (phi * forceKN) / 30);
  const hue = 220 - intensity * 220;
  return new THREE.Color(`hsl(${hue}, ${60 + intensity * 30}%, ${50 - intensity * 10}%)`);
}

function TowerModel({
  section,
  barType,
  baseWidth,
  height,
  panels,
  phi,
  alphaWind,
  forceKN,
}: Tower3DInput) {
  const geometry = useMemo(
    () => buildTowerGeometry(section, panels, baseWidth, height),
    [section, panels, baseWidth, height],
  );

  const barRadius = barType === 'circular' ? 0.04 : 0.03;
  const barColor = pressureColor(phi, forceKN);

  // Direção do vetor de força
  const alphaRad = (alphaWind * Math.PI) / 180;
  const forceDir = useMemo(
    () => new THREE.Vector3(Math.cos(alphaRad), 0, Math.sin(alphaRad)),
    [alphaRad],
  );

  return (
    <group>
      {/* Solo */}
      <mesh position={[0, 0, 0]} rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
        <planeGeometry args={[baseWidth * 4, baseWidth * 4]} />
        <meshStandardMaterial color="#94a3b8" opacity={0.2} transparent />
      </mesh>

      {/* Nós (esferas pequenas) */}
      {geometry.nodes.map((node, idx) => (
        <mesh key={`node-${idx}`} position={node.toArray()} castShadow>
          <sphereGeometry args={[barRadius * 1.4, 8, 8]} />
          <meshStandardMaterial color="#475569" />
        </mesh>
      ))}

      {/* Barras */}
      {geometry.members.map((m, idx) => {
        const start = geometry.nodes[m.start];
        const end = geometry.nodes[m.end];
        const midpoint = new THREE.Vector3()
          .addVectors(start, end)
          .multiplyScalar(0.5);
        const length = start.distanceTo(end);
        const dir = new THREE.Vector3().subVectors(end, start).normalize();

        // Rotação para alinhar cilindro com direção start→end
        const quat = new THREE.Quaternion();
        quat.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
        const euler = new THREE.Euler().setFromQuaternion(quat);

        const color =
          m.type === 'leg'
            ? '#1e293b'
            : m.type === 'horizontal'
              ? '#64748b'
              : barColor;

        return (
          <mesh key={`bar-${idx}`} position={midpoint.toArray()} rotation={[euler.x, euler.y, euler.z]} castShadow>
            <cylinderGeometry args={[barRadius, barRadius, length, 6]} />
            <meshStandardMaterial color={color} />
          </mesh>
        );
      })}

      {/* Seta de Vento única atingindo o meio da torre */}
      <WindArrow
        target={[0, height / 2, 0]}
        direction={forceDir}
      />

      {/* Labels indicativos */}
      <mesh position={[baseWidth / 2 + 0.5, 0.5, 0]}>
        <boxGeometry args={[0.02, 0.02, 0.02]} />
        <meshStandardMaterial color="#fbbf24" />
      </mesh>
      <Text
        position={[0, height + 1.0, 0]}
        fontSize={0.5}
        color="#1e40af"
        anchorX="center"
        anchorY="bottom"
      >
        h={height}m | base={baseWidth}m | φ={phi.toFixed(2)}
      </Text>
    </group>
  );
}

export default function Tower3DViewer(input: Tower3DInput) {
  const { baseWidth, height } = input;
  const dist = Math.max(baseWidth * 3, height * 1.2);

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

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