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 Vault3DInput {
  span: number;
  length: number;
  rise: number;
  cpi: number;
  cpeProfile: Record<string, number>;
}

function vaultColor(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 VaultModel({ span, length, rise, cpi, cpeProfile }: Vault3DInput) {
  const segments = 64;
  const points = useMemo(() => {
    const pts: THREE.Vector3[] = [];
    for (let i = 0; i <= segments; i++) {
      const t = i / segments;
      const x = -span / 2 + t * span;
      const y = rise * Math.sin(t * Math.PI);
      pts.push(new THREE.Vector3(x, y, 0));
    }
    return pts;
  }, [span, rise, segments]);

  // Divide em zonas (1, 2, 3, 4, 5, 6)
  const zones = useMemo(() => {
    const arr: { cpe: number; startIdx: number; endIdx: number }[] = [];
    const zoneSize = segments / 6;
    for (let z = 0; z < 6; z++) {
      const startIdx = Math.floor(z * zoneSize);
      const endIdx = Math.floor((z + 1) * zoneSize);
      const key = `zone${z + 1}`;
      arr.push({ cpe: cpeProfile[key] ?? -0.5, startIdx, endIdx });
    }
    return arr;
  }, [cpeProfile, segments]);

  // Shape para fechar os tímpanos (paredes frontais/traseiras em arco)
  const archShape = useMemo(() => {
    const s = new THREE.Shape();
    s.moveTo(-span / 2, 0);
    for (let i = 0; i <= segments; i++) {
      const t = i / segments;
      const x = -span / 2 + t * span;
      const y = rise * Math.sin(t * Math.PI);
      s.lineTo(x, y);
    }
    s.lineTo(span / 2, 0);
    s.closePath();
    return s;
  }, [span, rise, segments]);

  return (
    <group>
      {/* Casca da Abóbada */}
      {zones.map((zone, idx) => {
        const color = vaultColor(zone.cpe, cpi);
        const verts: number[] = [];
        for (let i = zone.startIdx; i <= zone.endIdx; i++) {
          verts.push(points[i].x, points[i].y, points[i].z);
          verts.push(points[i].x, points[i].y, length);
        }
        const indices: number[] = [];
        for (let i = 0; i < (zone.endIdx - zone.startIdx); i++) {
          const a = i * 2;
          const b = i * 2 + 1;
          const c = i * 2 + 2;
          const d = i * 2 + 3;
          indices.push(a, b, c, b, d, c);
        }
        return (
          <mesh key={idx} castShadow receiveShadow>
            <bufferGeometry>
              <bufferAttribute attach="attributes-position" args={[new Float32Array(verts), 3]} />
              <bufferAttribute attach="index" args={[new Uint16Array(indices), 1]} />
            </bufferGeometry>
            <meshStandardMaterial color={color} opacity={0.92} transparent side={THREE.DoubleSide} roughness={0.4} />
          </mesh>
        );
      })}

      {/* Tímpano Traseiro (Z = 0) */}
      <mesh position={[0, 0, 0]} castShadow receiveShadow>
        <shapeGeometry args={[archShape]} />
        <meshStandardMaterial color="#cbd5e1" opacity={0.7} transparent side={THREE.DoubleSide} roughness={0.5} />
      </mesh>

      {/* Tímpano Frontal (Z = length) */}
      <mesh position={[0, 0, length]} castShadow receiveShadow>
        <shapeGeometry args={[archShape]} />
        <meshStandardMaterial color="#cbd5e1" opacity={0.7} transparent side={THREE.DoubleSide} roughness={0.5} />
      </mesh>

      {/* Rótulo de dimensões */}
      <Text
        position={[0, rise + 0.6, length / 2]}
        fontSize={Math.max(0.3, Math.min(0.6, span / 20))}
        color="#1a202c"
        anchorX="center"
        anchorY="bottom"
      >
        Vão = {span}m | Compr = {length}m | Flecha = {rise}m
      </Text>
    </group>
  );
}

export default function Vault3DViewer({ span, length, rise, cpi, cpeProfile }: Vault3DInput) {
  const fallback = (
    <FallbackDiagram
      type="vault"
      props={{ span, length, rise, cpi, cpeProfile }}
    />
  );

  const maxDimension = Math.max(span, length, rise);

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