/**
 * 3D Brace Viewer Component
 * Uses Three.js to display GLB brace models with markers
 * 
 * Based on EXPERIMENT_6's brace-transform-playground-v2
 */
import { useEffect, useRef, useState, useCallback } from 'react';

// Three.js is loaded dynamically to avoid SSR issues
let THREE: any = null;
let GLTFLoader: any = null;
let OrbitControls: any = null;

type MarkerInfo = {
  name: string;
  position: [number, number, number];
  color: string;
};

type BraceViewerProps = {
  glbUrl: string | null;
  width?: number;
  height?: number;
  showMarkers?: boolean;
  onMarkersLoaded?: (markers: MarkerInfo[]) => void;
  deformationParams?: {
    thoracicPadDepth?: number;
    lumbarPadDepth?: number;
    trunkShift?: number;
  };
};

export default function BraceViewer({
  glbUrl,
  width = 600,
  height = 500,
  showMarkers = true,
  onMarkersLoaded,
  deformationParams,
}: BraceViewerProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const rendererRef = useRef<any>(null);
  const sceneRef = useRef<any>(null);
  const cameraRef = useRef<any>(null);
  const controlsRef = useRef<any>(null);
  const braceMeshRef = useRef<any>(null);
  const animationFrameRef = useRef<number>(0);
  
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [threeLoaded, setThreeLoaded] = useState(false);

  // Load Three.js dynamically
  useEffect(() => {
    const loadThree = async () => {
      try {
        const threeModule = await import('three');
        THREE = threeModule;
        
        const { GLTFLoader: Loader } = await import('three/examples/jsm/loaders/GLTFLoader.js');
        GLTFLoader = Loader;
        
        const { OrbitControls: Controls } = await import('three/examples/jsm/controls/OrbitControls.js');
        OrbitControls = Controls;
        
        setThreeLoaded(true);
      } catch (e) {
        console.error('Failed to load Three.js:', e);
        setError('Failed to load 3D viewer');
      }
    };
    
    loadThree();
    
    return () => {
      // Cleanup on unmount
      if (animationFrameRef.current) {
        cancelAnimationFrame(animationFrameRef.current);
      }
      if (rendererRef.current) {
        rendererRef.current.dispose();
      }
    };
  }, []);

  // Initialize scene
  const initScene = useCallback(() => {
    if (!THREE || !containerRef.current) return;
    
    // Scene
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x1a1a1a);
    sceneRef.current = scene;
    
    // Camera
    const camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 10000);
    camera.position.set(300, 200, 400);
    cameraRef.current = camera;
    
    // Renderer
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(width, height);
    renderer.setPixelRatio(window.devicePixelRatio);
    containerRef.current.appendChild(renderer.domElement);
    rendererRef.current = renderer;
    
    // Controls
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.target.set(0, 100, 0);
    controls.update();
    controlsRef.current = controls;
    
    // Lighting
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(ambientLight);
    
    const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.4);
    scene.add(hemisphereLight);
    
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(200, 300, 200);
    scene.add(directionalLight);
    
    // Grid helper (optional)
    const gridHelper = new THREE.GridHelper(500, 20, 0x444444, 0x333333);
    scene.add(gridHelper);
    
    // Animation loop
    const animate = () => {
      animationFrameRef.current = requestAnimationFrame(animate);
      controls.update();
      renderer.render(scene, camera);
    };
    animate();
  }, [width, height]);

  // Initialize scene when Three.js is loaded
  useEffect(() => {
    if (threeLoaded && containerRef.current && !rendererRef.current) {
      initScene();
    }
  }, [threeLoaded, initScene]);

  // Load GLB when URL changes
  useEffect(() => {
    if (!threeLoaded || !glbUrl || !sceneRef.current) return;
    
    setLoading(true);
    setError(null);
    
    const loader = new GLTFLoader();
    
    loader.load(
      glbUrl,
      (gltf: any) => {
        // Clear previous mesh
        if (braceMeshRef.current) {
          sceneRef.current.remove(braceMeshRef.current);
          braceMeshRef.current = null;
        }
        
        // Process loaded model
        const scene = gltf.scene;
        const markers: MarkerInfo[] = [];
        let mainMesh: any = null;
        
        // Find main mesh and markers
        scene.traverse((child: any) => {
          if (child.isMesh) {
            // Check if it's a marker
            if (child.name.startsWith('LM_')) {
              markers.push({
                name: child.name,
                position: child.position.toArray() as [number, number, number],
                color: getMarkerColor(child.name),
              });
              
              // Style marker for visibility
              if (showMarkers) {
                child.material = new THREE.MeshBasicMaterial({
                  color: getMarkerColor(child.name),
                  depthTest: false,
                  transparent: true,
                  opacity: 0.8,
                });
                child.renderOrder = 999;
              } else {
                child.visible = false;
              }
            } else {
              // Main brace mesh
              if (!mainMesh || child.geometry.attributes.position.count > mainMesh.geometry.attributes.position.count) {
                mainMesh = child;
              }
              
              // Apply standard material
              child.material = new THREE.MeshStandardMaterial({
                color: 0xcccccc,
                metalness: 0.2,
                roughness: 0.5,
                side: THREE.DoubleSide,
              });
            }
          }
        });
        
        // Add to scene
        sceneRef.current.add(scene);
        braceMeshRef.current = scene;
        
        // Center camera on mesh
        if (mainMesh) {
          const box = new THREE.Box3().setFromObject(scene);
          const center = box.getCenter(new THREE.Vector3());
          const size = box.getSize(new THREE.Vector3());
          
          controlsRef.current.target.copy(center);
          cameraRef.current.position.set(
            center.x + size.x,
            center.y + size.y * 0.5,
            center.z + size.z
          );
          controlsRef.current.update();
        }
        
        // Notify about markers
        if (onMarkersLoaded && markers.length > 0) {
          onMarkersLoaded(markers);
        }
        
        setLoading(false);
      },
      undefined,
      (err: any) => {
        console.error('Failed to load GLB:', err);
        setError('Failed to load 3D model');
        setLoading(false);
      }
    );
  }, [threeLoaded, glbUrl, showMarkers, onMarkersLoaded]);

  // Handle resize
  useEffect(() => {
    if (rendererRef.current && cameraRef.current) {
      rendererRef.current.setSize(width, height);
      cameraRef.current.aspect = width / height;
      cameraRef.current.updateProjectionMatrix();
    }
  }, [width, height]);

  // Loading state
  if (!threeLoaded) {
    return (
      <div className="brace-viewer-loading" style={{ width, height }}>
        <div className="spinner"></div>
        <p>Loading 3D viewer...</p>
      </div>
    );
  }

  return (
    <div className="brace-viewer-container" style={{ width, height }}>
      <div 
        ref={containerRef} 
        className="brace-viewer-canvas"
        style={{ width: '100%', height: '100%' }}
      />
      
      {loading && (
        <div className="brace-viewer-overlay">
          <div className="spinner"></div>
          <p>Loading model...</p>
        </div>
      )}
      
      {error && (
        <div className="brace-viewer-overlay error">
          <p>{error}</p>
        </div>
      )}
      
      {!glbUrl && !loading && (
        <div className="brace-viewer-overlay placeholder">
          <p>No 3D model loaded</p>
        </div>
      )}
    </div>
  );
}

// Helper function to get marker color based on name
function getMarkerColor(name: string): string {
  if (name.includes('PELVIS')) return '#ff0000';  // Red
  if (name.includes('TOP')) return '#00ff00';     // Green
  if (name.includes('PAD_TH')) return '#ff00ff';  // Magenta (thoracic pad)
  if (name.includes('BAY_TH')) return '#00ffff';  // Cyan (thoracic bay)
  if (name.includes('PAD_LUM')) return '#ffff00'; // Yellow (lumbar pad)
  if (name.includes('BAY_LUM')) return '#ff8800'; // Orange (lumbar bay)
  if (name.includes('ANCHOR')) return '#8800ff'; // Purple (anchors)
  return '#ffffff'; // White (default)
}
