/**
 * CelestialBody component - renders a planet or probe with textures
 */
import { useRef, useMemo, useState, useEffect } from 'react';
import { Mesh, DoubleSide } from 'three';
import { useFrame } from '@react-three/fiber';
import { useTexture, Html } from '@react-three/drei';
import type { CelestialBody as CelestialBodyType } from '../types';
import { calculateRenderPosition, getOffsetDescription } from '../utils/renderPosition';
import { fetchBodyResources } from '../utils/api';
import { PLANET_SIZES, SATELLITE_SIZES, getCelestialSize } from '../config/celestialSizes';

interface CelestialBodyProps {
  body: CelestialBodyType;
  allBodies: CelestialBodyType[];
  isSelected?: boolean;
}

// Saturn Rings component - multiple rings for band effect
function SaturnRings() {
  return (
    <group rotation={[Math.PI / 2, 0, 0]}>
      {/* Inner bright ring */}
      <mesh>
        <ringGeometry args={[1.4, 1.6, 64]} />
        <meshBasicMaterial
          color="#D4B896"
          transparent
          opacity={0.7}
          side={DoubleSide}
        />
      </mesh>
      {/* Middle darker band */}
      <mesh>
        <ringGeometry args={[1.6, 1.75, 64]} />
        <meshBasicMaterial
          color="#8B7355"
          transparent
          opacity={0.5}
          side={DoubleSide}
        />
      </mesh>
      {/* Outer bright ring */}
      <mesh>
        <ringGeometry args={[1.75, 2.0, 64]} />
        <meshBasicMaterial
          color="#C4A582"
          transparent
          opacity={0.6}
          side={DoubleSide}
        />
      </mesh>
      {/* Cassini Division (gap) */}
      <mesh>
        <ringGeometry args={[2.0, 2.05, 64]} />
        <meshBasicMaterial
          color="#000000"
          transparent
          opacity={0.2}
          side={DoubleSide}
        />
      </mesh>
      {/* A Ring (outer) */}
      <mesh>
        <ringGeometry args={[2.05, 2.2, 64]} />
        <meshBasicMaterial
          color="#B89968"
          transparent
          opacity={0.5}
          side={DoubleSide}
        />
      </mesh>
    </group>
  );
}

// Planet component with texture
function Planet({ body, size, emissive, emissiveIntensity, allBodies, isSelected = false }: {
  body: CelestialBodyType;
  size: number;
  emissive: string;
  emissiveIntensity: number;
  allBodies: CelestialBodyType[];
  isSelected?: boolean;
}) {
  const meshRef = useRef<Mesh>(null);
  const position = body.positions[0];
  const [texturePath, setTexturePath] = useState<string | null | undefined>(undefined);

  // Use smart render position calculation
  const renderPosition = useMemo(() => {
    return calculateRenderPosition(body, allBodies);
  }, [position.x, position.y, position.z, body, allBodies]);

  const scaledPos = { x: renderPosition.x, y: renderPosition.y, z: renderPosition.z };

  // Fetch texture from backend API
  useEffect(() => {
    fetchBodyResources(body.id, 'texture')
      .then((response) => {
        // Find the main texture (not atmosphere or night layers)
        const mainTexture = response.resources.find(
          (r) => !r.file_path.includes('atmosphere') && !r.file_path.includes('night')
        );
        if (mainTexture) {
          // Construct full URL from file_path
          // file_path is like "texture/2k_sun.jpg", need to add "upload/" prefix
          const protocol = window.location.protocol;
          const hostname = window.location.hostname;
          const port = import.meta.env.VITE_API_BASE_URL ? '' : ':8000';
          setTexturePath(`${protocol}//${hostname}${port}/upload/${mainTexture.file_path}`);
        } else {
          setTexturePath(null);
        }
      })
      .catch((err) => {
        console.error(`Failed to load texture for ${body.name}:`, err);
        setTexturePath(null);
      });
  }, [body.id, body.name]);

  // Show nothing while loading
  if (texturePath === undefined) {
    return null;
  }

  return <PlanetMesh
    body={body}
    size={size}
    emissive={emissive}
    emissiveIntensity={emissiveIntensity}
    scaledPos={scaledPos}
    texturePath={texturePath}
    position={position}
    meshRef={meshRef}
    hasOffset={renderPosition.hasOffset}
    allBodies={allBodies}
    isSelected={isSelected}
  />;
}

// Separate component to handle texture loading
function PlanetMesh({ body, size, emissive, emissiveIntensity, scaledPos, texturePath, position, meshRef, hasOffset, allBodies, isSelected = false }: {
  body: CelestialBodyType;
  size: number;
  emissive: string;
  emissiveIntensity: number;
  scaledPos: { x: number; y: number; z: number };
  texturePath: string | null;
  position: { x: number; y: number; z: number };
  meshRef: React.RefObject<Mesh>;
  hasOffset: boolean;
  allBodies: CelestialBodyType[];
  isSelected?: boolean;
}) {
  // Load texture if path is provided
  const texture = texturePath ? useTexture(texturePath) : null;

  // Slow rotation for visual effect
  useFrame((_, delta) => {
    if (meshRef.current) {
      meshRef.current.rotation.y += delta * 0.1;
    }
  });

  // Calculate ACTUAL distance from Sun for display (not scaled)
  const distance = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2);

  // Get offset description if this body has one
  const offsetDesc = hasOffset ? getOffsetDescription(body, allBodies) : null;

  return (
    <group position={[scaledPos.x, scaledPos.z, scaledPos.y]}>
      <mesh ref={meshRef} renderOrder={0}>
        <sphereGeometry args={[size, 64, 64]} />
        {texture ? (
          <meshStandardMaterial
            map={texture}
            emissive={emissive}
            emissiveIntensity={emissiveIntensity}
            roughness={body.type === 'star' ? 0 : 0.7}
            metalness={0.1}
            depthTest={true}
            depthWrite={true}
          />
        ) : (
          <meshStandardMaterial
            color="#888888"
            emissive={emissive}
            emissiveIntensity={emissiveIntensity}
            roughness={0.7}
            metalness={0.1}
            depthTest={true}
            depthWrite={true}
          />
        )}
      </mesh>

      {/* Saturn Rings */}
      {body.id === '699' && <SaturnRings />}

      {/* Sun glow effect */}
      {body.type === 'star' && (
        <>
          <pointLight intensity={10} distance={400} color="#fff8e7" />
          <mesh>
            <sphereGeometry args={[size * 1.8, 32, 32]} />
            <meshBasicMaterial color="#FDB813" transparent opacity={0.35} />
          </mesh>
        </>
      )}

      {/* Name label */}
      <Html
        position={[0, size + 0.3, 0]}
        center
        distanceFactor={10}
        style={{
          color: body.type === 'star' ? '#FDB813' : '#ffffff',
          fontSize: '9px', // 从 11px 减小到 9px
          fontWeight: 'bold',
          textShadow: '0 0 4px rgba(0,0,0,0.8)',
          pointerEvents: 'none',
          userSelect: 'none',
          whiteSpace: 'nowrap',
          opacity: isSelected ? 1 : 0.4, // 未选中时更暗淡
          transition: 'opacity 0.3s ease',
        }}
      >
        {body.name_zh || body.name}
        {offsetDesc && (
          <>
            <br />
            <span style={{ fontSize: '7px', color: '#ffaa00', opacity: isSelected ? 0.9 : 0.5 }}> {/* 从 9px 减小到 7px */}
              {offsetDesc}
            </span>
          </>
        )}
        <br />
        <span style={{ fontSize: '7px', opacity: isSelected ? 0.7 : 0.3 }}> {/* 从 8px 减小到 7px */}
          {distance.toFixed(2)} AU
        </span>
      </Html>
    </group>
  );
}

export function CelestialBody({ body, allBodies, isSelected = false }: CelestialBodyProps) {
  // Get the current position (use the first position for now)
  const position = body.positions[0];
  if (!position) return null;

  // Skip probes - they will use 3D models
  if (body.type === 'probe') {
    return null;
  }

  // Determine size based on body type
  const appearance = useMemo(() => {
    if (body.type === 'star') {
      return {
        size: 0.4, // Sun size
        emissive: '#FDB813',
        emissiveIntensity: 1.5,
      };
    }

    // Satellite (natural moons) - small size with slight glow for visibility
    if (body.type === 'satellite') {
      return {
        size: getCelestialSize(body.name, body.type),
        emissive: '#888888',  // Slight glow to make it visible
        emissiveIntensity: 0.4,
      };
    }

    // Planet and dwarf planet sizes
    return {
      size: getCelestialSize(body.name, body.type),
      emissive: '#000000',
      emissiveIntensity: 0,
    };
  }, [body.name, body.type]);

  return (
    <Planet
      body={body}
      size={appearance.size}
      emissive={appearance.emissive}
      emissiveIntensity={appearance.emissiveIntensity}
      allBodies={allBodies}
      isSelected={isSelected}
    />
  );
}
