"""
粒子物理系统
负责粒子的物理模拟和环境交互
"""

import math
import random
from typing import List, Dict, Optional
from panda3d.core import Vec3, Point3, BitMask32
from panda3d.bullet import BulletWorld, BulletRigidBodyNode, BulletSphereShape

from .particle_emitter import ParticleEmitter, Particle

class ParticlePhysics:
    """
    粒子物理系统
    处理粒子的物理模拟，包括重力、碰撞、力场等
    """
    
    def __init__(self, world):
        """
        初始化粒子物理系统
        
        Args:
            world: 3D世界对象
        """
        self.world = world
        self.enabled = False
        
        # 物理世界（如果可用）
        self.bullet_world = None
        self._init_bullet_world()
        
        # 全局物理参数
        self.gravity = Vec3(0, 0, -9.81)
        self.air_density = 1.225  # kg/m³
        self.wind_velocity = Vec3(0, 0, 0)
        self.wind_turbulence = 0.0
        
        # 环境力场
        self.force_fields = []
        
        # 碰撞检测
        self.collision_enabled = True
        self.ground_level = 0.0
        self.bounce_damping = 0.8
        
        # 注册的发射器
        self.registered_emitters: Dict[str, ParticleEmitter] = {}
        
        # 物理统计
        self.physics_stats = {
            'collision_checks': 0,
            'collisions_detected': 0,
            'force_calculations': 0,
            'physics_time': 0.0
        }
        
        print("✓ 粒子物理系统初始化完成")
        
    def _init_bullet_world(self):
        """初始化Bullet物理世界"""
        try:
            # 尝试获取现有的物理世界
            if hasattr(self.world, 'physics_world') and self.world.physics_world:
                self.bullet_world = self.world.physics_world.bullet_world
                print("✓ 使用现有Bullet物理世界")
            else:
                print("⚠ 未找到Bullet物理世界，使用简化物理模拟")
        except Exception as e:
            print(f"⚠ Bullet物理世界初始化失败: {e}")
            
    def enable(self):
        """启用物理系统"""
        if self.enabled:
            return
            
        self.enabled = True
        print("✓ 粒子物理系统已启用")
        
    def disable(self):
        """禁用物理系统"""
        if not self.enabled:
            return
            
        self.enabled = False
        print("✓ 粒子物理系统已禁用")
        
    def cleanup(self):
        """清理资源"""
        self.disable()
        self.registered_emitters.clear()
        self.force_fields.clear()
        
    def register_emitter(self, emitter: ParticleEmitter):
        """注册粒子发射器"""
        self.registered_emitters[emitter.emitter_id] = emitter
        
    def unregister_emitter(self, emitter: ParticleEmitter):
        """注销粒子发射器"""
        emitter_id = emitter.emitter_id
        if emitter_id in self.registered_emitters:
            del self.registered_emitters[emitter_id]
            
    def update(self, dt: float):
        """更新物理模拟"""
        if not self.enabled:
            return
            
        import time
        start_time = time.time()
            
        # 重置统计信息
        self.physics_stats['collision_checks'] = 0
        self.physics_stats['collisions_detected'] = 0
        self.physics_stats['force_calculations'] = 0
        
        # 更新每个发射器的粒子物理
        for emitter in self.registered_emitters.values():
            self._update_emitter_physics(emitter, dt)
            
        self.physics_stats['physics_time'] = time.time() - start_time
            
    def _update_emitter_physics(self, emitter: ParticleEmitter, dt: float):
        """更新发射器的粒子物理"""
        particles = emitter.get_particles()
        
        for particle in particles:
            if not particle.is_alive():
                continue
                
            # 计算作用在粒子上的所有力
            total_force = self._calculate_particle_forces(particle)
            
            # 应用力到粒子
            if particle.mass > 0:
                acceleration = total_force / particle.mass
                particle.acceleration = acceleration
            else:
                particle.acceleration = Vec3(0, 0, 0)
                
            # 更新速度和位置（使用欧拉积分）
            particle.velocity += particle.acceleration * dt
            particle.position += particle.velocity * dt
            
            # 碰撞检测
            if self.collision_enabled:
                self._handle_particle_collision(particle, dt)
                
            self.physics_stats['force_calculations'] += 1
            
    def _calculate_particle_forces(self, particle: Particle) -> Vec3:
        """计算作用在粒子上的所有力"""
        total_force = Vec3(0, 0, 0)
        
        # 重力
        gravity_force = self.gravity * particle.mass * particle.gravity_scale
        total_force += gravity_force
        
        # 空气阻力
        drag_force = self._calculate_drag_force(particle)
        total_force += drag_force
        
        # 风力
        wind_force = self._calculate_wind_force(particle)
        total_force += wind_force
        
        # 力场
        for force_field in self.force_fields:
            field_force = self._calculate_force_field(particle, force_field)
            total_force += field_force
            
        return total_force
        
    def _calculate_drag_force(self, particle: Particle) -> Vec3:
        """计算空气阻力"""
        if particle.velocity.lengthSquared() == 0:
            return Vec3(0, 0, 0)
            
        # 简化的阻力模型: F = -k * v * |v|
        velocity_magnitude = particle.velocity.length()
        drag_coefficient = particle.air_resistance
        
        drag_force = -particle.velocity * drag_coefficient * velocity_magnitude
        return drag_force
        
    def _calculate_wind_force(self, particle: Particle) -> Vec3:
        """计算风力"""
        if self.wind_velocity.lengthSquared() == 0 and self.wind_turbulence == 0:
            return Vec3(0, 0, 0)
            
        # 相对风速
        relative_wind = Vec3(self.wind_velocity)
        
        # 添加湍流
        if self.wind_turbulence > 0:
            turbulence = Vec3(
                random.uniform(-self.wind_turbulence, self.wind_turbulence),
                random.uniform(-self.wind_turbulence, self.wind_turbulence),
                random.uniform(-self.wind_turbulence, self.wind_turbulence)
            )
            relative_wind += turbulence
            
        # 风力 = 空气密度 * 阻力系数 * 面积 * 相对风速²
        # 简化为: F = k * relative_wind * |relative_wind|
        wind_magnitude = relative_wind.length()
        if wind_magnitude > 0:
            wind_coefficient = 0.1  # 可调参数
            wind_force = relative_wind * wind_coefficient * wind_magnitude
            return wind_force
            
        return Vec3(0, 0, 0)
        
    def _calculate_force_field(self, particle: Particle, force_field: Dict) -> Vec3:
        """计算力场作用力"""
        field_type = force_field.get('type', 'point')
        field_position = force_field.get('position', Point3(0, 0, 0))
        field_strength = force_field.get('strength', 1.0)
        field_radius = force_field.get('radius', 10.0)
        
        # 计算到力场中心的距离
        to_field = field_position - particle.position
        distance = to_field.length()
        
        if distance > field_radius or distance == 0:
            return Vec3(0, 0, 0)
            
        if field_type == 'point':
            # 点力场（引力/斥力）
            direction = to_field / distance
            # 力的大小与距离平方成反比
            force_magnitude = field_strength / (distance * distance + 0.01)  # 添加小值避免除零
            return direction * force_magnitude
            
        elif field_type == 'vortex':
            # 涡流力场
            axis = force_field.get('axis', Vec3(0, 0, 1))
            axis.normalize()
            
            # 计算切向力
            radial_vector = to_field - to_field.dot(axis) * axis
            if radial_vector.length() > 0:
                radial_vector.normalize()
                tangent = axis.cross(radial_vector)
                force_magnitude = field_strength / (distance + 0.01)
                return tangent * force_magnitude
                
        elif field_type == 'directional':
            # 方向力场（如风）
            direction = force_field.get('direction', Vec3(0, 0, 1))
            direction.normalize()
            falloff = max(0, 1.0 - distance / field_radius)
            return direction * field_strength * falloff
            
        return Vec3(0, 0, 0)
        
    def _handle_particle_collision(self, particle: Particle, dt: float):
        """处理粒子碰撞"""
        self.physics_stats['collision_checks'] += 1
        
        # 简单的地面碰撞检测
        if particle.position.z <= self.ground_level and particle.velocity.z < 0:
            # 反弹
            particle.velocity.z = -particle.velocity.z * particle.bounce_factor * self.bounce_damping
            particle.position.z = self.ground_level + 0.01  # 稍微抬高避免穿透
            
            # 应用摩擦力
            friction = 0.9
            particle.velocity.x *= friction
            particle.velocity.y *= friction
            
            self.physics_stats['collisions_detected'] += 1
            
        # 墙壁碰撞检测
        # 假设有一个边界盒子 [-50, 50] x [-50, 50] x [0, 100]
        boundary_min = Point3(-50, -50, 0)
        boundary_max = Point3(50, 50, 100)
        
        # X轴边界
        if particle.position.x <= boundary_min.x and particle.velocity.x < 0:
            particle.velocity.x = -particle.velocity.x * particle.bounce_factor
            particle.position.x = boundary_min.x + 0.01
            self.physics_stats['collisions_detected'] += 1
        elif particle.position.x >= boundary_max.x and particle.velocity.x > 0:
            particle.velocity.x = -particle.velocity.x * particle.bounce_factor
            particle.position.x = boundary_max.x - 0.01
            self.physics_stats['collisions_detected'] += 1
            
        # Y轴边界
        if particle.position.y <= boundary_min.y and particle.velocity.y < 0:
            particle.velocity.y = -particle.velocity.y * particle.bounce_factor
            particle.position.y = boundary_min.y + 0.01
            self.physics_stats['collisions_detected'] += 1
        elif particle.position.y >= boundary_max.y and particle.velocity.y > 0:
            particle.velocity.y = -particle.velocity.y * particle.bounce_factor
            particle.position.y = boundary_max.y - 0.01
            self.physics_stats['collisions_detected'] += 1
            
        # Z轴上边界
        if particle.position.z >= boundary_max.z and particle.velocity.z > 0:
            particle.velocity.z = -particle.velocity.z * particle.bounce_factor
            particle.position.z = boundary_max.z - 0.01
            self.physics_stats['collisions_detected'] += 1
            
        # 如果有Bullet物理世界，可以进行更复杂的碰撞检测
        if self.bullet_world:
            self._handle_bullet_collision(particle, dt)
            
    def _handle_bullet_collision(self, particle: Particle, dt: float):
        """使用Bullet进行碰撞检测"""
        # 这里可以实现更复杂的碰撞检测
        # 由于粒子数量可能很大，通常只对重要粒子进行精确碰撞检测
        pass
        
    def add_force_field(self, field_type: str, position: Point3, 
                       strength: float, radius: float, **kwargs):
        """添加力场"""
        force_field = {
            'type': field_type,
            'position': position,
            'strength': strength,
            'radius': radius,
            **kwargs
        }
        self.force_fields.append(force_field)
        print(f"✓ 添加力场: {field_type} at {position}")
        
    def remove_force_field(self, index: int):
        """移除力场"""
        if 0 <= index < len(self.force_fields):
            del self.force_fields[index]
            print(f"✓ 移除力场: {index}")
            
    def clear_force_fields(self):
        """清除所有力场"""
        self.force_fields.clear()
        print("✓ 清除所有力场")
        
    def set_gravity(self, gravity: Vec3):
        """设置重力"""
        self.gravity = gravity
        
    def set_wind(self, velocity: Vec3, turbulence: float = 0.0):
        """设置风力"""
        self.wind_velocity = velocity
        self.wind_turbulence = turbulence
        
    def set_ground_level(self, level: float):
        """设置地面高度"""
        self.ground_level = level
        
    def set_collision_enabled(self, enabled: bool):
        """设置碰撞检测"""
        self.collision_enabled = enabled
        
    def get_physics_stats(self) -> Dict:
        """获取物理统计信息"""
        return self.physics_stats.copy()
        
    def clear_all(self):
        """清除所有物理状态"""
        self.force_fields.clear()
        
    # 预设力场创建方法
    def create_gravity_well(self, position: Point3, strength: float = 10.0, radius: float = 5.0):
        """创建重力井"""
        self.add_force_field('point', position, strength, radius)
        
    def create_repulsion_field(self, position: Point3, strength: float = -10.0, radius: float = 3.0):
        """创建排斥力场"""
        self.add_force_field('point', position, strength, radius)
        
    def create_vortex(self, position: Point3, strength: float = 5.0, 
                     radius: float = 4.0, axis: Vec3 = None):
        """创建涡流"""
        if axis is None:
            axis = Vec3(0, 0, 1)
        self.add_force_field('vortex', position, strength, radius, axis=axis)
        
    def create_wind_zone(self, position: Point3, direction: Vec3, 
                        strength: float = 2.0, radius: float = 8.0):
        """创建风区"""
        direction.normalize()
        self.add_force_field('directional', position, strength, radius, direction=direction)