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

export interface Vault3DInput {
  span: number;
  length: number;
  rise: number;
  cpi: number;
  cpeProfile: Record<string, number>;
  cpeParallel?: Record<string, number>;
  viewDirection?: 'perpendicular' | 'parallel';
}

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

function VaultModel({ span, length, rise, cpi, cpeProfile, cpeParallel, viewDirection = 'perpendicular' }: Vault3DInput) {
  const theme = useCanvasTheme();
  const isDark = theme === 'dark';
  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]);

  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]);

  const renderPerpendicular = () => {
    const zones = [];
    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}`;
      zones.push({ cpe: cpeProfile[key] ?? -0.5, startIdx, endIdx, label: `${z + 1}` });
    }

    return zones.map((zone, idx) => {
      const color = vaultColor(zone.cpe, cpi, isDark);
      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);
      }
      
      const midIdx = Math.floor((zone.startIdx + zone.endIdx) / 2);
      const midPt = points[midIdx];
      
      return (
        <group key={idx}>
          <mesh 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>
          <Text
            position={[midPt.x, midPt.y + 0.5, length / 2]}
            fontSize={Math.max(0.48, span / 18.75)}
            color={isDark ? "#f8fafc" : "#0f172a"}
            anchorX="center"
            anchorY="middle"
          >
            {zone.label}
          </Text>
        </group>
      );
    });
  };

  const renderParallel = () => {
    const zones = ['A', 'B', 'C', 'D'];
    const zStep = length / 4;
    
    return zones.map((label, idx) => {
      const zStart = idx * zStep;
      const zEnd = (idx + 1) * zStep;
      const cpe = cpeParallel?.[label] ?? -0.5;
      const color = vaultColor(cpe, cpi, isDark);
      
      const verts: number[] = [];
      for (let i = 0; i <= segments; i++) {
        verts.push(points[i].x, points[i].y, zStart);
        verts.push(points[i].x, points[i].y, zEnd);
      }
      const indices: number[] = [];
      for (let i = 0; i < segments; 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 (
        <group key={idx}>
          <mesh 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>
          <Text
            position={[0, rise + 0.5, (zStart + zEnd) / 2]}
            fontSize={Math.max(0.48, span / 18.75)}
            color={isDark ? "#f8fafc" : "#0f172a"}
            anchorX="center"
            anchorY="middle"
            rotation={[-Math.PI / 2, 0, 0]}
          >
            {label}
          </Text>
        </group>
      );
    });
  };

  return (
    <group>
      {viewDirection === 'perpendicular' ? renderPerpendicular() : renderParallel()}

      {/* Tímpano Traseiro (Z = 0) */}
      <mesh position={[0, 0, 0]} castShadow receiveShadow>
        <shapeGeometry args={[archShape]} />
        <meshStandardMaterial color={isDark ? "#334155" : "#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={isDark ? "#334155" : "#cbd5e1"} opacity={0.7} transparent side={THREE.DoubleSide} roughness={0.5} />
      </mesh>

      {/* Rótulo de dimensões */}
      <Text
        position={[0, rise + 1.5, length / 2]}
        fontSize={Math.max(0.3, Math.min(0.6, span / 20))}
        color={isDark ? "#cbd5e1" : "#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, cpeParallel, viewDirection = 'perpendicular' }: Vault3DInput) {
  const theme = useCanvasTheme();
  const isDark = theme === 'dark';

  const fallback = (
    <FallbackDiagram
      type="vault"
      props={{ span, length, rise, cpi, cpeProfile }}
    />
  );

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

  return (
    <SceneCanvas moduleId="abobada"
      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} cpeParallel={cpeParallel} viewDirection={viewDirection} />
      <Grid 
        infiniteGrid 
        fadeDistance={maxDimension * 5} 
        sectionColor={isDark ? "#475569" : "#94a3b8"} 
        cellColor={isDark ? "#1e293b" : "#cbd5e1"} 
        position={[0, -0.01, 0]} 
      />
      <OrbitControls makeDefault minPolarAngle={0} maxPolarAngle={Math.PI / 2 - 0.05} />
      <Environment preset="city" />
    </SceneCanvas>
  );
}