import React, { useState, useRef, useMemo, FC, useEffect } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Sphere, Cone, Box, Text } from '@react-three/drei';
import * as THREE from 'three';
import { createNoise3D } from 'simplex-noise';
import { generateGlobeTextureData } from './texture-generator';

// --- 타입 정의 ---

interface CityData {
    name: string;
    lat: number; // 위도 (degrees)
    lon: number; // 경도 (degrees)
    population?: number; // 예시 데이터
}

interface SymbolicBuildingProps {
    position: THREE.Vector3;
    cityName: string;
    scale?: number;
    onPointerOver: () => void;
    onPointerOut: () => void;
}

interface GlobeProps {
    radius: number;
}

// --- 유틸리티 함수 ---

/**
 * 위도, 경도를 3D 벡터 좌표로 변환
 * @param lat 위도 (degrees)
 * @param lon 경도 (degrees)
 * @param radius 구의 반지름
 * @returns THREE.Vector3 좌표
 */
const latLonToVector3 = (lat: number, lon: number, radius: number): THREE.Vector3 => {
    const phi = (90 - lat) * (Math.PI / 180); // 위도를 극 각도(phi)로 변환 (라디안)
    const theta = (lon + 180) * (Math.PI / 180); // 경도를 방위각(theta)으로 변환 (라디안)

    const x = -(radius * Math.sin(phi) * Math.cos(theta));
    const z = radius * Math.sin(phi) * Math.sin(theta);
    const y = radius * Math.cos(phi);

    return new THREE.Vector3(x, y, z);
};

/**
 * 간단한 절차적 지구본 텍스처 생성 (Simplex Noise 사용)
 * @param width 텍스처 너비
 * @param height 텍스처 높이
 * @returns THREE.DataTexture
 */
const generateGlobeTexture = (width: number, height: number, seed?: number): THREE.DataTexture => {
    const { data } = generateGlobeTextureData(width, height, seed); // 텍스처 데이터 생성
    const texture = new THREE.DataTexture(
        data,
        width,
        height,
        THREE.RGBAFormat // RGBA 포맷 사용
    );

    texture.needsUpdate = true;
    // 텍스처 필터링 및 래핑 설정 (선택 사항)
    texture.magFilter = THREE.LinearFilter;
    texture.minFilter = THREE.LinearMipmapLinearFilter; // 밉맵 사용 시
    texture.wrapS = THREE.ClampToEdgeWrapping; // 구 텍스처는 ClampToEdge가 더 적합할 수 있음
    texture.wrapT = THREE.ClampToEdgeWrapping;
    texture.generateMipmaps = true; // 밉맵 생성

    return texture;
};


// --- 컴포넌트 정의 ---

/**
 * 도시를 상징하는 건물 컴포넌트 (Cone 사용)
 */
const SymbolicBuilding: FC<SymbolicBuildingProps> = ({ position, cityName, scale = 1, onPointerOver, onPointerOut }) => {
    const coneRef = useRef<THREE.Mesh>(null!);
    const textRef = useRef<any>(null); // drei Text 타입 추론 어려움
    const [hovered, setHovered] = useState(false);

    // 건물이 구 표면에서 바깥쪽을 향하도록 방향 설정
    useEffect(() => {
        if (coneRef.current) {
            coneRef.current.lookAt(0, 0, 0); // 구의 중심을 바라보게 하여 위쪽이 바깥을 향하도록
            coneRef.current.rotateX(Math.PI / 2); // Cone은 기본적으로 Y축 방향이므로 X축 회전 추가
        }
        if (textRef.current) {
            // 텍스트도 같은 방향을 보도록 설정
            textRef.current.lookAt(1000 * position.x, 1000 * position.y, 1000 * position.z); // 카메라를 향하도록
        }
    }, [position]);

    const coneHeight = 0.5 * scale;
    const coneRadius = 0.1 * scale;

    return (
        <group position={position}>
            <Cone
                ref={coneRef}
                args={[coneRadius, coneHeight, 8]} // 반지름, 높이, 분할 수
                position={[0, coneHeight / 2, 0]} // 위치 조정 (Cone의 기준점은 바닥 중앙)
                castShadow
                onPointerOver={(e) => { e.stopPropagation(); setHovered(true); onPointerOver(); }}
                onPointerOut={(e) => { setHovered(false); onPointerOut(); }}
            >
                <meshStandardMaterial color={hovered ? 'red' : 'yellow'} emissive={hovered ? 'darkred' : 'black'} />
            </Cone>
            {/* 호버 시 도시 이름 표시 */}
            <Text
                ref={textRef}
                position={[0, coneHeight + 0.2, 0]} // 콘 위쪽에 위치
                fontSize={0.15}
                color="white"
                anchorX="center"
                anchorY="middle"
                visible={hovered}
                depthOffset={-1000} // 다른 객체 위에 렌더링되도록
            >
                {cityName}
            </Text>
        </group>
    );
};


const mapSeed = Math.random() * 1000; // 랜덤 시드 (선택 사항)
/**
 * 지구본 컴포넌트
 */
const Globe: FC<GlobeProps> = ({ radius }) => {
    const meshRef = useRef<THREE.Mesh>(null!);
    const [globeTexture, setGlobeTexture] = useState<THREE.DataTexture | null>(
        () => generateGlobeTexture(256, 128, mapSeed) // 초기 텍스처 생성 (메인 스레드에서)
    );
    const workerRef = useRef<Worker | null>(null);

    useEffect(() => {
        // 웹 워커를 사용하여 텍스처 생성
        workerRef.current = new Worker(new URL('./textureWorker.ts', import.meta.url), { type: 'module' });
        workerRef.current.onmessage = (event) => {
            const { data, width, height } = event.data;
            const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
            texture.needsUpdate = true;
            texture.magFilter = THREE.LinearFilter;
            texture.minFilter = THREE.LinearMipmapLinearFilter;
            texture.wrapS = THREE.ClampToEdgeWrapping;
            texture.wrapT = THREE.ClampToEdgeWrapping;
            texture.generateMipmaps = true;
            console.log('Texture generated in worker:', texture);
            setGlobeTexture(texture);
        };
        workerRef.current.postMessage({ width: 4096, height: 2048, seed: mapSeed });

        return () => {
            if (workerRef.current) {
                workerRef.current.terminate();
            }
        };
    }, []);

    return (
        <Sphere ref={meshRef} args={[radius, 64, 64]} receiveShadow castShadow>
            {/* 절차적 텍스처 적용 */}
            <meshStandardMaterial
                map={globeTexture}
                roughness={1}
                metalness={0.5}
                color={"#ffffff"} // 기본 색상 (흰색)
            // bumpMap={globeTexture} // 같은 텍스처를 범프맵으로 사용 (선택 사항)
            // bumpScale={0.01}
            />
        </Sphere>
    );
};


// --- 메인 앱 컴포넌트 ---
const App: FC = () => {
    const globeRadius = 5; // 지구본 반지름
    const [hoveredCity, setHoveredCity] = useState<string | null>(null);

    // 주요 도시 데이터
    const cities: CityData[] = useMemo(() => [
        { name: 'Seoul', lat: 37.5665, lon: 126.9780 },
        { name: 'New York', lat: 40.7128, lon: -74.0060 },
        { name: 'London', lat: 51.5074, lon: -0.1278 },
        { name: 'Tokyo', lat: 35.6895, lon: 139.6917 },
        { name: 'Sydney', lat: -33.8688, lon: 151.2093 },
        { name: 'Cairo', lat: 30.0444, lon: 31.2357 },
        { name: 'Rio de Janeiro', lat: -22.9068, lon: -43.1729 },
        { name: 'Moscow', lat: 55.7558, lon: 37.6173 },
    ], []);

    return (
        // Tailwind CSS 적용
        <div className="w-screen h-screen relative bg-black">
            {/* 호버된 도시 이름 표시 (선택 사항) */}
            {/*
        <div className="absolute top-5 left-5 text-white font-sans z-50">
            Hovered: {hoveredCity || 'None'}
        </div>
        */}
            <Canvas shadows camera={{ position: [0, 0, 15], fov: 45 }}>
                {/* 배경색 제거 (우주처럼 검게) */}
                {/* <color attach="background" args={['#111111']} /> */}
                <ambientLight intensity={0.3} />
                <directionalLight
                    position={[5, 5, 5]} // 태양광처럼 멀리서 비추는 빛
                    intensity={5}
                    castShadow
                    shadow-mapSize-width={1024}
                    shadow-mapSize-height={1024}
                />
                <OrbitControls enablePan={false} minDistance={8} maxDistance={30} />

                {/* 지구본 렌더링 */}
                <Globe radius={globeRadius} />

                {/* 도시 건물 렌더링 */}
                {cities.map((city) => {
                    const position = latLonToVector3(city.lat, city.lon, globeRadius);
                    return (
                        <SymbolicBuilding
                            key={city.name}
                            position={position}
                            cityName={city.name}
                            scale={0.5} // 건물 크기 조절
                            onPointerOver={() => setHoveredCity(city.name)}
                            onPointerOut={() => setHoveredCity(null)}
                        />
                    );
                })}

            </Canvas>
        </div>
    );
}

export default App;

// --- TypeScript 및 Tailwind CSS 설정 참고 ---
// 이전과 동일

// --- 필요 라이브러리 설치 ---
// npm install react react-dom three @react-three/fiber @react-three/drei
// yarn add react react-dom three @react-three/fiber @react-three/drei
// npm install --save-dev @types/three

// --- 실행 방법 ---
// 이전과 동일 (App.tsx 사용)
