import React, { Suspense, useState, useEffect } from 'react';
import { Canvas, useLoader } from '@react-three/fiber';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
import { OrbitControls, Stage, useProgress, Environment, ContactShadows } from '@react-three/drei';
import { Spin } from 'antd';
import JSZip from 'jszip';
import * as THREE from 'three';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error("3D Model Viewer Error:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div style={{ 
          display: 'flex', 
          alignItems: 'center', 
          justifyContent: 'center', 
          height: '100%', 
          color: '#888',
          padding: 20,
          textAlign: 'center',
          fontSize: '14px'
        }}>
          3D 模型加载失败
        </div>
      );
    }

    return this.props.children;
  }
}

const Model = ({ objPath, mtlPath, scale = 1 }) => {
  // If mtlPath is provided, load materials first
  const materials = mtlPath ? useLoader(MTLLoader, mtlPath) : null;
  
  const obj = useLoader(OBJLoader, objPath, (loader) => {
    if (materials) {
      materials.preload();
      loader.setMaterials(materials);
    }
  });

  const clone = obj.clone();
  return <primitive object={clone} scale={scale} />;
};

const LoadingOverlay = () => {
  const { progress, active } = useProgress();
  if (!active) return null;
  
  return (
    <div style={{ 
      position: 'absolute', 
      top: 0, 
      left: 0, 
      width: '100%', 
      height: '100%', 
      display: 'flex', 
      alignItems: 'center', 
      justifyContent: 'center',
      background: 'rgba(0,0,0,0.5)',
      zIndex: 10,
      pointerEvents: 'none'
    }}>
      <div style={{ textAlign: 'center' }}>
        <Spin size="large" />
        <div style={{ color: '#00b96b', marginTop: 10, fontWeight: 'bold' }}>
          {progress.toFixed(0)}% Loading
        </div>
      </div>
    </div>
  );
};

const ModelViewer = ({ objPath, mtlPath, scale = 1, autoRotate = true }) => {
  const [paths, setPaths] = useState(null);
  const [unzipping, setUnzipping] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isMounted = true;
    const blobUrls = [];

    const loadPaths = async () => {
      if (!objPath) return;

      // 如果是 zip 文件
      if (objPath.toLowerCase().endsWith('.zip')) {
        setUnzipping(true);
        setError(null);
        try {
          const response = await fetch(objPath);
          const arrayBuffer = await response.arrayBuffer();
          const zip = await JSZip.loadAsync(arrayBuffer);
          
          let extractedObj = null;
          let extractedMtl = null;
          const fileMap = {};

          // 1. 提取所有文件并创建 Blob URL 映射
          for (const [filename, file] of Object.entries(zip.files)) {
            if (file.dir) continue;
            
            const content = await file.async('blob');
            const url = URL.createObjectURL(content);
            blobUrls.push(url);
            
            // 记录文件名到 URL 的映射，用于后续材质引用图片等情况
            const baseName = filename.split('/').pop();
            fileMap[baseName] = url;

            if (filename.toLowerCase().endsWith('.obj')) {
              extractedObj = url;
            } else if (filename.toLowerCase().endsWith('.mtl')) {
              extractedMtl = url;
            }
          }

          if (isMounted) {
            if (extractedObj) {
              setPaths({ obj: extractedObj, mtl: extractedMtl });
            } else {
              setError('压缩包内未找到 .obj 模型文件');
            }
          }
        } catch (err) {
          console.error('Error unzipping model:', err);
          if (isMounted) setError('加载压缩包失败');
        } finally {
          if (isMounted) setUnzipping(false);
        }
      } else {
        // 普通路径
        setPaths({ obj: objPath, mtl: mtlPath });
      }
    };

    loadPaths();

    return () => {
      isMounted = false;
      // 清理 Blob URL 释放内存
      blobUrls.forEach(url => URL.revokeObjectURL(url));
    };
  }, [objPath, mtlPath]);

  if (unzipping) {
    return (
      <div style={{ 
        display: 'flex', 
        flexDirection: 'column', 
        alignItems: 'center', 
        justifyContent: 'center', 
        height: '100%', 
        background: 'rgba(0,0,0,0.1)' 
      }}>
        <Spin size="large" />
        <div style={{ color: '#00b96b', marginTop: 15, fontWeight: '500' }}>正在解压 3D 资源...</div>
      </div>
    );
  }

  if (error) {
    return (
      <div style={{ 
        display: 'flex', 
        alignItems: 'center', 
        justifyContent: 'center', 
        height: '100%', 
        color: '#ff4d4f',
        padding: 20,
        textAlign: 'center'
      }}>
        {error}
      </div>
    );
  }

  if (!paths) return null;

  return (
    <div style={{ position: 'relative', width: '100%', height: '100%' }}>
      <ErrorBoundary>
        <LoadingOverlay />
        <Canvas shadows dpr={[1, 2]} camera={{ fov: 45, position: [0, 0, 5] }} style={{ height: '100%', width: '100%' }}>
          <ambientLight intensity={0.7} />
          <pointLight position={[10, 10, 10]} intensity={1} />
          <spotLight position={[-10, 10, 10]} angle={0.15} penumbra={1} intensity={1} />
          
          <Suspense fallback={null}>
            <Stage environment="city" intensity={0.6} adjustCamera={true}>
              <Model objPath={paths.obj} mtlPath={paths.mtl} scale={scale} />
            </Stage>
            <Environment preset="city" />
            <ContactShadows position={[0, -0.8, 0]} opacity={0.4} scale={10} blur={2} far={0.8} />
          </Suspense>
          <OrbitControls autoRotate={autoRotate} makeDefault />
        </Canvas>
      </ErrorBoundary>
    </div>
  );
};

export default ModelViewer;
