"""
环境感知和响应管理器
提供群体对环境的感知能力和响应机制
"""

from panda3d.core import Vec3
import random
import math
from typing import Dict, List, Tuple, Optional, Any


class EnvironmentSensor:
    """
    环境传感器类
    模拟群体成员的环境感知能力
    """
    
    def __init__(self, sensor_range: float = 15.0, sensor_accuracy: float = 0.9):
        """
        初始化传感器
        
        :param sensor_range: 传感器感知范围
        :param sensor_accuracy: 传感器精度 (0.0-1.0)
        """
        self.sensor_range = sensor_range
        self.sensor_accuracy = sensor_accuracy
        self.sensor_noise = 1.0 - sensor_accuracy  # 传感器噪声水平
        
    def sense_environment(self, position: Vec3, environment_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        感知环境
        返回在指定位置感知到的环境信息
        
        :param position: 感知位置
        :param environment_data: 环境数据
        :return: 感知到的环境信息
        """
        sensed_data = {}
        
        # 感知障碍物
        sensed_data['obstacles'] = self._sense_obstacles(position, environment_data.get('obstacles', []))
        
        # 感知其他群体
        sensed_data['other_swarms'] = self._sense_other_swarms(position, environment_data.get('swarms', []))
        
        # 感知捕食者
        sensed_data['predators'] = self._sense_predators(position, environment_data.get('predators', []))
        
        # 感知天气/环境条件
        sensed_data['weather'] = self._sense_weather(position, environment_data.get('weather', {}))
        
        # 感知资源点
        sensed_data['resources'] = self._sense_resources(position, environment_data.get('resources', []))
        
        # 感知危险区域
        sensed_data['hazards'] = self._sense_hazards(position, environment_data.get('hazards', []))
        
        # 添加传感器噪声
        sensed_data = self._add_sensor_noise(sensed_data)
        
        return sensed_data
        
    def _sense_obstacles(self, position: Vec3, obstacles: List[Dict]) -> List[Dict]:
        """
        感知障碍物
        """
        sensed_obstacles = []
        for obstacle in obstacles:
            distance = (position - obstacle['position']).length()
            if distance <= self.sensor_range:
                # 计算感知误差
                error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
                sensed_obstacle = obstacle.copy()
                sensed_obstacle['distance'] = distance * error_factor
                sensed_obstacle['direction'] = (obstacle['position'] - position).normalized()
                sensed_obstacles.append(sensed_obstacle)
                
        return sensed_obstacles
        
    def _sense_other_swarms(self, position: Vec3, swarms: List[Dict]) -> List[Dict]:
        """
        感知其他群体
        """
        sensed_swarms = []
        for swarm in swarms:
            # 计算群体中心位置
            if 'members' in swarm and len(swarm['members']) > 0:
                center = Vec3(0, 0, 0)
                for member in swarm['members']:
                    center += member['position']
                center /= len(swarm['members'])
                
                distance = (position - center).length()
                if distance <= self.sensor_range:
                    error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
                    sensed_swarm = {
                        'id': swarm['id'],
                        'type': swarm['type'],
                        'distance': distance * error_factor,
                        'direction': (center - position).normalized(),
                        'size': len(swarm['members'])
                    }
                    sensed_swarms.append(sensed_swarm)
                    
        return sensed_swarms
        
    def _sense_predators(self, position: Vec3, predators: List[Dict]) -> List[Dict]:
        """
        感知捕食者
        """
        sensed_predators = []
        for predator in predators:
            distance = (position - predator['position']).length()
            if distance <= self.sensor_range:
                error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
                sensed_predator = {
                    'position': predator['position'],
                    'distance': distance * error_factor,
                    'direction': (predator['position'] - position).normalized(),
                    'velocity': predator.get('velocity', Vec3(0, 0, 0))
                }
                sensed_predators.append(sensed_predator)
                
        return sensed_predators
        
    def _sense_weather(self, position: Vec3, weather: Dict) -> Dict:
        """
        感知天气/环境条件
        """
        # 天气信息通常对整个区域是相同的，但可能有局部变化
        sensed_weather = weather.copy()
        
        # 添加局部变化
        if 'wind' in sensed_weather:
            wind = sensed_weather['wind']
            # 添加传感器噪声
            noise_x = random.uniform(-self.sensor_noise, self.sensor_noise) * wind['direction'].x
            noise_y = random.uniform(-self.sensor_noise, self.sensor_noise) * wind['direction'].y
            sensed_weather['wind']['direction'] = Vec3(
                wind['direction'].x + noise_x,
                wind['direction'].y + noise_y,
                wind['direction'].z
            ).normalized()
            
        return sensed_weather
        
    def _sense_resources(self, position: Vec3, resources: List[Dict]) -> List[Dict]:
        """
        感知资源点
        """
        sensed_resources = []
        for resource in resources:
            distance = (position - resource['position']).length()
            if distance <= self.sensor_range:
                error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
                sensed_resource = resource.copy()
                sensed_resource['distance'] = distance * error_factor
                sensed_resource['direction'] = (resource['position'] - position).normalized()
                sensed_resources.append(sensed_resource)
                
        return sensed_resources
        
    def _sense_hazards(self, position: Vec3, hazards: List[Dict]) -> List[Dict]:
        """
        感知危险区域
        """
        sensed_hazards = []
        for hazard in hazards:
            distance = (position - hazard['position']).length()
            if distance <= self.sensor_range:
                error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
                sensed_hazard = hazard.copy()
                sensed_hazard['distance'] = distance * error_factor
                sensed_hazard['direction'] = (hazard['position'] - position).normalized()
                sensed_hazards.append(sensed_hazard)
                
        return sensed_hazards
        
    def _add_sensor_noise(self, sensed_data: Dict) -> Dict:
        """
        为感知数据添加噪声
        """
        # 在实际应用中，可以对某些数值添加噪声
        return sensed_data


class EnvironmentalResponseSystem:
    """
    环境响应系统
    根据感知到的环境信息决定群体的响应行为
    """
    
    def __init__(self, config):
        self.config = config
        
    def calculate_response(self, member: Dict, sensed_data: Dict, 
                          current_velocity: Vec3, current_position: Vec3) -> Vec3:
        """
        根据感知数据计算响应力
        """
        response_force = Vec3(0, 0, 0)
        
        # 避开障碍物
        response_force += self._avoid_obstacles(sensed_data['obstacles'], current_position, current_velocity)
        
        # 应对捕食者
        response_force += self._respond_to_predators(sensed_data['predators'], current_position)
        
        # 寻找资源
        response_force += self._seek_resources(sensed_data['resources'], current_position)
        
        # 避开危险区域
        response_force += self._avoid_hazards(sensed_data['hazards'], current_position)
        
        # 适应天气条件
        response_force += self._adapt_to_weather(sensed_data['weather'], current_position, current_velocity)
        
        # 处理其他群体
        response_force += self._respond_to_other_swarms(sensed_data['other_swarms'], current_position)
        
        return response_force
        
    def _avoid_obstacles(self, obstacles: List[Dict], position: Vec3, velocity: Vec3) -> Vec3:
        """
        避开障碍物
        """
        avoidance_force = Vec3(0, 0, 0)
        
        for obstacle in obstacles:
            distance = obstacle['distance']
            if distance < 5.0:  # 在近距离内才需要避障
                # 计算避障方向（远离障碍物）
                direction = obstacle['direction'] * -1
                # 距离越近，避障力越大
                magnitude = max(0, 5.0 - distance) / 5.0
                avoidance_force += direction * magnitude
                
        return avoidance_force * self.config.get("obstacle_response_weight", 2.0)
        
    def _respond_to_predators(self, predators: List[Dict], position: Vec3) -> Vec3:
        """
        响应捕食者
        """
        flee_force = Vec3(0, 0, 0)
        
        for predator in predators:
            distance = predator['distance']
            if distance < self.config.get("predator_radius", 15.0):
                # 逃离捕食者方向
                direction = predator['direction'] * -1
                # 距离越近，逃离力越大
                magnitude = max(0, (self.config.get("predator_radius", 15.0) - distance) / self.config.get("predator_radius", 15.0))
                flee_force += direction * magnitude
                
        return flee_force * self.config.get("predator_response_weight", 3.0)
        
    def _seek_resources(self, resources: List[Dict], position: Vec3) -> Vec3:
        """
        寻找资源
        """
        if not resources:
            return Vec3(0, 0, 0)
            
        # 寻找最近的资源
        nearest_resource = min(resources, key=lambda r: r['distance'])
        distance = nearest_resource['distance']
        
        if distance < 20.0:  # 在一定范围内才寻求资源
            direction = nearest_resource['direction']
            # 距离越远，寻求力越大，当接近时减小
            magnitude = max(0.1, 1.0 - distance/20.0)
            seek_force = direction * magnitude
            return seek_force * self.config.get("resource_seek_weight", 0.5)  # 使用配置中的权重
            
        return Vec3(0, 0, 0)
        
    def _avoid_hazards(self, hazards: List[Dict], position: Vec3) -> Vec3:
        """
        避开危险区域
        """
        avoidance_force = Vec3(0, 0, 0)
        
        for hazard in hazards:
            distance = hazard['distance']
            hazard_radius = hazard.get('radius', 5.0)
            if distance < hazard_radius * 2:  # 在危险区域两倍半径内
                direction = hazard['direction'] * -1  # 远离危险
                magnitude = max(0, (hazard_radius * 2 - distance) / (hazard_radius * 2))
                avoidance_force += direction * magnitude
                
        return avoidance_force * self.config.get("hazard_avoid_weight", 3.0)  # 使用配置中的权重
        
    def _adapt_to_weather(self, weather: Dict, position: Vec3, velocity: Vec3) -> Vec3:
        """
        适应天气条件
        """
        if not weather or 'wind' not in weather:
            return Vec3(0, 0, 0)
            
        wind = weather['wind']
        wind_force = wind['direction'] * wind['strength']
        
        # 根据成员类型调整对天气的响应
        member_type = position  # 位置参数用于占位
        adaptation_factor = 1.0
        
        # 实际应用中，可以根据成员类型调整响应
        if hasattr(self, 'member_type'):
            if self.member_type == "鸟类":
                adaptation_factor = 0.7  # 鸟类受风影响较小
            elif self.member_type == "昆虫":
                adaptation_factor = 1.5  # 昆虫受风影响较大
                
        return wind_force * adaptation_factor
        
    def _respond_to_other_swarms(self, other_swarms: List[Dict], position: Vec3) -> Vec3:
        """
        响应其他群体
        根据群体类型和关系决定响应
        """
        response_force = Vec3(0, 0, 0)
        
        for swarm in other_swarms:
            distance = swarm['distance']
            swarm_type = swarm['type']
            
            if distance < 10.0:  # 在近距离内响应
                direction = swarm['direction']
                
                # 根据群体类型决定响应
                if swarm_type == "predator":  # 假设这是捕食者群体
                    # 逃离
                    response_force += direction * -1 * max(0, (10.0 - distance) / 10.0) * 2.0
                elif swarm_type == "same":  # 同类群体
                    # 可能靠近或远离，取决于密度
                    response_force += direction * max(0, (distance - 5.0) / 5.0) * 0.5
                else:  # 其他类型
                    # 中性响应
                    response_force += direction * 0.1
                    
        return response_force


class EnvironmentManager:
    """
    环境管理器
    管理整个环境的状态和变化
    """
    
    def __init__(self, config):
        self.config = config
        self.sensors = {}
        self.response_system = EnvironmentalResponseSystem(config)
        self.environment_state = {
            'obstacles': [],
            'swarms': [],
            'predators': [],
            'weather': {},
            'resources': [],
            'hazards': [],
            'time_of_day': 12.0,  # 24小时制时间
            'season': 'spring'
        }
        self.weather_effects = {
            'wind': {'direction': Vec3(0, 1, 0), 'strength': 0.2},
            'temperature': 20.0,
            'precipitation': 0.0
        }
        
    def add_sensor(self, member_id: str, sensor_range: float = None, sensor_accuracy: float = None):
        """
        为成员添加传感器
        """
        if sensor_range is None:
            sensor_range = self.config.get("sensor_range", 15.0)
        if sensor_accuracy is None:
            sensor_accuracy = self.config.get("sensor_accuracy", 0.9)
            
        self.sensors[member_id] = EnvironmentSensor(sensor_range, sensor_accuracy)
        
    def update_environment_state(self, obstacles: List[Dict], swarms: List[Dict], 
                                predators: List[Dict], resources: List[Dict], 
                                hazards: List[Dict]):
        """
        更新环境状态
        """
        self.environment_state['obstacles'] = obstacles
        self.environment_state['swarms'] = swarms
        self.environment_state['predators'] = predators
        self.environment_state['resources'] = resources
        self.environment_state['hazards'] = hazards
        
        # 更新天气效果（简化模拟）
        self._update_weather_effects()
        
    def _update_weather_effects(self):
        """
        更新天气效果（随时间变化）
        """
        # 简单的天气变化模拟
        time_factor = math.sin(self.environment_state['time_of_day'] * math.pi / 12)  # 0-24小时周期
        self.weather_effects['wind']['strength'] = 0.2 + abs(time_factor) * 0.3
        
        # 温度变化
        self.weather_effects['temperature'] = 15 + time_factor * 10
        
        # 更新环境状态
        self.environment_state['weather'] = self.weather_effects.copy()
        
    def get_environmental_response(self, member: Dict, position: Vec3, velocity: Vec3) -> Vec3:
        """
        获取成员的环境响应力
        """
        member_id = id(member)
        
        # 如果成员没有传感器，添加一个默认传感器
        if member_id not in self.sensors:
            self.add_sensor(member_id)
            
        # 使用传感器感知环境
        sensed_data = self.sensors[member_id].sense_environment(position, self.environment_state)
        
        # 计算环境响应
        response_force = self.response_system.calculate_response(
            member, sensed_data, velocity, position
        )
        
        return response_force
        
    def advance_time(self, dt: float):
        """
        推进环境时间
        """
        self.environment_state['time_of_day'] += dt * 0.1  # 时间流逝速度调整
        if self.environment_state['time_of_day'] >= 24.0:
            self.environment_state['time_of_day'] -= 24.0
            
    def add_resource(self, position: Vec3, resource_type: str = "food", amount: float = 100.0):
        """
        添加资源点
        """
        resource = {
            'position': position,
            'type': resource_type,
            'amount': amount,
            'radius': 3.0
        }
        self.environment_state['resources'].append(resource)
        return resource
        
    def add_hazard(self, position: Vec3, hazard_type: str = "toxic", radius: float = 5.0):
        """
        添加危险区域
        """
        hazard = {
            'position': position,
            'type': hazard_type,
            'radius': radius
        }
        self.environment_state['hazards'].append(hazard)
        return hazard
        
    def get_environment_info(self) -> Dict:
        """
        获取环境信息
        """
        return self.environment_state.copy()
        
    def update_environment_dynamics(self):
        """
        更新环境动态变化
        如资源消耗、天气变化等
        """
        # 更新资源（简化模拟资源消耗）
        for i, resource in enumerate(self.environment_state['resources']):
            if resource['amount'] > 0:
                # 模拟资源随时间缓慢恢复
                resource['amount'] = min(resource['amount'] + 0.01, 100.0)
                
        # 更新天气
        self._update_weather_effects()