"""
地形管理器
负责管理地形的核心功能
"""

import numpy as np
from typing import Dict, Any, List, Tuple
import time

class TerrainManager:
    """
    地形管理器
    负责管理地形的核心功能，包括地形数据管理、生成控制等
    """
    
    def __init__(self, plugin):
        """
        初始化地形管理器
        
        Args:
            plugin: 程序化地形生成插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 地形配置
        self.terrain_size = plugin.config.get('terrain_size', 512)
        self.terrain_scale = plugin.config.get('terrain_scale', 1.0)
        self.height_scale = plugin.config.get('height_scale', 100.0)
        self.seed = plugin.config.get('seed', 12345)
        
        # 地形数据
        self.heightmap = None
        self.normalmap = None
        self.biome_map = None
        self.moisture_map = None
        self.temperature_map = None
        self.erosion_map = None
        self.sediment_map = None
        self.water_map = None
        self.vegetation_map = None
        
        # 地形统计信息
        self.stats = {
            'generation_time': 0.0,
            'triangles_generated': 0,
            'vertices_generated': 0,
            'chunks_generated': 0,
            'lod_levels': plugin.config.get('lod_levels', 5)
        }
        
        # 地形生成状态
        self.is_generating = False
        self.generation_progress = 0.0
        self.last_generation_time = 0.0
        
        # 地形分块管理
        self.chunk_size = plugin.config.get('chunk_size', 32)
        self.chunks = {}
        self.visible_chunks = set()
        
        print("✓ 地形管理器已创建")
        
    def initialize(self) -> bool:
        """
        初始化地形管理器
        
        Returns:
            是否初始化成功
        """
        try:
            # 初始化地形数据结构
            self._initialize_terrain_data()
            
            self.initialized = True
            print("✓ 地形管理器初始化完成")
            return True
            
        except Exception as e:
            print(f"✗ 地形管理器初始化失败: {e}")
            import traceback
            traceback.print_exc()
            return False
            
    def enable(self) -> bool:
        """
        启用地形管理器
        
        Returns:
            是否启用成功
        """
        try:
            if not self.initialized:
                print("✗ 地形管理器未初始化")
                return False
                
            self.enabled = True
            print("✓ 地形管理器已启用")
            return True
            
        except Exception as e:
            print(f"✗ 地形管理器启用失败: {e}")
            import traceback
            traceback.print_exc()
            return False
            
    def disable(self):
        """禁用地形管理器"""
        try:
            self.enabled = False
            print("✓ 地形管理器已禁用")
            
        except Exception as e:
            print(f"✗ 地形管理器禁用失败: {e}")
            import traceback
            traceback.print_exc()
            
    def finalize(self):
        """清理地形管理器资源"""
        try:
            self.disable()
            self.initialized = False
            print("✓ 地形管理器资源已清理")
            
        except Exception as e:
            print(f"✗ 地形管理器资源清理失败: {e}")
            import traceback
            traceback.print_exc()
            
    def update(self, dt: float):
        """
        更新地形管理器状态
        
        Args:
            dt: 时间增量
        """
        # 处理地形更新逻辑
        pass
        
    def _initialize_terrain_data(self):
        """初始化地形数据结构"""
        try:
            size = self.terrain_size
            # 初始化高度图
            self.heightmap = np.zeros((size, size), dtype=np.float32)
            
            # 初始化法线图
            self.normalmap = np.zeros((size, size, 3), dtype=np.float32)
            
            # 初始化生物群落图
            self.biome_map = np.zeros((size, size), dtype=np.int32)
            
            # 初始化湿度图
            self.moisture_map = np.zeros((size, size), dtype=np.float32)
            
            # 初始化温度图
            self.temperature_map = np.zeros((size, size), dtype=np.float32)
            
            # 初始化侵蚀图
            self.erosion_map = np.zeros((size, size), dtype=np.float32)
            
            # 初始化沉积物图
            self.sediment_map = np.zeros((size, size), dtype=np.float32)
            
            # 初始化水图
            self.water_map = np.zeros((size, size), dtype=np.float32)
            
            # 初始化植被图
            self.vegetation_map = np.zeros((size, size), dtype=np.int32)
            
            print("✓ 地形数据结构初始化完成")
            
        except Exception as e:
            print(f"✗ 地形数据结构初始化失败: {e}")
            import traceback
            traceback.print_exc()
            
    def generate_terrain(self, width: int = None, height: int = None, seed: int = None) -> bool:
        """
        生成地形
        
        Args:
            width: 地形宽度
            height: 地形高度
            seed: 随机种子
            
        Returns:
            是否生成成功
        """
        try:
            if not self.enabled:
                print("✗ 地形管理器未启用")
                return False
                
            if self.is_generating:
                print("⚠ 地形生成已在进行中")
                return True
                
            # 更新参数
            if width is not None:
                self.terrain_size = width
                
            if seed is not None:
                self.seed = seed
                if self.plugin.noise_generator:
                    self.plugin.noise_generator.set_seed(seed)
                if self.plugin.heightmap_generator:
                    self.plugin.heightmap_generator.set_seed(seed)
                    
            # 重新初始化地形数据（如果尺寸改变）
            if width is not None or height is not None:
                self._initialize_terrain_data()
                
            generation_start_time = time.time()
            self.is_generating = True
            self.generation_progress = 0.0
            
            print("✓ 开始生成地形...")
            
            # 1. 生成高度图
            print("  → 生成高度图...")
            if self.plugin.heightmap_generator:
                self.heightmap = self.plugin.heightmap_generator.generate_heightmap(
                    self.terrain_size, self.terrain_size, self.seed
                )
                self.generation_progress = 20.0
                
            # 2. 计算法线
            print("  → 计算法线...")
            self.normalmap = self._calculate_normals(self.heightmap)
            self.generation_progress = 30.0
            
            # 3. 生成生物群落
            print("  → 生成生物群落...")
            if self.plugin.biome_generator:
                biome_data = self.plugin.biome_generator.generate_biomes(
                    self.heightmap, self.seed
                )
                self.biome_map = biome_data.get('biome_map', self.biome_map)
                self.moisture_map = biome_data.get('moisture_map', self.moisture_map)
                self.temperature_map = biome_data.get('temperature_map', self.temperature_map)
                self.generation_progress = 50.0
                
            # 4. 应用侵蚀
            print("  → 应用侵蚀模拟...")
            if self.plugin.erosion_processor:
                erosion_result = self.plugin.erosion_processor.apply_erosion(
                    self.heightmap, self.seed
                )
                self.heightmap = erosion_result.get('heightmap', self.heightmap)
                self.erosion_map = erosion_result.get('erosion_map', self.erosion_map)
                self.sediment_map = erosion_result.get('sediment_map', self.sediment_map)
                self.water_map = erosion_result.get('water_map', self.water_map)
                self.generation_progress = 70.0
                
            # 5. 生成植被
            print("  → 生成植被...")
            if self.plugin.vegetation_generator:
                self.vegetation_map = self.plugin.vegetation_generator.generate_vegetation(
                    self.heightmap, self.biome_map, self.seed
                )
                self.generation_progress = 90.0
                
            # 6. 更新统计信息
            self.stats['generation_time'] = time.time() - generation_start_time
            self.stats['triangles_generated'] = self.terrain_size * self.terrain_size * 2
            self.stats['vertices_generated'] = self.terrain_size * self.terrain_size
            self.stats['chunks_generated'] = (self.terrain_size // self.chunk_size) ** 2
            
            self.is_generating = False
            self.generation_progress = 100.0
            self.last_generation_time = time.time()
            
            print(f"✓ 地形生成完成，耗时: {self.stats['generation_time']:.2f}秒")
            return True
            
        except Exception as e:
            print(f"✗ 地形生成失败: {e}")
            import traceback
            traceback.print_exc()
            self.is_generating = False
            return False
            
    def _calculate_normals(self, heightmap: np.ndarray) -> np.ndarray:
        """
        根据高度图计算法线图
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            法线图数据
        """
        try:
            height, width = heightmap.shape
            normals = np.zeros((height, width, 3), dtype=np.float32)
            
            # 计算每个点的法线
            for y in range(height):
                for x in range(width):
                    # 计算相邻点的高度
                    h_left = heightmap[y, max(0, x-1)]
                    h_right = heightmap[y, min(width-1, x+1)]
                    h_up = heightmap[max(0, y-1), x]
                    h_down = heightmap[min(height-1, y+1), x]
                    
                    # 计算梯度
                    dx = (h_right - h_left) * self.height_scale
                    dy = (h_down - h_up) * self.height_scale
                    dz = 2.0 * self.terrain_scale
                    
                    # 计算法线
                    normal = np.array([-dx, -dy, dz], dtype=np.float32)
                    norm = np.linalg.norm(normal)
                    if norm > 0:
                        normal = normal / norm
                        
                    normals[y, x] = normal
                    
            return normals
            
        except Exception as e:
            print(f"✗ 法线计算失败: {e}")
            return np.zeros((heightmap.shape[0], heightmap.shape[1], 3), dtype=np.float32)
            
    def get_terrain_data(self) -> Dict[str, Any]:
        """
        获取地形数据
        
        Returns:
            地形数据字典
        """
        return {
            'heightmap': self.heightmap,
            'normalmap': self.normalmap,
            'biome_map': self.biome_map,
            'moisture_map': self.moisture_map,
            'temperature_map': self.temperature_map,
            'erosion_map': self.erosion_map,
            'sediment_map': self.sediment_map,
            'water_map': self.water_map,
            'vegetation_map': self.vegetation_map,
            'stats': self.stats.copy(),
            'is_generating': self.is_generating,
            'generation_progress': self.generation_progress
        }
        
    def get_height_at(self, x: int, y: int) -> float:
        """
        获取指定位置的高度值
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            高度值
        """
        try:
            if self.heightmap is not None and 0 <= x < self.heightmap.shape[1] and 0 <= y < self.heightmap.shape[0]:
                return self.heightmap[y, x]
            return 0.0
        except Exception as e:
            print(f"✗ 获取高度值失败: {e}")
            return 0.0
            
    def get_normal_at(self, x: int, y: int) -> np.ndarray:
        """
        获取指定位置的法线向量
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            法线向量
        """
        try:
            if self.normalmap is not None and 0 <= x < self.normalmap.shape[1] and 0 <= y < self.normalmap.shape[0]:
                return self.normalmap[y, x].copy()
            return np.array([0.0, 0.0, 1.0], dtype=np.float32)
        except Exception as e:
            print(f"✗ 获取法线向量失败: {e}")
            return np.array([0.0, 0.0, 1.0], dtype=np.float32)
            
    def get_biome_at(self, x: int, y: int) -> int:
        """
        获取指定位置的生物群落类型
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            生物群落类型
        """
        try:
            if self.biome_map is not None and 0 <= x < self.biome_map.shape[1] and 0 <= y < self.biome_map.shape[0]:
                return self.biome_map[y, x]
            return 0
        except Exception as e:
            print(f"✗ 获取生物群落类型失败: {e}")
            return 0
            
    def set_terrain_scale(self, scale: float):
        """
        设置地形缩放
        
        Args:
            scale: 缩放因子
        """
        self.terrain_scale = scale
        print(f"✓ 地形缩放设置为: {scale}")
        
    def set_height_scale(self, scale: float):
        """
        设置高度缩放
        
        Args:
            scale: 高度缩放因子
        """
        self.height_scale = scale
        print(f"✓ 高度缩放设置为: {scale}")
        
    def get_stats(self) -> Dict[str, Any]:
        """
        获取统计信息
        
        Returns:
            统计信息字典
        """
        return self.stats.copy()
        
    def is_terrain_generated(self) -> bool:
        """
        检查地形是否已生成
        
        Returns:
            是否已生成地形
        """
        return self.heightmap is not None and self.heightmap.size > 0
        
    def clear_terrain(self):
        """清空地形数据"""
        try:
            self.heightmap = None
            self.normalmap = None
            self.biome_map = None
            self.moisture_map = None
            self.temperature_map = None
            self.erosion_map = None
            self.sediment_map = None
            self.water_map = None
            self.vegetation_map = None
            
            # 重新初始化数据结构
            self._initialize_terrain_data()
            
            print("✓ 地形数据已清空")
            
        except Exception as e:
            print(f"✗ 清空地形数据失败: {e}")
            import traceback
            traceback.print_exc()
            
    def resize_terrain(self, new_size: int):
        """
        调整地形大小
        
        Args:
            new_size: 新的地形大小
        """
        try:
            old_size = self.terrain_size
            self.terrain_size = new_size
            
            # 重新初始化地形数据
            self._initialize_terrain_data()
            
            print(f"✓ 地形大小已从 {old_size} 调整为 {new_size}")
            
        except Exception as e:
            print(f"✗ 调整地形大小失败: {e}")
            import traceback
            traceback.print_exc()
            
    def get_generation_progress(self) -> float:
        """
        获取生成进度
        
        Returns:
            生成进度百分比 (0.0-100.0)
        """
        return self.generation_progress
        
    def is_generating(self) -> bool:
        """
        检查是否正在生成地形
        
        Returns:
            是否正在生成
        """
        return self.is_generating
        
    def get_chunk_info(self, chunk_x: int, chunk_y: int) -> Dict[str, Any]:
        """
        获取指定区块的信息
        
        Args:
            chunk_x: 区块X坐标
            chunk_y: 区块Y坐标
            
        Returns:
            区块信息
        """
        chunk_key = f"{chunk_x},{chunk_y}"
        if chunk_key in self.chunks:
            return self.chunks[chunk_key].copy()
        else:
            return {
                'x': chunk_x,
                'y': chunk_y,
                'generated': False,
                'visible': False,
                'lod_level': 0
            }
            
    def set_chunk_visibility(self, chunk_x: int, chunk_y: int, visible: bool):
        """
        设置区块可见性
        
        Args:
            chunk_x: 区块X坐标
            chunk_y: 区块Y坐标
            visible: 是否可见
        """
        chunk_key = f"{chunk_x},{chunk_y}"
        if chunk_key in self.chunks:
            self.chunks[chunk_key]['visible'] = visible
            if visible:
                self.visible_chunks.add(chunk_key)
            elif chunk_key in self.visible_chunks:
                self.visible_chunks.remove(chunk_key)
                
    def get_visible_chunks(self) -> List[str]:
        """
        获取可见区块列表
        
        Returns:
            可见区块键列表
        """
        return list(self.visible_chunks)
        
    def update_chunk_lod(self, chunk_x: int, chunk_y: int, lod_level: int):
        """
        更新区块LOD级别
        
        Args:
            chunk_x: 区块X坐标
            chunk_y: 区块Y坐标
            lod_level: LOD级别
        """
        chunk_key = f"{chunk_x},{chunk_y}"
        if chunk_key in self.chunks:
            self.chunks[chunk_key]['lod_level'] = max(0, min(lod_level, self.stats['lod_levels'] - 1))
            
    def get_terrain_bounds(self) -> Tuple[int, int]:
        """
        获取地形边界
        
        Returns:
            (宽度, 高度)
        """
        if self.heightmap is not None:
            return self.heightmap.shape[1], self.heightmap.shape[0]
        return self.terrain_size, self.terrain_size
        
    def get_terrain_center(self) -> Tuple[float, float]:
        """
        获取地形中心点
        
        Returns:
            (中心X坐标, 中心Y坐标)
        """
        width, height = self.get_terrain_bounds()
        return width / 2.0, height / 2.0
        
    def get_terrain_area(self) -> float:
        """
        获取地形面积
        
        Returns:
            地形面积
        """
        width, height = self.get_terrain_bounds()
        return width * height * self.terrain_scale * self.terrain_scale
        
    def get_height_range(self) -> Tuple[float, float]:
        """
        获取高度范围
        
        Returns:
            (最小高度, 最大高度)
        """
        if self.heightmap is not None and self.heightmap.size > 0:
            return float(np.min(self.heightmap)), float(np.max(self.heightmap))
        return 0.0, 0.0
        
    def get_average_height(self) -> float:
        """
        获取平均高度
        
        Returns:
            平均高度
        """
        if self.heightmap is not None and self.heightmap.size > 0:
            return float(np.mean(self.heightmap))
        return 0.0
        
    def get_terrain_gradient(self, x: int, y: int) -> float:
        """
        获取指定位置的地形坡度
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            坡度值 (弧度)
        """
        try:
            if self.normalmap is not None and 0 <= x < self.normalmap.shape[1] and 0 <= y < self.normalmap.shape[0]:
                normal = self.normalmap[y, x]
                # 计算与垂直方向的夹角
                vertical = np.array([0.0, 0.0, 1.0])
                dot_product = np.dot(normal, vertical)
                angle = np.arccos(np.clip(dot_product, -1.0, 1.0))
                return float(angle)
            return 0.0
        except Exception as e:
            print(f"✗ 计算地形坡度失败: {e}")
            return 0.0
            
    def get_terrain_aspect(self, x: int, y: int) -> float:
        """
        获取指定位置的地形坡向
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            坡向值 (弧度，0为北向)
        """
        try:
            if self.normalmap is not None and 0 <= x < self.normalmap.shape[1] and 0 <= y < self.normalmap.shape[0]:
                normal = self.normalmap[y, x]
                # 计算在水平面上的投影
                aspect = np.arctan2(normal[1], normal[0])
                # 转换为0-2π范围
                if aspect < 0:
                    aspect += 2 * np.pi
                return float(aspect)
            return 0.0
        except Exception as e:
            print(f"✗ 计算地形坡向失败: {e}")
            return 0.0
            
    def get_terrain_curvature(self, x: int, y: int) -> float:
        """
        获取指定位置的地形曲率
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            曲率值
        """
        try:
            if self.heightmap is None:
                return 0.0
                
            height, width = self.heightmap.shape
            if not (1 <= x < width - 1 and 1 <= y < height - 1):
                return 0.0
                
            # 使用拉普拉斯算子计算曲率
            center = self.heightmap[y, x]
            laplacian = (
                self.heightmap[y-1, x] + self.heightmap[y+1, x] +
                self.heightmap[y, x-1] + self.heightmap[y, x+1] - 4 * center
            )
            
            return float(laplacian)
        except Exception as e:
            print(f"✗ 计算地形曲率失败: {e}")
            return 0.0
            
    def get_terrain_roughness(self, x: int, y: int, radius: int = 3) -> float:
        """
        获取指定位置的地形粗糙度
        
        Args:
            x: X坐标
            y: Y坐标
            radius: 计算半径
            
        Returns:
            粗糙度值
        """
        try:
            if self.heightmap is None:
                return 0.0
                
            height, width = self.heightmap.shape
            min_x = max(0, x - radius)
            max_x = min(width - 1, x + radius)
            min_y = max(0, y - radius)
            max_y = min(height - 1, y + radius)
            
            if min_x >= max_x or min_y >= max_y:
                return 0.0
                
            # 计算局部高度变化
            local_heights = self.heightmap[min_y:max_y+1, min_x:max_x+1]
            roughness = float(np.std(local_heights))
            
            return roughness
        except Exception as e:
            print(f"✗ 计算地形粗糙度失败: {e}")
            return 0.0
            
    def get_water_level(self, x: int, y: int) -> float:
        """
        获取指定位置的水位
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            水位值
        """
        try:
            if self.water_map is not None and 0 <= x < self.water_map.shape[1] and 0 <= y < self.water_map.shape[0]:
                return self.water_map[y, x]
            return 0.0
        except Exception as e:
            print(f"✗ 获取水位值失败: {e}")
            return 0.0
            
    def is_under_water(self, x: int, y: int) -> bool:
        """
        检查指定位置是否在水下
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            是否在水下
        """
        try:
            if self.heightmap is not None and self.water_map is not None:
                if 0 <= x < self.heightmap.shape[1] and 0 <= y < self.heightmap.shape[0]:
                    return self.water_map[y, x] > self.heightmap[y, x]
            return False
        except Exception as e:
            print(f"✗ 检查水下状态失败: {e}")
            return False
            
    def get_vegetation_density(self, x: int, y: int) -> float:
        """
        获取指定位置的植被密度
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            植被密度 (0.0-1.0)
        """
        try:
            if self.vegetation_map is not None and 0 <= x < self.vegetation_map.shape[1] and 0 <= y < self.vegetation_map.shape[0]:
                # 简化处理，将植被类型转换为密度值
                vegetation_type = self.vegetation_map[y, x]
                return min(1.0, vegetation_type / 10.0)  # 假设最多10种植被类型
            return 0.0
        except Exception as e:
            print(f"✗ 获取植被密度失败: {e}")
            return 0.0
            
    def get_biome_properties(self, x: int, y: int) -> Dict[str, Any]:
        """
        获取指定位置的生物群落属性
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            生物群落属性字典
        """
        try:
            biome_type = self.get_biome_at(x, y)
            moisture = 0.0
            temperature = 0.0
            
            if self.moisture_map is not None and 0 <= x < self.moisture_map.shape[1] and 0 <= y < self.moisture_map.shape[0]:
                moisture = self.moisture_map[y, x]
                
            if self.temperature_map is not None and 0 <= x < self.temperature_map.shape[1] and 0 <= y < self.temperature_map.shape[0]:
                temperature = self.temperature_map[y, x]
                
            return {
                'biome_type': biome_type,
                'moisture': moisture,
                'temperature': temperature
            }
        except Exception as e:
            print(f"✗ 获取生物群落属性失败: {e}")
            return {
                'biome_type': 0,
                'moisture': 0.0,
                'temperature': 0.0
            }
            
    def get_erosion_level(self, x: int, y: int) -> float:
        """
        获取指定位置的侵蚀程度
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            侵蚀程度 (0.0-1.0)
        """
        try:
            if self.erosion_map is not None and 0 <= x < self.erosion_map.shape[1] and 0 <= y < self.erosion_map.shape[0]:
                return self.erosion_map[y, x]
            return 0.0
        except Exception as e:
            print(f"✗ 获取侵蚀程度失败: {e}")
            return 0.0
            
    def get_sediment_level(self, x: int, y: int) -> float:
        """
        获取指定位置的沉积物水平
            
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            沉积物水平 (0.0-1.0)
        """
        try:
            if self.sediment_map is not None and 0 <= x < self.sediment_map.shape[1] and 0 <= y < self.sediment_map.shape[0]:
                return self.sediment_map[y, x]
            return 0.0
        except Exception as e:
            print(f"✗ 获取沉积物水平失败: {e}")
            return 0.0