import React, { useRef, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';


import type { ServerData, ServerIconConfig, RackConfig, ServerIconConfigs,DeviceStatusInfo } from './api.ts';
import { queryFns } from './api.ts';

interface UseServerHoverProps {
  scene: THREE.Scene;
  camera: THREE.Camera;
  containerRef: React.RefObject<HTMLDivElement>;
  tooltipRef: React.RefObject<HTMLDivElement>;
}

// 合并服务器基本信息和状态信息
interface ServerStatus extends ServerData, DeviceStatusInfo {}



// 颜色常量定义
const COLORS = {
  // 背景色(调亮为 #002952)
  BACKGROUND: 0x002952,
  
  // 地板颜色(相应调亮)
  FLOOR: 0x1D5491,        // 调亮地板颜色
  FLOOR_GRID: 0x2E66A3,   // 相应调亮网格线条
  
  // 机柜颜色
  RACK: {
    FRAME: 0x2E5483,      // 机柜框架颜色(调亮)
    FRONT: 0x2E5483,      // 机柜前面板
    SIDE: 0x274D70,       // 机柜侧面板(稍暗)
  },
  
  // 服务器颜色
  SERVER: {
    DEFAULT: 0x2E4D75,    // 服务器默认颜色(调亮)
    FRONT: 0x355882,      // 服务器前面板(调亮)
    STATUS: {
      ONLINE: 0x00FF00,   // 在线状态指示灯(绿色)
      WARNING: 0xFFFF00,  // 警告状态指示灯(黄色)
      OFFLINE: 0xFF0000   // 离线状态指示灯(红色)
    },
    HOVER: {
      COLOR: 0x00DDFF,    // 悬停发光颜色(青色)
      INTENSITY: 0.05      // 悬停发光强度
    }
  },
  
  // 灯光颜色
  LIGHTS: {
    AMBIENT: 0xCCE0FF,    // 环境光(偏蓝色冷光)
    DIRECT: 0xFFFFFF,     // 直射光(白光)
    SPOT: 0x00DDFF,       // 聚光灯(青色)
  }
} as const; 

// UI样式常量
const UI_STYLES = {
  TOOLTIP: {
    BACKGROUND: '#001529',
    BORDER: '#00dff9',
    BORDER_INNER: '#15243A',
    SHADOW: '0 0 10px rgba(0,223,249,0.3)',
    TEXT: '#ffffff',
    PADDING: '12px 16px',
    BORDER_RADIUS: '4px',
    FONT_SIZE: '14px'
  }
} as const; 

// 定义1U的高度(米)
const U_HEIGHT = 0.04445; // 1U = 44.45mm = 0.04445m


function useServerHover({ scene, camera, containerRef, tooltipRef }: UseServerHoverProps) {
  const HOVER_COLOR = new THREE.Color(COLORS.SERVER.HOVER.COLOR);
  const HOVER_INTENSITY = COLORS.SERVER.HOVER.INTENSITY;
  let INTERSECTED: THREE.Mesh | null = null;
  const raycaster = new THREE.Raycaster();
  const mouse = new THREE.Vector2();

  const setMaterialEmissive = (materials: THREE.Material | THREE.Material[], color: THREE.Color, intensity: number) => {
    if (Array.isArray(materials)) {
      materials.forEach(material => {
        if (material instanceof THREE.MeshPhongMaterial) {
          material.emissive.copy(color);
          material.emissiveIntensity = intensity;
          material.needsUpdate = true;
        }
      });
    } else if (materials instanceof THREE.MeshPhongMaterial) {
      materials.emissive.copy(color);
      materials.emissiveIntensity = intensity;
      materials.needsUpdate = true;
    }
  };

  const resetMaterialEmissive = (materials: THREE.Material | THREE.Material[]) => {
    if (Array.isArray(materials)) {
      materials.forEach(material => {
        if (material instanceof THREE.MeshPhongMaterial) {
          material.emissive.setHex(0x000000);
          material.emissiveIntensity = 0.2;
          material.needsUpdate = true;
        }
      });
    } else if (materials instanceof THREE.MeshPhongMaterial) {
      materials.emissive.setHex(0x000000);
      materials.emissiveIntensity = 0.2;
      materials.needsUpdate = true;
    }
  };

  const handleMouseMove = (event: MouseEvent) => {
    const rect = containerRef.current?.getBoundingClientRect();
    if (!rect) return;
    
    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);

    if (intersects.length > 0) {
      const found = intersects.find(item => 
        item.object instanceof THREE.Mesh && 
        item.object.userData.type === 'server'
      );

      if (found) {
        const serverMesh = found.object as THREE.Mesh;
        
        if (INTERSECTED !== serverMesh) {
          if (INTERSECTED) {
            resetMaterialEmissive(INTERSECTED.material);
          }
          
          INTERSECTED = serverMesh;
          setMaterialEmissive(INTERSECTED.material, HOVER_COLOR, HOVER_INTENSITY);

          updateTooltip(event, INTERSECTED.userData.status);
        }
      } else {
        resetHoverState();
      }
    } else {
      resetHoverState();
    }
  };

  const resetIntersected = () => {
    if (INTERSECTED) {
      resetMaterialEmissive(INTERSECTED.material);
    }
  };

  const resetHoverState = () => {
    resetIntersected();
    INTERSECTED = null;
    if (tooltipRef.current) {
      tooltipRef.current.style.display = 'none';
    }
  };

  const updateTooltip = (event: MouseEvent, serverStatus: ServerStatus) => {
    if (tooltipRef.current) {
      const containerRect = containerRef.current?.getBoundingClientRect();
      if (!containerRect) return;

      const tooltipX = event.clientX - containerRect.left;
      const tooltipY = event.clientY - containerRect.top;

      const tooltipRect = tooltipRef.current.getBoundingClientRect();
      const tooltipWidth = tooltipRect.width;
      const tooltipHeight = tooltipRect.height;

      const finalX = Math.min(
        tooltipX + 10,
        containerRect.width - tooltipWidth - 10
      );
      const finalY = Math.min(
        tooltipY + 10,
        containerRect.height - tooltipHeight - 10
      );

      tooltipRef.current.style.left = `${finalX}px`;
      tooltipRef.current.style.top = `${finalY}px`;
      tooltipRef.current.innerHTML = `
        <div class="bg-[${UI_STYLES.TOOLTIP.BACKGROUND}] border border-[${UI_STYLES.TOOLTIP.BORDER}] 
             shadow-[${UI_STYLES.TOOLTIP.SHADOW}] p-3 px-4 rounded text-[${UI_STYLES.TOOLTIP.TEXT}] text-sm">
          <div class="flex items-center gap-1.5 mb-1.5 pb-1 border-b border-[${UI_STYLES.TOOLTIP.BORDER_INNER}]">
            <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none">
              <path d="M19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3ZM5 19V5H19V19H5Z" fill="currentColor"/>
              <path d="M12 17H17V15H12V17ZM7 13H17V11H7V13ZM7 9H17V7H7V9Z" fill="currentColor"/>
            </svg>
            <span class="font-medium">资产信息</span>
          </div>
          <div class="grid gap-0.5 ml-1 mb-2">
            <div>名称: ${serverStatus.name}</div>
            <div>IP地址: ${serverStatus.ip}</div>
          </div>
          
          <div class="flex items-center gap-1.5 mb-1.5 pb-1 border-b border-[${UI_STYLES.TOOLTIP.BORDER_INNER}]">
            <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none">
              <path d="M15.9 4.99999C15.9 4.99999 15.9 4.89999 15.8 4.89999C15.4 4.39999 14.8 3.99999 14.2 3.69999L12.2 6.29999L15.9 4.99999Z" fill="currentColor"/>
              <path d="M18.2 7.3L15.9 5C15.9 5 15.9 4.9 15.8 4.9C16.8 5.7 17.6 6.4 18.2 7.3Z" fill="currentColor"/>
              <path d="M21 16V8C21 6.7 20.2 5.6 19 5.2C18.3 4.1 17.3 3.2 16.2 2.5C14.7 1.6 13 1 11.2 1C6.1 1 2 5.1 2 10.2C2 13.6 3.9 16.5 6.5 18.1C7.8 18.9 9 20.2 9 21.7V23H15V21.7C15 20.2 16.2 18.9 17.5 18.1C19.4 17 20.7 15.1 21 16ZM13 17H11V15H13V17ZM13 13H11V7H13V13Z" fill="currentColor"/>
            </svg>
            <span class="font-medium">网络状态</span>
          </div>
          <div class="grid gap-0.5 ml-1 mb-2">
            <div class="flex justify-between">
              <span>状态:</span>
              <div class="flex items-center gap-1.5">
                <span>${serverStatus.networkStatus === 1 ? '在线' : '离线'}</span>
                <span class="w-2 h-2 rounded-full ${serverStatus.networkStatus === 1 ? 'bg-green-500' : 'bg-red-500'}"></span>
              </div>
            </div>
            <div>丢包率: ${serverStatus.packetLoss}%</div>
          </div>

          <div class="flex items-center gap-1.5 mb-1.5 pb-1 border-b border-[${UI_STYLES.TOOLTIP.BORDER_INNER}]">
            <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none">
              <path d="M4 6H20V8H4V6Z" fill="currentColor"/>
              <path d="M4 11H20V13H4V11Z" fill="currentColor"/>
              <path d="M4 16H20V18H4V16Z" fill="currentColor"/>
              <path d="M2 4.5C2 3.67157 2.67157 3 3.5 3H20.5C21.3284 3 22 3.67157 22 4.5V19.5C22 20.3284 21.3284 21 20.5 21H3.5C2.67157 21 2 20.3284 2 19.5V4.5Z" stroke="currentColor" stroke-width="2"/>
            </svg>
            <span class="font-medium">配置信息</span>
          </div>
          <div class="grid gap-0.5 ml-1">
            <div>CPU: ${serverStatus.cpu || '-'}</div>
            <div>内存: ${serverStatus.memory || '-'}</div>
            <div>硬盘: ${serverStatus.disk || '-'}</div>
          </div>
        </div>
      `;
      tooltipRef.current.style.display = 'block';
    }
  };

  const cleanup = () => {
    resetHoverState();
  };

  return {
    handleMouseMove,
    cleanup
  };
} 

// 创建机柜模型 - 修改机柜的原点为底部中心
function createRack(position: THREE.Vector3): THREE.Mesh {
  // 创建机柜的六个面
  const rackGeometry = new THREE.BoxGeometry(0.6, 2, 1);
  
  // 创建两种材质：
  // 1. 通用材质 - 用于除前面外的所有面，双面渲染
  const commonMaterial = new THREE.MeshPhongMaterial({
    color: COLORS.RACK.SIDE,
    side: THREE.DoubleSide, // 双面渲染
    opacity: 0.9,
  });
  
  // 2. 前面材质 - 半透明
  const frontMaterial = new THREE.MeshPhongMaterial({
    color: COLORS.RACK.FRONT,
    transparent: true,
    opacity: 0.1,  // 前面设置为更透明
  });

  // 创建材质数组，按照几何体的面的顺序设置材质
  // BoxGeometry的面顺序：右、左、上、下、前、后
  const materials = [
    commonMaterial,  // 右面 - 双面渲染
    commonMaterial,  // 左面 - 双面渲染
    commonMaterial,  // 上面 - 双面渲染
    commonMaterial,  // 下面 - 双面渲染
    frontMaterial,   // 前面 - 半透明
    commonMaterial,  // 后面 - 双面渲染
  ];

  const rack = new THREE.Mesh(rackGeometry, materials);
  rack.position.copy(position);
  rackGeometry.translate(0, 1, 0);
  return rack;
}

// 创建服务器模型
function createServer(
  position: THREE.Vector3,
  serverData: ServerData,
  serverIconConfig: ServerIconConfig
): { server: THREE.Mesh } {
  const config = serverIconConfig;
  const U = serverData.u;
  
  const serverGeometry = new THREE.BoxGeometry(
    0.483,  // 19英寸 ≈ 0.483米
    U * U_HEIGHT,  // 将U数转换为实际高度
    0.8     // 深度保持0.8米
  );
  
  serverGeometry.translate(0, U * U_HEIGHT/2, 0);

  // 创建基础材质（用于侧面、顶面、底面和后面）
  const baseMaterial = new THREE.MeshPhongMaterial({ 
    color: config.color,
    shininess: 30,  // 降低反光度
  });

  // 创建前面的材质（用于贴图）
  const frontMaterial = new THREE.MeshPhongMaterial({ 
    color: config.color,
    shininess: 30,
    map: null,  // 初始化时设为null，等待贴图加载
  });

  // 创建材质数组
  const materials = [
    baseMaterial,  // 右面
    baseMaterial,  // 左面
    baseMaterial,  // 上面
    baseMaterial,  // 下面
    frontMaterial, // 前面 - 用于贴图
    baseMaterial,  // 后面
  ];

  const server = new THREE.Mesh(serverGeometry, materials);
  server.position.copy(position);

  // 加载贴图（如果有）
  if (config.textureUrl) {
    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(config.textureUrl, (texture) => {
      // 设置贴图属性以提高清晰度
      texture.minFilter = THREE.LinearFilter;
      texture.magFilter = THREE.LinearFilter;
      texture.anisotropy = 16;  // 增加各向异性过滤
      
      // 调整贴图的重复和偏移
      texture.repeat.set(1, 1);
      texture.offset.set(0, 0);
      
      // 更新材质
      frontMaterial.map = texture;
      frontMaterial.needsUpdate = true;
    });
  }

  return { server };
}

// 添加创建地板的函数
function createFloor(): THREE.Mesh {
  const floorGeometry = new THREE.PlaneGeometry(10, 10);
  const floorMaterial = new THREE.MeshPhongMaterial({
    color: COLORS.FLOOR,
    side: THREE.DoubleSide
  });
  
  // 添加网格纹理
  const gridHelper = new THREE.GridHelper(10, 20, COLORS.FLOOR_GRID, COLORS.FLOOR_GRID);
  gridHelper.rotation.x = Math.PI / 2;
  
  const floor = new THREE.Mesh(floorGeometry, floorMaterial);
  floor.rotation.x = -Math.PI / 2;
  floor.add(gridHelper);
  
  return floor;
} 

class ServerRack {
  rack: THREE.Mesh;
  servers: THREE.Mesh[] = [];
  statusLights: THREE.PointLight[] = [];

  constructor(scene: THREE.Scene, rackConfig: RackConfig, serverIconConfigs: ServerIconConfigs) {
    // 创建机柜
    this.rack = createRack(rackConfig.position);
    scene.add(this.rack);

    const bottomSpace = 0.04445;    // 底部预留空间1U
    const slotHeight = 0.04445;  // 每个槽位高度1U
    
    // 使用配置中的服务器数据创建服务器
    rackConfig.servers.forEach((serverData: ServerData) => {
      // 从底部开始计算高度
      const currentHeight = bottomSpace + (slotHeight * (serverData.slot - 1));
      
      const serverPosition = new THREE.Vector3(
        rackConfig.position.x,
        rackConfig.position.y + currentHeight,
        rackConfig.position.z
      );

      const serverIconConfig = serverIconConfigs[serverData.type];
      // console.log(serverIconConfig, serverIconConfigs);
      // console.log(serverData);
      // console.log(serverPosition);
      const { server } = createServer(
        serverPosition,
        serverData,
        serverIconConfig
      );

      server.userData.type = 'server';
      server.userData.status = getServerStatus(serverData);

      this.servers.push(server);

      scene.add(server);
    });
  }

  // 更新服务器状态
  updateServerStatus(serverId: string, status: ServerStatus) {
    const server = this.servers.find(s => s.userData.id === serverId);
    if (server) {
      server.userData.status = status;
      const index = this.servers.indexOf(server);
      if (index !== -1) {
        const light = this.statusLights[index];
        light.color.setHex(
          status.status === 'online' ? COLORS.SERVER.STATUS.ONLINE :
          status.status === 'warning' ? COLORS.SERVER.STATUS.WARNING : 
          COLORS.SERVER.STATUS.OFFLINE
        );
      }
    }
  }
} 

// 将服务器状态根据设备状态转换为对应的status格式
const getServerStatus = (serverData: ServerData): ServerStatus => {
  // 转换网络状态为UI显示状态
  let status: 'online' | 'offline' | 'warning' = 'offline';
  
  // 根据设备状态判断显示状态
  if (serverData.deviceStatus === 0) { // 正常
    status = 'online';
  } else if (serverData.deviceStatus === 2) { // 故障
    status = 'warning';
  } else { // 其他情况(维护中、下线)
    status = 'offline';
  }

  // 随机生成资源使用率用于展示
  return {
    ...serverData,
    status,
    usage: {
      cpu: Math.floor(Math.random() * 100),
      memory: Math.floor(Math.random() * 100),
      disk: Math.floor(Math.random() * 100)
    }
  };
};

export function ThreeJSRoom() {
  const containerRef = useRef<HTMLDivElement>(null);
  const tooltipRef = useRef<HTMLDivElement>(null);
  const racksRef = useRef<ServerRack[]>([]);
  const sceneRef = useRef<{
    scene: THREE.Scene;
    camera: THREE.PerspectiveCamera;
    renderer: THREE.WebGLRenderer;
    controls: typeof OrbitControls;
    cleanup: () => void;
  } | null>(null);

  // 获取服务器类型图标
  const { data: deviceIcons } = useQuery({
    queryKey: ['deviceIcons'],
    queryFn: queryFns.fetchDeviceIcons
  });

  // 获取机柜配置,添加自动刷新
  const { data: rackConfigs } = useQuery({
    queryKey: ['rackConfigs'],
    queryFn: queryFns.fetchRackConfigs,
    refetchInterval: 30000,
    refetchIntervalInBackground: true
  });

  // 初始化3D场景
  useEffect(() => {
    if (!containerRef.current) return;

    // 初始化场景
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(COLORS.BACKGROUND);

    const camera = new THREE.PerspectiveCamera(
      22,
      containerRef.current.clientWidth / containerRef.current.clientHeight,
      0.1,
      1000
    );

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight);
    containerRef.current.appendChild(renderer.domElement);

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.maxPolarAngle = Math.PI / 2;
    controls.minDistance = 6;
    controls.maxDistance = 10;
    controls.enablePan = false;
    controls.target.set(0, 1, 0);
    controls.enabled = false;

    // 添加地板
    const floor = createFloor();
    floor.position.y = -0.01;
    scene.add(floor);

    // 设置场景光照
    const ambientLight = new THREE.AmbientLight(COLORS.LIGHTS.AMBIENT, 0.6);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(COLORS.LIGHTS.DIRECT, 0.8);
    directionalLight.position.set(5, 5, 5);
    scene.add(directionalLight);

    const spotLight = new THREE.SpotLight(COLORS.LIGHTS.SPOT, 0.8);
    spotLight.position.set(0, 5, 0);
    spotLight.angle = Math.PI / 4;
    spotLight.penumbra = 0.1;
    scene.add(spotLight);

    camera.position.set(0, 1, 1);
    camera.lookAt(0, 1, 0);

    const { handleMouseMove, cleanup } = useServerHover({
      scene,
      camera,
      containerRef: containerRef as React.RefObject<HTMLDivElement>,
      tooltipRef: tooltipRef as React.RefObject<HTMLDivElement>
    });

    containerRef.current.addEventListener('mousemove', handleMouseMove);

    // 动画循环
    const animate = () => {
      requestAnimationFrame(animate);
      controls.update();
      renderer.render(scene, camera);
    };

    animate();

    // 保存场景引用
    sceneRef.current = {
      scene,
      camera,
      renderer,
      controls: controls as unknown as typeof OrbitControls,
      cleanup: () => {
        cleanup();
        if (containerRef.current) {
          containerRef.current.removeEventListener('mousemove', handleMouseMove);
          containerRef.current.removeChild(renderer.domElement);
        }
      }
    };

    // 使用 ResizeObserver 监听容器大小变化
    const resizeObserver = new ResizeObserver(() => {
      if (!containerRef.current || !sceneRef.current) return;
      // console.log('resizeObserver', containerRef.current.clientWidth, containerRef.current.clientHeight);
      const { camera, renderer } = sceneRef.current;
      camera.aspect = containerRef.current.clientWidth / containerRef.current.clientHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight);
    });

    resizeObserver.observe(containerRef.current);

    // 清理
    return () => {
      resizeObserver.disconnect();
      sceneRef.current?.cleanup();
    };
  }, []);

  // 更新机柜数据
  useEffect(() => {
    if (!sceneRef.current || !rackConfigs || !deviceIcons) return;

    // 清除现有机柜
    racksRef.current.forEach(rack => {
      rack.servers.forEach(server => {
        sceneRef.current!.scene.remove(server);
      });
      sceneRef.current!.scene.remove(rack.rack);
    });
    racksRef.current = [];


    // 创建新机柜
    racksRef.current = rackConfigs.map(config => {
      return new ServerRack(sceneRef.current!.scene, config, deviceIcons);
    });

  }, [rackConfigs, deviceIcons]);

  return (
    <div className="relative w-full h-full">
      <div ref={containerRef} className="w-full h-full" />
      <div 
        ref={tooltipRef}
        className="absolute hidden z-10"
        style={{ 
          pointerEvents: 'none',
          position: 'absolute',
          transform: 'translate3d(0, 0, 0)'
        }}
      >
        <div className="bg-[#001529] border border-[#00dff9] shadow-[0_0_10px_rgba(0,223,249,0.3)] p-2 rounded">
          {/* 工具提示内容由useServerHover处理 */}
        </div>
      </div>
    </div>
  );
} 