'use client';

import { useRef, useMemo, Suspense } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import {
  OrbitControls,
  Grid,
  GizmoHelper,
  GizmoViewport,
  Environment,
  Stats,
  PerspectiveCamera,
} from '@react-three/drei';
import * as THREE from 'three';

import { usePreviewStore } from '@/stores/preview-store';
import { PreviewInstance, MATERIAL_PROPERTIES } from '@/lib/preview/types';

// Single instance mesh component
function InstanceMesh({ instance }: { instance: PreviewInstance }) {
  const meshRef = useRef<THREE.Mesh>(null);

  // Get material properties
  const matProps = MATERIAL_PROPERTIES[instance.material] || MATERIAL_PROPERTIES.Plastic;

  // Create geometry based on shape
  const geometry = useMemo(() => {
    switch (instance.shape) {
      case 'Ball':
        return new THREE.SphereGeometry(0.5, 32, 32);
      case 'Cylinder':
        return new THREE.CylinderGeometry(0.5, 0.5, 1, 32);
      case 'Wedge':
        // Create a wedge shape
        const shape = new THREE.Shape();
        shape.moveTo(0, 0);
        shape.lineTo(1, 0);
        shape.lineTo(0, 1);
        shape.closePath();
        const extrudeSettings = { depth: 1, bevelEnabled: false };
        return new THREE.ExtrudeGeometry(shape, extrudeSettings);
      case 'Block':
      default:
        return new THREE.BoxGeometry(1, 1, 1);
    }
  }, [instance.shape]);

  // Create material
  const material = useMemo(() => {
    const color = new THREE.Color(instance.color.r, instance.color.g, instance.color.b);

    if (matProps.emissive) {
      return new THREE.MeshStandardMaterial({
        color,
        emissive: color,
        emissiveIntensity: 0.5,
        roughness: matProps.roughness,
        metalness: matProps.metalness,
        transparent: instance.transparency > 0,
        opacity: 1 - instance.transparency,
      });
    }

    return new THREE.MeshStandardMaterial({
      color,
      roughness: matProps.roughness,
      metalness: matProps.metalness,
      transparent: instance.transparency > 0,
      opacity: 1 - instance.transparency,
    });
  }, [instance.color, instance.transparency, instance.material, matProps]);

  if (!instance.visible) return null;

  return (
    <mesh
      ref={meshRef}
      position={[instance.position.x, instance.position.y, instance.position.z]}
      rotation={[instance.rotation.x, instance.rotation.y, instance.rotation.z]}
      scale={[instance.scale.x, instance.scale.y, instance.scale.z]}
      geometry={geometry}
      material={material}
      castShadow
      receiveShadow
    />
  );
}

// Scene content
function SceneContent() {
  const { scene, settings } = usePreviewStore();

  return (
    <>
      {/* Lighting */}
      {scene.lights.map((light) => {
        const color = new THREE.Color(light.color.r, light.color.g, light.color.b);

        switch (light.type) {
          case 'directional':
            return (
              <directionalLight
                key={light.id}
                position={[light.position.x, light.position.y, light.position.z]}
                color={color}
                intensity={light.intensity}
                castShadow={settings.shadowsEnabled && light.castShadow}
                shadow-mapSize={[2048, 2048]}
                shadow-camera-far={200}
                shadow-camera-left={-50}
                shadow-camera-right={50}
                shadow-camera-top={50}
                shadow-camera-bottom={-50}
              />
            );
          case 'point':
            return (
              <pointLight
                key={light.id}
                position={[light.position.x, light.position.y, light.position.z]}
                color={color}
                intensity={light.intensity}
                distance={light.range || 10}
                castShadow={settings.shadowsEnabled && light.castShadow}
              />
            );
          case 'spot':
            return (
              <spotLight
                key={light.id}
                position={[light.position.x, light.position.y, light.position.z]}
                color={color}
                intensity={light.intensity}
                distance={light.range || 20}
                angle={((light.angle || 45) * Math.PI) / 180}
                castShadow={settings.shadowsEnabled && light.castShadow}
              />
            );
          case 'ambient':
            return (
              <ambientLight key={light.id} color={color} intensity={light.intensity} />
            );
          default:
            return null;
        }
      })}

      {/* Instances */}
      {scene.instances.map((instance) => (
        <InstanceMesh key={instance.id} instance={instance} />
      ))}

      {/* Grid */}
      {settings.showGrid && (
        <Grid
          args={[100, 100]}
          position={[0, 0, 0]}
          cellSize={2}
          cellThickness={0.5}
          cellColor="#4a4a6a"
          sectionSize={10}
          sectionThickness={1}
          sectionColor="#6a6a8a"
          fadeDistance={100}
          fadeStrength={1}
          followCamera={false}
          infiniteGrid={true}
        />
      )}

      {/* Axes Helper */}
      {settings.showAxes && (
        <GizmoHelper alignment="bottom-right" margin={[80, 80]}>
          <GizmoViewport
            axisColors={['#ff4444', '#44ff44', '#4444ff']}
            labelColor="white"
          />
        </GizmoHelper>
      )}
    </>
  );
}

// Camera controller
function CameraController() {
  const { scene, settings } = usePreviewStore();
  const controlsRef = useRef<any>(null);

  useFrame(() => {
    if (controlsRef.current && settings.autoRotate) {
      controlsRef.current.autoRotate = true;
      controlsRef.current.autoRotateSpeed = 1;
    } else if (controlsRef.current) {
      controlsRef.current.autoRotate = false;
    }
  });

  return (
    <>
      <PerspectiveCamera
        makeDefault
        position={[scene.camera.position.x, scene.camera.position.y, scene.camera.position.z]}
        fov={scene.camera.fov}
        near={scene.camera.near}
        far={scene.camera.far}
      />
      <OrbitControls
        ref={controlsRef}
        target={[scene.camera.target.x, scene.camera.target.y, scene.camera.target.z]}
        enableDamping
        dampingFactor={0.05}
        minDistance={1}
        maxDistance={500}
      />
    </>
  );
}

// Loading fallback
function LoadingFallback() {
  return (
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="#888888" wireframe />
    </mesh>
  );
}

export default function PreviewViewport() {
  const { settings } = usePreviewStore();

  return (
    <div className="w-full h-full relative">
      <Canvas
        shadows={settings.shadowsEnabled}
        gl={{
          antialias: settings.antialias,
          toneMapping: THREE.ACESFilmicToneMapping,
          toneMappingExposure: 1,
        }}
        style={{ background: settings.backgroundColor }}
      >
        <Suspense fallback={<LoadingFallback />}>
          <CameraController />
          <SceneContent />
          <Environment preset="city" background={false} />
        </Suspense>
        {settings.showStats && <Stats />}
      </Canvas>
    </div>
  );
}
