"""
水体表面模块
负责水体表面的几何生成和动态更新
"""

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

class WaterSurface:
    """
    水体表面管理器
    负责水体表面的几何生成、动态更新和渲染准备
    """
    
    def __init__(self, plugin):
        """
        初始化水体表面管理器
        
        Args:
            plugin: 水体和流体模拟插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 网格配置
        self.mesh_config = {
            'resolution_x': 128,
            'resolution_z': 128,
            'tessellation_level': 1,
            'patch_size': 10.0,
            'lod_enabled': True,
            'lod_distance': 50.0
        }
        
        # 表面顶点数据
        self.vertices = []
        self.normals = []
        self.uvs = []
        self.indices = []
        
        # 表面高度场
        self.height_field = None
        self.normal_field = None
        
        # 动态更新配置
        self.update_config = {
            'update_frequency': 60.0,  # Hz
            'last_update_time': 0.0,
            'needs_update': True
        }
        
        # 纹理坐标配置
        self.uv_config = {
            'scale_u': 1.0,
            'scale_v': 1.0,
            'scroll_u': 0.0,
            'scroll_v': 0.0,
            'scroll_speed_u': 0.1,
            'scroll_speed_v': 0.05
        }
        
        # 几何统计
        self.geometry_stats = {
            'vertex_count': 0,
            'triangle_count': 0,
            'patch_count': 0,
            'updates_performed': 0
        }
        
        # 性能优化
        self.optimization_settings = {
            'frustum_culling': True,
            'occlusion_culling': False,
            'dynamic_lod': True,
            'vertex_cache': True
        }
        
        print("✓ 水体表面管理器已创建")
        
    def initialize(self) -> bool:
        """
        初始化水体表面管理器
        
        Returns:
            是否初始化成功
        """
        try:
            # 初始化高度场
            self._initialize_height_field()
            
            # 生成初始网格
            self._generate_initial_mesh()
            
            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._clear_mesh_data()
            self.initialized = False
            print("✓ 水体表面管理器资源已清理")
            
        except Exception as e:
            print(f"✗ 水体表面管理器资源清理失败: {e}")
            import traceback
            traceback.print_exc()
            
    def update(self, dt: float):
        """
        更新水体表面状态
        
        Args:
            dt: 时间增量
        """
        try:
            if not self.enabled:
                return
                
            # 更新时间
            self.update_config['last_update_time'] += dt
            
            # 检查是否需要更新
            update_interval = 1.0 / self.update_config['update_frequency']
            if self.update_config['last_update_time'] >= update_interval:
                # 更新表面几何
                self._update_surface_geometry(dt)
                
                # 更新纹理坐标
                self._update_texture_coordinates(dt)
                
                # 重置更新计时器
                self.update_config['last_update_time'] = 0.0
                self.update_config['needs_update'] = False
                
                # 更新统计信息
                self.geometry_stats['updates_performed'] += 1
                
        except Exception as e:
            print(f"✗ 水体表面管理器更新失败: {e}")
            import traceback
            traceback.print_exc()
            
    def _initialize_height_field(self):
        """初始化高度场"""
        try:
            res_x = self.mesh_config['resolution_x']
            res_z = self.mesh_config['resolution_z']
            
            # 初始化高度场
            self.height_field = np.zeros((res_x, res_z))
            
            # 初始化法线场
            self.normal_field = np.zeros((res_x, res_z, 3))
            
            print("✓ 高度场初始化完成")
            
        except Exception as e:
            print(f"✗ 高度场初始化失败: {e}")
            raise
            
    def _generate_initial_mesh(self):
        """生成初始网格"""
        try:
            self._clear_mesh_data()
            
            res_x = self.mesh_config['resolution_x']
            res_z = self.mesh_config['resolution_z']
            patch_size = self.mesh_config['patch_size']
            
            # 生成顶点
            for i in range(res_x):
                for j in range(res_z):
                    x = (i - res_x / 2) * patch_size / res_x
                    z = (j - res_z / 2) * patch_size / res_z
                    y = self.height_field[i, j] if self.height_field is not None else 0.0
                    
                    self.vertices.append((x, y, z))
                    
                    # 生成UV坐标
                    u = i / (res_x - 1) * self.uv_config['scale_u']
                    v = j / (res_z - 1) * self.uv_config['scale_v']
                    self.uvs.append((u, v))
                    
            # 生成索引（三角形列表）
            for i in range(res_x - 1):
                for j in range(res_z - 1):
                    # 第一个三角形
                    self.indices.append(i * res_z + j)
                    self.indices.append((i + 1) * res_z + j)
                    self.indices.append(i * res_z + (j + 1))
                    
                    # 第二个三角形
                    self.indices.append((i + 1) * res_z + j)
                    self.indices.append((i + 1) * res_z + (j + 1))
                    self.indices.append(i * res_z + (j + 1))
                    
            # 计算法线
            self._calculate_normals()
            
            # 更新统计信息
            self.geometry_stats['vertex_count'] = len(self.vertices)
            self.geometry_stats['triangle_count'] = len(self.indices) // 3
            self.geometry_stats['patch_count'] = (res_x - 1) * (res_z - 1)
            
            print("✓ 初始网格生成完成")
            
        except Exception as e:
            print(f"✗ 初始网格生成失败: {e}")
            raise
            
    def _clear_mesh_data(self):
        """清理网格数据"""
        try:
            self.vertices.clear()
            self.normals.clear()
            self.uvs.clear()
            self.indices.clear()
            
            if self.height_field is not None:
                self.height_field.fill(0)
                
            if self.normal_field is not None:
                self.normal_field.fill(0)
                
        except Exception as e:
            print(f"✗ 网格数据清理失败: {e}")
            
    def _update_surface_geometry(self, dt: float):
        """
        更新表面几何
        
        Args:
            dt: 时间增量
        """
        try:
            if not self.vertices or self.height_field is None:
                return
                
            res_x = self.mesh_config['resolution_x']
            res_z = self.mesh_config['resolution_z']
            
            # 更新顶点高度
            for i in range(res_x):
                for j in range(res_z):
                    vertex_index = i * res_z + j
                    if vertex_index < len(self.vertices):
                        x, y, z = self.vertices[vertex_index]
                        # 从高度场获取新高度
                        new_height = self.height_field[i, j]
                        self.vertices[vertex_index] = (x, new_height, z)
                        
            # 重新计算法线
            self._calculate_normals()
            
        except Exception as e:
            print(f"✗ 表面几何更新失败: {e}")
            
    def _calculate_normals(self):
        """计算顶点法线"""
        try:
            if not self.vertices or not self.indices:
                return
                
            # 清除旧法线
            self.normals.clear()
            
            # 初始化法线数组
            vertex_normals = [np.array([0.0, 0.0, 0.0]) for _ in self.vertices]
            
            # 计算每个三角形的法线并累加到顶点
            for i in range(0, len(self.indices), 3):
                i0 = self.indices[i]
                i1 = self.indices[i + 1]
                i2 = self.indices[i + 2]
                
                # 获取三角形顶点
                v0 = np.array(self.vertices[i0])
                v1 = np.array(self.vertices[i1])
                v2 = np.array(self.vertices[i2])
                
                # 计算边向量
                edge1 = v1 - v0
                edge2 = v2 - v0
                
                # 计算法线（叉积）
                normal = np.cross(edge1, edge2)
                
                # 归一化
                normal_length = np.linalg.norm(normal)
                if normal_length > 0:
                    normal = normal / normal_length
                    
                # 累加到顶点法线
                vertex_normals[i0] += normal
                vertex_normals[i1] += normal
                vertex_normals[i2] += normal
                
            # 归一化顶点法线并存储
            for normal in vertex_normals:
                normal_length = np.linalg.norm(normal)
                if normal_length > 0:
                    normal = normal / normal_length
                self.normals.append(tuple(normal))
                
        except Exception as e:
            print(f"✗ 法线计算失败: {e}")
            
    def _update_texture_coordinates(self, dt: float):
        """
        更新纹理坐标
        
        Args:
            dt: 时间增量
        """
        try:
            # 更新滚动偏移
            self.uv_config['scroll_u'] += self.uv_config['scroll_speed_u'] * dt
            self.uv_config['scroll_v'] += self.uv_config['scroll_speed_v'] * dt
            
            # 保持在[0,1)范围内
            self.uv_config['scroll_u'] %= 1.0
            self.uv_config['scroll_v'] %= 1.0
            
            # 更新UV坐标
            if self.uvs:
                res_x = self.mesh_config['resolution_x']
                res_z = self.mesh_config['resolution_z']
                
                for i in range(res_x):
                    for j in range(res_z):
                        vertex_index = i * res_z + j
                        if vertex_index < len(self.uvs):
                            u = (i / (res_x - 1) + self.uv_config['scroll_u']) * self.uv_config['scale_u']
                            v = (j / (res_z - 1) + self.uv_config['scroll_v']) * self.uv_config['scale_v']
                            self.uvs[vertex_index] = (u % 1.0, v % 1.0)
                            
        except Exception as e:
            print(f"✗ 纹理坐标更新失败: {e}")
            
    def update_height_field(self, new_height_field: np.ndarray):
        """
        更新高度场
        
        Args:
            new_height_field: 新的高度场数据
        """
        try:
            if self.height_field is None:
                self._initialize_height_field()
                
            # 复制新高度场数据
            if new_height_field.shape == self.height_field.shape:
                self.height_field[:, :] = new_height_field[:, :]
            else:
                # 如果尺寸不匹配，进行插值
                from scipy.interpolate import interp2d
                
                old_x = np.linspace(0, 1, self.height_field.shape[0])
                old_y = np.linspace(0, 1, self.height_field.shape[1])
                new_x = np.linspace(0, 1, new_height_field.shape[0])
                new_y = np.linspace(0, 1, new_height_field.shape[1])
                
                interpolator = interp2d(old_x, old_y, new_height_field, kind='linear')
                self.height_field[:, :] = interpolator(old_x, old_y)
                
            # 标记需要更新
            self.update_config['needs_update'] = True
            
        except Exception as e:
            print(f"✗ 高度场更新失败: {e}")
            
    def generate_wave_pattern(self, wave_parameters: Dict[str, float], 
                             time_value: float) -> np.ndarray:
        """
        生成波浪模式
        
        Args:
            wave_parameters: 波浪参数字典
            time_value: 时间值
            
        Returns:
            高度场数组
        """
        try:
            if self.height_field is None:
                self._initialize_height_field()
                
            res_x, res_z = self.height_field.shape
            patch_size = self.mesh_config['patch_size']
            
            # 获取波浪参数
            amplitude = wave_parameters.get('amplitude', 1.0)
            wavelength = wave_parameters.get('wavelength', 10.0)
            speed = wave_parameters.get('speed', 1.0)
            direction = wave_parameters.get('direction', 0.0)  # 弧度
            
            # 计算波向量
            wave_vector_x = 2 * math.pi / wavelength * math.cos(direction)
            wave_vector_z = 2 * math.pi / wavelength * math.sin(direction)
            
            # 生成波浪
            for i in range(res_x):
                for j in range(res_z):
                    # 计算世界坐标
                    x = (i - res_x / 2) * patch_size / res_x
                    z = (j - res_z / 2) * patch_size / res_z
                    
                    # 计算相位
                    phase = wave_vector_x * x + wave_vector_z * z - speed * time_value
                    
                    # 计算波浪高度
                    height = amplitude * math.sin(phase)
                    self.height_field[i, j] = height
                    
            return self.height_field.copy()
            
        except Exception as e:
            print(f"✗ 波浪模式生成失败: {e}")
            # 返回零高度场
            return np.zeros((res_x, res_z)) if self.height_field is not None else np.zeros((1, 1))
            
    def generate_gerstner_waves(self, waves: List[Dict[str, float]], 
                               time_value: float) -> np.ndarray:
        """
        生成Gerstner波浪（更真实的波浪模型）
        
        Args:
            waves: 波浪参数列表，每个包含'amplitude', 'wavelength', 'speed', 'direction'
            time_value: 时间值
            
        Returns:
            高度场数组
        """
        try:
            if self.height_field is None:
                self._initialize_height_field()
                
            res_x, res_z = self.height_field.shape
            patch_size = self.mesh_config['patch_size']
            
            # 清零高度场
            self.height_field.fill(0)
            
            # 为每个波浪累加贡献
            for wave in waves:
                amplitude = wave.get('amplitude', 1.0)
                wavelength = wave.get('wavelength', 10.0)
                speed = wave.get('speed', 1.0)
                direction = wave.get('direction', 0.0)
                
                # 计算波数和频率
                wavenumber = 2 * math.pi / wavelength
                frequency = speed * wavenumber
                
                # 计算波向量
                kx = wavenumber * math.cos(direction)
                kz = wavenumber * math.sin(direction)
                
                # 为每个点计算波浪贡献
                for i in range(res_x):
                    for j in range(res_z):
                        # 计算世界坐标
                        x = (i - res_x / 2) * patch_size / res_x
                        z = (j - res_z / 2) * patch_size / res_z
                        
                        # 计算相位
                        phase = kx * x + kz * z - frequency * time_value
                        
                        # Gerstner波浪公式
                        height_contribution = amplitude * math.sin(phase)
                        self.height_field[i, j] += height_contribution
                        
            return self.height_field.copy()
            
        except Exception as e:
            print(f"✗ Gerstner波浪生成失败: {e}")
            return np.zeros((res_x, res_z)) if self.height_field is not None else np.zeros((1, 1))
            
    def get_mesh_data(self) -> Dict[str, List[Tuple[float, float, float]]]:
        """
        获取网格数据
        
        Returns:
            包含顶点、法线、UV坐标和索引的字典
        """
        return {
            'vertices': self.vertices.copy(),
            'normals': self.normals.copy(),
            'uvs': self.uvs.copy(),
            'indices': self.indices.copy()
        }
        
    def get_height_at(self, x: float, z: float) -> float:
        """
        获取指定位置的高度
        
        Args:
            x, z: 世界坐标
            
        Returns:
            高度值
        """
        try:
            if self.height_field is None:
                return 0.0
                
            res_x, res_z = self.height_field.shape
            patch_size = self.mesh_config['patch_size']
            
            # 转换到网格坐标
            grid_x = (x / patch_size + 0.5) * res_x
            grid_z = (z / patch_size + 0.5) * res_z
            
            # 边界检查
            if grid_x < 0 or grid_x >= res_x or grid_z < 0 or grid_z >= res_z:
                return 0.0
                
            # 简单的双线性插值
            i = int(grid_x)
            j = int(grid_z)
            fx = grid_x - i
            fz = grid_z - j
            
            # 边界处理
            i1 = min(i + 1, res_x - 1)
            j1 = min(j + 1, res_z - 1)
            
            # 双线性插值
            h00 = self.height_field[i, j]
            h10 = self.height_field[i1, j]
            h01 = self.height_field[i, j1]
            h11 = self.height_field[i1, j1]
            
            h0 = h00 * (1 - fx) + h10 * fx
            h1 = h01 * (1 - fx) + h11 * fx
            
            return h0 * (1 - fz) + h1 * fz
            
        except Exception as e:
            print(f"✗ 高度获取失败: {e}")
            return 0.0
            
    def set_mesh_config(self, config: Dict[str, Any]):
        """
        设置网格配置
        
        Args:
            config: 网格配置字典
        """
        try:
            old_res_x = self.mesh_config['resolution_x']
            old_res_z = self.mesh_config['resolution_z']
            
            self.mesh_config.update(config)
            
            new_res_x = self.mesh_config['resolution_x']
            new_res_z = self.mesh_config['resolution_z']
            
            # 如果分辨率改变，重新生成网格
            if old_res_x != new_res_x or old_res_z != new_res_z:
                self._generate_initial_mesh()
                
            print(f"✓ 网格配置已更新: {self.mesh_config}")
        except Exception as e:
            print(f"✗ 网格配置设置失败: {e}")
            
    def get_mesh_config(self) -> Dict[str, Any]:
        """
        获取网格配置
        
        Returns:
            网格配置字典
        """
        return self.mesh_config.copy()
        
    def set_uv_config(self, config: Dict[str, float]):
        """
        设置UV配置
        
        Args:
            config: UV配置字典
        """
        try:
            self.uv_config.update(config)
            print(f"✓ UV配置已更新: {self.uv_config}")
        except Exception as e:
            print(f"✗ UV配置设置失败: {e}")
            
    def get_uv_config(self) -> Dict[str, float]:
        """
        获取UV配置
        
        Returns:
            UV配置字典
        """
        return self.uv_config.copy()
        
    def get_geometry_stats(self) -> Dict[str, int]:
        """
        获取几何统计信息
        
        Returns:
            几何统计字典
        """
        return self.geometry_stats.copy()
        
    def reset_geometry_stats(self):
        """重置几何统计信息"""
        try:
            self.geometry_stats = {
                'vertex_count': len(self.vertices),
                'triangle_count': len(self.indices) // 3,
                'patch_count': (self.mesh_config['resolution_x'] - 1) * (self.mesh_config['resolution_z'] - 1),
                'updates_performed': 0
            }
            print("✓ 几何统计信息已重置")
        except Exception as e:
            print(f"✗ 几何统计信息重置失败: {e}")
            
    def apply_displacement_map(self, displacement_map: np.ndarray):
        """
        应用位移贴图
        
        Args:
            displacement_map: 位移贴图数据
        """
        try:
            self.update_height_field(displacement_map)
            print("✓ 位移贴图已应用")
        except Exception as e:
            print(f"✗ 位移贴图应用失败: {e}")