import React, { Suspense, useEffect, useMemo, useRef, useState, useCallback } from "react";
import { Canvas, useThree, useFrame } from "@react-three/fiber";
import { OrbitControls, Html, useGLTF, Bounds, useFBX, useAnimations, useProgress } from "@react-three/drei";
import * as THREE from "three";

/**
 * --- 1. 模型加载模块 (Model Loading) ---
 * 负责不同格式模型的加载 (GLTF, FBX) 以及动画播放
 */

// 自定义 Hook: 手动 Fetch 获取真实进度
function useFetchLoader(url) {
  const [state, setState] = useState({
    progress: 0,
    loaded: 0,
    total: 0,
    blobUrl: null,
    error: null,
    loading: false
  });

  useEffect(() => {
    if (!url) return;

    const controller = new AbortController();
    let objectUrl = null;

    const load = async () => {
      setState(s => ({ ...s, loading: true, progress: 0, loaded: 0, total: 0, error: null }));
      
      try {
        const response = await fetch(url, { signal: controller.signal });
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);

        const contentLength = response.headers.get('content-length');
        const total = contentLength ? parseInt(contentLength, 10) : 0;
        
        const reader = response.body.getReader();
        let receivedLength = 0;
        const chunks = [];
        
        while(true) {
          const { done, value } = await reader.read();
          if (done) break;
          
          chunks.push(value);
          receivedLength += value.length;
          
          setState(prev => ({
            ...prev,
            loaded: receivedLength,
            total: total,
            progress: total ? (receivedLength / total) * 100 : 0
          }));
        }
        
        const blob = new Blob(chunks);
        objectUrl = URL.createObjectURL(blob);
        
        setState(prev => ({
          ...prev,
          blobUrl: objectUrl,
          loading: false,
          progress: 100
        }));
        
      } catch (e) {
        if (e.name !== 'AbortError') {
          console.error("Fetch Loader error:", e);
          setState(prev => ({ ...prev, error: e.message, loading: false }));
        }
      }
    };
    
    load();
    
    return () => {
      controller.abort();
      if (objectUrl) URL.revokeObjectURL(objectUrl);
    };
  }, [url]);
  
  return state;
}

function Loader({ customState }) {
  // 优先使用传入的 customState，否则回退到 useProgress (用于纹理加载等后续过程)
  const { active, progress: dreiProgress } = useProgress();
  
  // 合并状态：如果是下载阶段(customState.loading)，用 customState；否则用 drei
  const isLoading = customState?.loading || active;
  if (!isLoading) return null;

  const loaded = customState?.loading ? customState.loaded : 0;
  const total = customState?.loading ? customState.total : 0;
  const progress = customState?.loading ? customState.progress : (dreiProgress || 0);
  
  // 格式化文件大小
  const formatBytes = (bytes) => {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  };

  // 判断是否无法计算总大小
  const isIndeterminate = customState?.loading && total === 0 && loaded > 0;
  
  const progressText = isIndeterminate 
    ? `已下载 ${formatBytes(loaded)}` 
    : `${progress.toFixed(0)}%`;

  const statusText = customState?.loading 
    ? (total > 0 ? `下载中 ${formatBytes(loaded)} / ${formatBytes(total)}` : '下载中...')
    : '解析模型中...';

  return (
    <Html center style={{ zIndex: 9999, pointerEvents: 'none' }}>
      <div 
        style={{ 
          color: "#333", 
          fontSize: 14, 
          textAlign: "center",
          background: "rgba(255, 255, 255, 0.9)",
          padding: "15px 25px",
          borderRadius: "8px",
          boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
          minWidth: "200px",
          backdropFilter: "blur(5px)"
        }}
      >
        <div style={{ marginBottom: 8, fontWeight: 500 }}>{statusText}</div>
        <div
          style={{
            width: "100%",
            height: 6,
            background: "#eee",
            borderRadius: 3,
            overflow: "hidden",
            position: "relative"
          }}
        >
          <div
            style={{
              width: isIndeterminate ? "100%" : `${progress}%`,
              height: "100%",
              background: "#666",
              transition: isIndeterminate ? "none" : "width 0.2s ease-out",
              position: "absolute",
              left: 0,
              top: 0,
              backgroundImage: isIndeterminate 
                ? "linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)" 
                : "none",
              backgroundSize: "40px 40px",
              animation: isIndeterminate ? "progress-bar-stripes 1s linear infinite" : "none"
            }}
          />
        </div>
        <div style={{ marginTop: 8, fontSize: 12, color: "#666", display: "flex", justifyContent: "space-between" }}>
          <span>{progressText}</span>
          {total > 0 && <span>{formatBytes(total)}</span>}
        </div>
      </div>
      <style>{`
        @keyframes progress-bar-stripes {
          from { background-position: 40px 0; }
          to { background-position: 0 0; }
        }
      `}</style>
    </Html>
  );
}

// GLTF 模型组件
function GLTFModel({ url, ...props }) {
  const { scene, animations } = useGLTF(url, true);
  const ref = useRef();
  const { actions, names } = useAnimations(animations, ref);

  // 自动播放第一个动画
  useEffect(() => {
    if (actions && names.length > 0) {
      actions[names[0]].reset().fadeIn(0.5).play();
    }
  }, [actions, names]);

  return <primitive ref={ref} object={scene} {...props} />;
}

// FBX 模型组件
function FBXModel({ url, ...props }) {
  const obj = useFBX(url);
  const ref = useRef();
  const { actions, names } = useAnimations(obj.animations || [], ref);

  // 自动播放第一个动画
  useEffect(() => {
    if (actions && names.length > 0) {
      actions[names[0]].reset().fadeIn(0.5).play();
    }
  }, [actions, names]);

  return <primitive ref={ref} object={obj} {...props} />;
}

// 预留 USDZ 支持 (iOS ARQuickLook 格式)
function USDZModel({ url }) {
  // 注意：useGLTF 默认不支持 .usdz，需配合特定 loader 或其他库
  // 这里仅作占位，方便后续扩展
  return null;
}

// 统一模型加载器
// 根据 URL 后缀分发到对应的加载组件
function ModelLoader({ url, fileType }) {
  const kind = useMemo(() => {
    // 如果显式传递了 fileType，则直接使用
    if (fileType) return fileType;
    
    // 否则尝试从 URL 推断 (Blob URL 通常无法推断，所以 fileType 很重要)
    const u = (url || "").toLowerCase().split("?")[0].split("#")[0];
    if (u.endsWith(".fbx")) return "fbx";
    if (u.endsWith(".usdz")) return "usdz";
    return "gltf";
  }, [url, fileType]);

  switch (kind) {
    case "fbx":
      return <FBXModel url={url} />;
    case "usdz":
      return <USDZModel url={url} />;
    default:
      return <GLTFModel url={url} />;
  }
}

/**
 * --- 2. 交互逻辑模块 (Interaction Logic) ---
 * 包含：自动适应检测、相机控制、交互锁定
 */

// FitWatcher: 负责检测 Bounds 组件的自适应动画是否完成
// 原理：监听相机位置和目标点的变化，当连续多帧保持静止时，认为自适应完成
function FitWatcher({ controlsRef, onFitReady }) {
  const { camera } = useThree();
  // 记录上一帧的状态，用于对比差异
  const lastState = useRef({ pos: new THREE.Vector3(), target: new THREE.Vector3() });
  const stableFrames = useRef(0);
  const isFitted = useRef(false);

  // 当 URL 变化时重置检测状态，重新开始监听
  useEffect(() => {
    isFitted.current = false;
    stableFrames.current = 0;
  }, [onFitReady]);

  // useFrame 会在每一帧渲染时执行
  useFrame(() => {
    if (!controlsRef.current || isFitted.current) return;

    const controls = controlsRef.current;
    const currentPos = camera.position;
    const currentTarget = controls.target;

    const distDiff = currentPos.distanceTo(lastState.current.pos);
    const targetDiff = currentTarget.distanceTo(lastState.current.target);

    // 只有当相机几乎静止时（位移 < 0.001）才开始计数
    if (distDiff < 0.001 && targetDiff < 0.001) {
      stableFrames.current++;
    } else {
      stableFrames.current = 0;
    }

    lastState.current.pos.copy(currentPos);
    lastState.current.target.copy(currentTarget);

    // 连续 10 帧稳定（约 160ms @ 60fps）认为 fit 动画彻底结束
    if (stableFrames.current > 10) {
      isFitted.current = true;
      const distance = currentPos.distanceTo(currentTarget);

      console.log("Fit stable, distance:", distance);
      // 回调通知父组件：相机已就位，可以解锁交互并记录初始位置
      onFitReady({
        position: currentPos.clone(),
        target: currentTarget.clone(),
        distance,
      });
    }
  });

  return null;
}

// CameraController: 封装 OrbitControls 并处理缩放限制
function CameraController({
  controlsRef,
  zoomMin,
  zoomMax,
  baseDistance,
  autoRotateSpeed,
  enabled = true,
  onStart,
  onEnd,
}) {
  // 动态计算 maxDistance 和 minDistance
  useEffect(() => {
    const controls = controlsRef.current;
    if (!controls || baseDistance == null) return;

    // zoomMin (default 1) -> 最小放大倍数 -> 意味着相机拉得最远 -> 对应 maxDistance
    // zoomMax (default 4) -> 最大放大倍数 -> 意味着相机拉得最近 -> 对应 minDistance
    // 公式：实际距离 = 基础距离(baseDistance) / 缩放倍率(zoom)

    // 防止除以 0
    const minZ = Math.max(0.001, zoomMin || 1);
    const maxZ = Math.max(minZ, zoomMax || 4);

    controls.maxDistance = baseDistance / minZ;
    controls.minDistance = baseDistance / maxZ;
  }, [baseDistance, zoomMin, zoomMax, controlsRef]);

  return (
    <OrbitControls
      ref={controlsRef}
      enabled={enabled} // 在 fit 完成前禁用交互，防止用户打断自动飞入动画
      enableDamping
      dampingFactor={0.08}
      rotateSpeed={0.8}
      zoomSpeed={1.0}
      enableZoom
      enablePan
      panSpeed={0.8}
      screenSpacePanning
      touches={{
        ONE: THREE.TOUCH.ROTATE,
        TWO: THREE.TOUCH.DOLLY_PAN,
      }}
      makeDefault
      autoRotate={!!autoRotateSpeed}
      autoRotateSpeed={autoRotateSpeed}
      onStart={onStart}
      onEnd={onEnd}
    />
  );
}

/**
 * --- 3. 场景容器 (Scene Container) ---
 * 组装模型、灯光、交互，并管理全局状态
 */

function SceneContent({ url, zoomMin, zoomMax, fileType }) {
  const controlsRef = useRef();
  const { camera, gl } = useThree();

  // baseDistance: 模型自适应后的基础观察距离，用于计算缩放限制
  const [baseDistance, setBaseDistance] = useState(null);

  // 自动旋转配置
  const [autoRotateConfig, setAutoRotateConfig] = useState({
    active: false, // 是否开启了自动旋转模式（总开关）
    speed: 1.0, // 旋转速度
    delay: 5000, // 无操作后的恢复延迟 (ms)
    isInteracting: false, // 用户是否正在交互
  });

  // isReady: 标记是否完成初始飞入动画，完成后才解锁交互
  const [isReady, setIsReady] = useState(false);

  // 记录初始 fit 后的完美状态（位置 + 目标点），用于双击复位
  const initialState = useRef(null);
  const timerRef = useRef(null);

  // 当 FitWatcher 告诉我们相机稳定时调用
  const handleFitReady = useCallback((state) => {
    initialState.current = {
      position: state.position,
      target: state.target,
    };
    setBaseDistance(state.distance);
    setIsReady(true); // 解锁交互
  }, []);

  // 平滑复位函数：使用插值动画让相机回到初始状态
  // 支持 onComplete 回调，用于在复位完成后执行操作（如开始自动旋转）
  const resetToInitial = useCallback(
    (onComplete) => {
      if (!controlsRef.current || !initialState.current) return;

      const controls = controlsRef.current;
      const startPos = camera.position.clone();
      const startTarget = controls.target.clone();
      const endPos = initialState.current.position;
      const endTarget = initialState.current.target;

      const duration = 800; // 动画时长 ms
      const startTime = performance.now();

      const animate = (time) => {
        const elapsed = time - startTime;
        const t = Math.min(elapsed / duration, 1);
        const ease = 1 - Math.pow(1 - t, 3); // cubic ease-out 缓动效果

        camera.position.lerpVectors(startPos, endPos, ease);
        controls.target.lerpVectors(startTarget, endTarget, ease);
        controls.update();

        if (t < 1) {
          requestAnimationFrame(animate);
        } else {
          if (typeof onComplete === "function") {
            onComplete();
          }
        }
      };
      requestAnimationFrame(animate);
    },
    [camera]
  );

  // 处理用户交互开始
  const handleInteractionStart = useCallback(() => {
    setAutoRotateConfig((prev) => ({ ...prev, isInteracting: true }));
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      timerRef.current = null;
    }
  }, []);

  // 处理用户交互结束
  const handleInteractionEnd = useCallback(() => {
    setAutoRotateConfig((prev) => ({ ...prev, isInteracting: false }));

    // 如果开启了自动旋转模式，则启动定时器恢复旋转
    if (autoRotateConfig.active) {
      setAutoRotateConfig((prev) => ({ ...prev, isWaiting: true }));
      
      timerRef.current = setTimeout(() => {
        // 核心修改：等待结束后，先执行复位，复位完成后再恢复旋转
        console.log("无操作超时，开始复位并恢复旋转...");
        resetToInitial(() => {
           // 复位动画完成的回调
           setAutoRotateConfig((prev) => ({ ...prev, isWaiting: false }));
        });
      }, autoRotateConfig.delay);
    }
  }, [autoRotateConfig.active, autoRotateConfig.delay, resetToInitial]);

  // 计算最终传给 Controls 的旋转速度
  // 只有当：总开关开启(active) 且 没有在交互(isInteracting) 且 没有在等待延迟(isWaiting) 时，才有速度
  const effectiveSpeed = autoRotateConfig.active && !autoRotateConfig.isInteracting && !autoRotateConfig.isWaiting ? autoRotateConfig.speed : 0;

  // 通用相机位移动画函数
  const animateCamera = useCallback((targetPos, onComplete) => {
    if (!controlsRef.current) return;
    const controls = controlsRef.current;
    
    const startPos = camera.position.clone();
    const startTime = performance.now();
    const duration = 300;

    const animate = (time) => {
      const t = Math.min((time - startTime) / duration, 1);
      const ease = 1 - Math.pow(1 - t, 3); // cubic ease-out
      
      camera.position.lerpVectors(startPos, targetPos, ease);
      controls.update();
      
      if (t < 1) {
        requestAnimationFrame(animate);
      } else {
        if (typeof onComplete === "function") {
          onComplete();
        }
      }
    };
    requestAnimationFrame(animate);
  }, [camera]);

  // 计算新的相机位置（不改变方向，只改变距离）
  const calculateZoomPos = useCallback((factor, isZoomIn) => {
    if (!controlsRef.current || !baseDistance) return null;
    const controls = controlsRef.current;
    
    const currentDist = camera.position.distanceTo(controls.target);
    // 放大是除以倍数（距离变小），缩小是乘以倍数（距离变大）
    const targetDist = isZoomIn ? currentDist / factor : currentDist * factor;

    // 检查限制
    if (isZoomIn && targetDist < controls.minDistance) {
      console.warn("已达到最大放大倍数");
      return null;
    }
    if (!isZoomIn && targetDist > controls.maxDistance) {
       console.warn("已达到最小缩小倍数");
       // 允许缩放到 maxDistance，但不超过
    }
    const finalDist = Math.max(controls.minDistance, Math.min(targetDist, controls.maxDistance));

    const direction = new THREE.Vector3().subVectors(camera.position, controls.target).normalize();
    return controls.target.clone().add(direction.multiplyScalar(finalDist));
  }, [camera, baseDistance]);

  // 暴露全局 API 给外部使用 (window.sceneFc)
  useEffect(() => {
    window.sceneFc = {
      resetView: () => {
        // 手动重置时，如果当前正在自动旋转，是否应该关闭自动旋转？
        // 通常手动重置意味着用户想回到初始状态，可能希望停止自动旋转。
        // 这里我们假设手动重置会关闭自动旋转，除非用户再次调用 setAutoRotate
        setAutoRotateConfig((prev) => ({ ...prev, active: false }));
        resetToInitial();
        console.log("已调用重置方法！");
      },
      setAutoRotate: (speed = 1.0, delay = 5000) => {
        const s = Math.max(0.1, Math.min(8, Number(speed) || 1));
        const d = Math.max(0, Number(delay) || 5000);

        console.log(`设置自动旋转: 速度=${s}, 延迟=${d}ms`);

        // 1. 先关闭当前的旋转（如果正在转）
        setAutoRotateConfig((prev) => ({ ...prev, active: false }));

        // 2. 调用重置
        resetToInitial(() => {
          // 3. 重置完成后，开启自动旋转
          setAutoRotateConfig({
            active: true,
            speed: s,
            delay: d,
            isInteracting: false,
            isWaiting: false,
          });
        });
      },
      stopAutoRotate: () => {
        console.log("停止自动旋转");
        setAutoRotateConfig((prev) => ({ ...prev, active: false }));
      },
      zoomIn: (factor = 1.2) => {
        const f = Math.max(1.01, Number(factor) || 1.2);
        
        // 执行缩放动作的封装
        const doZoom = (onDone) => {
           const newPos = calculateZoomPos(f, true); // true = zoomIn
           if (newPos) {
             animateCamera(newPos, () => {
               // 关键修改：缩放完成后，更新 initialState，这样后续复位就会回到这个新位置
               if (initialState.current) {
                 initialState.current.position.copy(newPos);
                 // target 通常不变，但为了保险也同步一下当前 target
                 if (controlsRef.current) {
                   initialState.current.target.copy(controlsRef.current.target);
                 }
               }
               if (onDone) onDone();
             });
           } else if (onDone) {
             onDone(); 
           }
        };

        if (autoRotateConfig.active) {
          // 流程：暂停 -> 复位 -> 缩放 -> 等待(handleInteractionEnd)
          handleInteractionStart(); // 1. 暂停
          resetToInitial(() => {    // 2. 复位到(旧)初始位置
            doZoom(() => {          // 3. 缩放并更新初始位置
              handleInteractionEnd(); // 4. 进入等待恢复流程 (恢复后旋转将基于新位置)
            });
          });
        } else {
          doZoom(); // 直接缩放
        }
      },
      zoomOut: (factor = 1.2) => {
        const f = Math.max(1.01, Number(factor) || 1.2);
        
        const doZoom = (onDone) => {
           const newPos = calculateZoomPos(f, false); // false = zoomOut
           if (newPos) {
             animateCamera(newPos, () => {
               // 关键修改：更新 initialState
               if (initialState.current) {
                 initialState.current.position.copy(newPos);
                 if (controlsRef.current) {
                   initialState.current.target.copy(controlsRef.current.target);
                 }
               }
               if (onDone) onDone();
             });
           } else if (onDone) {
             onDone();
           }
        };

        if (autoRotateConfig.active) {
          handleInteractionStart();
          resetToInitial(() => {
            doZoom(() => {
              handleInteractionEnd();
            });
          });
        } else {
          doZoom();
        }
      }
    };
    return () => {
      // 组件卸载时清理全局对象
      if (window.sceneFc) {
        delete window.sceneFc;
      }
    };
  }, [resetToInitial, baseDistance, camera, autoRotateConfig.active, handleInteractionStart, handleInteractionEnd, animateCamera, calculateZoomPos]);

  // 清理定时器
  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, []);

  // 双击复位监听 (Native DOM Event)
  useEffect(() => {
    const dom = gl.domElement;
    const handleDblClick = (e) => {
      e.preventDefault();
      resetToInitial();
    };
    dom.addEventListener("dblclick", handleDblClick);
    return () => dom.removeEventListener("dblclick", handleDblClick);
  }, [gl, resetToInitial]);

  return (
    <>
      {/* Bounds: 自动计算模型包围盒并调整相机视角 */}
      <Bounds fit clip observe margin={1.5}>
        <ModelLoader url={url} fileType={fileType} />
      </Bounds>

      <CameraController
        controlsRef={controlsRef}
        zoomMin={zoomMin}
        zoomMax={zoomMax}
        baseDistance={baseDistance}
        autoRotateSpeed={effectiveSpeed}
        enabled={isReady}
        onStart={handleInteractionStart}
        onEnd={handleInteractionEnd}
      />

      {/* 不渲染任何 UI，仅负责逻辑检测 */}
      <FitWatcher controlsRef={controlsRef} onFitReady={handleFitReady} />
    </>
  );
}

export default function Scene({ url, zoomMin, zoomMax }) {
  // 使用自定义 Hook 加载文件
  const fetchState = useFetchLoader(url);
  
  // 推断文件类型，传递给 ModelLoader
  const fileType = useMemo(() => {
    if (!url) return null;
    const u = url.toLowerCase().split("?")[0].split("#")[0];
    if (u.endsWith(".fbx")) return "fbx";
    if (u.endsWith(".usdz")) return "usdz";
    return "gltf";
  }, [url]);

  return (
    <>
      <ambientLight intensity={0.8} />
      <directionalLight position={[5, 5, 5]} intensity={1.0} />
      {url ? (
        <>
          {fetchState.blobUrl && (
            <Suspense fallback={null}>
              <SceneContent url={fetchState.blobUrl} zoomMin={zoomMin} zoomMax={zoomMax} fileType={fileType} />
            </Suspense>
          )}
          <Loader customState={fetchState} />
        </>
      ) : (
        <Html center style={{ color: "#222", fontSize: 14 }}>
          请在地址栏提供 ?src=GLB地址
        </Html>
      )}
    </>
  );
}
