"""
音频编辑器
提供可视化编辑音频场景和参数的功能
"""

from typing import Dict, List, Any, Optional
from panda3d.core import NodePath, Vec3

class AudioEditor:
    """
    音频编辑器
    提供可视化编辑音频场景和参数的功能
    """
    
    def __init__(self, plugin, world):
        """
        初始化音频编辑器
        
        Args:
            plugin: 3D音频插件实例
            world: 3D世界实例
        """
        self.plugin = plugin
        self.world = world
        self.visible = False
        self.editor_node = None
        self.zone_visualizations = {}
        self.sound_visualizations = {}
        self.selected_item = None
        
        # 编辑器状态
        self.edit_mode = False
        self.selected_tool = "select"  # select, add_sound, add_zone
        self.grid_size = 5.0
        self.snap_to_grid = True
        
        # GUI元素
        self.gui_elements = []
        self.tool_buttons = {}
        
    def toggle_visibility(self):
        """切换编辑器可见性"""
        if self.visible:
            self.hide()
        else:
            self.show()
            
    def show(self):
        """显示编辑器"""
        if self.visible:
            return
            
        self.visible = True
        self._create_editor_visualization()
        self._create_editor_gui()
        print("✓ 音频编辑器已显示")
        
    def hide(self):
        """隐藏编辑器"""
        if not self.visible:
            return
            
        self.visible = False
        self._cleanup_editor_visualization()
        self._cleanup_editor_gui()
        print("✓ 音频编辑器已隐藏")
        
    def _create_editor_visualization(self):
        """创建编辑器可视化元素"""
        try:
            if not self.world.render:
                return
                
            # 创建编辑器根节点
            self.editor_node = self.world.render.attachNewNode("audio_editor")
            
            # 可视化现有的音频区域
            self._visualize_zones()
            
            # 可视化现有的音频源
            self._visualize_sounds()
            
        except Exception as e:
            print(f"⚠ 编辑器可视化创建失败: {e}")
            
    def _cleanup_editor_visualization(self):
        """清理编辑器可视化元素"""
        try:
            # 清理区域可视化
            for zone_node in self.zone_visualizations.values():
                zone_node.removeNode()
            self.zone_visualizations.clear()
            
            # 清理音源可视化
            for sound_node in self.sound_visualizations.values():
                sound_node.removeNode()
            self.sound_visualizations.clear()
            
            # 清理编辑器根节点
            if self.editor_node:
                self.editor_node.removeNode()
                self.editor_node = None
                
        except Exception as e:
            print(f"⚠ 编辑器可视化清理失败: {e}")
            
    def _visualize_zones(self):
        """可视化音频区域"""
        if not self.editor_node:
            return
            
        # 获取所有区域信息
        zones_info = self.plugin.environment_audio_manager.get_all_zones_info()
        
        for zone_info in zones_info:
            zone_id = zone_info['id']
            position = zone_info['position']
            radius = zone_info['radius']
            
            # 创建区域可视化节点
            zone_node = self.editor_node.attachNewNode(f"zone_{zone_id}")
            zone_node.setPos(position[0], position[1], position[2])
            
            # 这里应该创建一个球体或其他可视化表示
            # 为简化起见，我们只是存储节点
            self.zone_visualizations[zone_id] = zone_node
            
    def _visualize_sounds(self):
        """可视化音频源"""
        if not self.editor_node:
            return
            
        # 获取所有音频源
        for sound_id, sound_info in self.plugin.audio_source_manager.audio_sources.items():
            position = sound_info['position']
            
            # 创建音源可视化节点
            sound_node = self.editor_node.attachNewNode(f"sound_{sound_id}")
            sound_node.setPos(position[0], position[1], position[2])
            
            # 这里应该创建一个图标或其他可视化表示
            # 为简化起见，我们只是存储节点
            self.sound_visualizations[sound_id] = sound_node
            
    def _create_editor_gui(self):
        """创建编辑器GUI"""
        try:
            if not hasattr(self.world, 'gui_manager') or not self.world.gui_manager:
                print("⚠ GUI管理器不可用，无法创建编辑器界面")
                return
                
            gui_manager = self.world.gui_manager
            
            # 创建编辑器面板标题
            panel = gui_manager.createGUIButton(
                pos=(0.7, 0, 0.95), 
                text="音频编辑器", 
                size=0.06
            )
            self.gui_elements.append(panel)
            
            # 创建工具按钮
            tools = [
                ("选择", "select"),
                ("添加音效", "add_sound"),
                ("添加区域", "add_zone")
            ]
            
            for i, (name, tool) in enumerate(tools):
                button = gui_manager.createGUIButton(
                    pos=(0.7, 0, 0.88 - i * 0.06), 
                    text=name, 
                    size=0.04
                )
                self.gui_elements.append(button)
                self.tool_buttons[tool] = button
                self.world.accept(f"audio_tool_{tool}", 
                                lambda t=tool: self.set_edit_tool(t))
                
            # 创建编辑功能按钮
            functions = [
                ("网格对齐", self.toggle_grid_snap),
                ("播放测试音", self.play_test_sound),
                ("环境音效", self.toggle_environment_audio),
                ("保存场景", self.save_audio_scene),
                ("加载场景", self.load_audio_scene)
            ]
            
            for i, (name, callback) in enumerate(functions):
                button = gui_manager.createGUIButton(
                    pos=(0.82, 0, 0.88 - i * 0.06), 
                    text=name, 
                    size=0.04
                )
                self.gui_elements.append(button)
                self.world.accept(f"audio_func_{name}", callback)
                
        except Exception as e:
            print(f"⚠ 编辑器GUI创建失败: {e}")
            
    def _cleanup_editor_gui(self):
        """清理编辑器GUI"""
        try:
            if hasattr(self.world, 'gui_manager') and self.world.gui_manager:
                gui_manager = self.world.gui_manager
                
                for element in self.gui_elements:
                    gui_manager.deleteGUIElement(element)
                    
            # 清理事件监听
            tools = ["select", "add_sound", "add_zone"]
            for tool in tools:
                self.world.ignore(f"audio_tool_{tool}")
                
            functions = [
                "网格对齐", "播放测试音", "环境音效", 
                "保存场景", "加载场景"
            ]
            for func in functions:
                self.world.ignore(f"audio_func_{func}")
                
            self.gui_elements.clear()
            self.tool_buttons.clear()
            
        except Exception as e:
            print(f"⚠ 编辑器GUI清理失败: {e}")
            
    def set_edit_tool(self, tool: str):
        """设置编辑工具"""
        self.selected_tool = tool
        print(f"✓ 切换到 {tool} 工具")
        
        # 更新按钮状态
        for tool_name, button in self.tool_buttons.items():
            if tool_name == tool:
                # 高亮选中工具
                button.setColor(0.5, 1.0, 0.5, 1.0)  # 绿色
            else:
                # 恢复默认颜色
                button.setColor(1.0, 1.0, 1.0, 1.0)  # 白色
                
    def toggle_grid_snap(self):
        """切换网格对齐"""
        self.snap_to_grid = not self.snap_to_grid
        print(f"✓ 网格对齐已{'启用' if self.snap_to_grid else '禁用'}")
        
    def play_test_sound(self):
        """播放测试音效"""
        print("✓ 播放测试音效")
        
    def toggle_environment_audio(self):
        """切换环境音频"""
        self.plugin.environment_audio_manager.toggle_enabled()
        print("✓ 环境音频切换")
        
    def save_audio_scene(self):
        """保存音频场景"""
        print("✓ 保存音频场景")
        
    def load_audio_scene(self):
        """加载音频场景"""
        print("✓ 加载音频场景")
        
    def handle_mouse_click(self, mouse_x: float, mouse_y: float):
        """处理鼠标点击事件"""
        if not self.edit_mode:
            return
            
        # 将屏幕坐标转换为世界坐标
        world_pos = self._screen_to_world(mouse_x, mouse_y)
        if not world_pos:
            return
            
        # 根据当前工具执行操作
        if self.selected_tool == "add_sound":
            self._add_sound_at_position(world_pos)
        elif self.selected_tool == "add_zone":
            self._add_zone_at_position(world_pos)
        elif self.selected_tool == "select":
            self._select_item_at_position(world_pos)
            
    def _screen_to_world(self, screen_x: float, screen_y: float) -> Optional[Vec3]:
        """
        将屏幕坐标转换为世界坐标
        
        Args:
            screen_x: 屏幕X坐标 (-1 到 1)
            screen_y: 屏幕Y坐标 (-1 到 1)
            
        Returns:
            世界坐标，如果转换失败则返回None
        """
        # 这是一个简化的实现
        # 实际应用中需要使用摄像机的射线检测
        
        # 简单地将屏幕坐标映射到XZ平面
        x = screen_x * 20  # 假设场景大小为40x40
        z = screen_y * 20
        y = 0  # 在地面高度
        
        # 网格对齐
        if self.snap_to_grid:
            x = round(x / self.grid_size) * self.grid_size
            z = round(z / self.grid_size) * self.grid_size
            
        return Vec3(x, y, z)
        
    def _add_sound_at_position(self, position: Vec3):
        """
        在指定位置添加音效
        
        Args:
            position: 位置
        """
        print(f"✓ 在位置 {position} 添加音效")
        # 这里应该打开一个对话框让用户选择音频文件等参数
        
    def _add_zone_at_position(self, position: Vec3):
        """
        在指定位置添加区域
        
        Args:
            position: 位置
        """
        print(f"✓ 在位置 {position} 添加音频区域")
        # 这里应该打开一个对话框让用户设置区域参数
        
    def _select_item_at_position(self, position: Vec3):
        """
        选择指定位置的项目
        
        Args:
            position: 位置
        """
        print(f"✓ 选择位置 {position} 的项目")
        # 这里应该实现项目选择逻辑
        
    def toggle_edit_mode(self):
        """切换编辑模式"""
        self.edit_mode = not self.edit_mode
        if self.edit_mode:
            print("✓ 进入音频编辑模式")
        else:
            print("✓ 退出音频编辑模式")
            
    def update(self, dt: float):
        """更新编辑器状态"""
        # 处理键盘输入
        if self.world.mouseWatcherNode.hasMouse():
            mouse_pos = self.world.mouseWatcherNode.getMouse()
            
            # 检查鼠标按键
            from panda3d.core import MouseWatcher
            if self.world.mouseWatcherNode.isButtonDown(MouseWatcher.getGlobalPointer()):
                self.handle_mouse_click(mouse_pos.x, mouse_pos.y)
                
            # 检查键盘快捷键
            from panda3d.core import KeyboardButton
            if self.world.mouseWatcherNode.isButtonDown(KeyboardButton.asciiKey('e')):
                self.toggle_edit_mode()
                
    def cleanup(self):
        """清理编辑器资源"""
        self.hide()
        self.plugin = None
        self.world = None
        self.selected_item = None


class AudioSceneSerializer:
    """
    音频场景序列化器
    处理音频场景的保存和加载
    """
    
    def __init__(self, plugin):
        """
        初始化序列化器
        
        Args:
            plugin: 3D音频插件实例
        """
        self.plugin = plugin
        
    def save_scene(self, filepath: str) -> bool:
        """
        保存音频场景
        
        Args:
            filepath: 文件路径
            
        Returns:
            是否保存成功
        """
        try:
            import json
            
            # 收集场景数据
            scene_data = {
                'version': '1.0',
                'zones': self._collect_zones_data(),
                'sounds': self._collect_sounds_data(),
                'effects': self._collect_effects_data()
            }
            
            # 保存到文件
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(scene_data, f, indent=2, ensure_ascii=False)
                
            print(f"✓ 音频场景已保存到: {filepath}")
            return True
            
        except Exception as e:
            print(f"✗ 保存音频场景失败: {e}")
            return False
            
    def load_scene(self, filepath: str) -> bool:
        """
        加载音频场景
        
        Args:
            filepath: 文件路径
            
        Returns:
            是否加载成功
        """
        try:
            import json
            
            # 从文件加载
            with open(filepath, 'r', encoding='utf-8') as f:
                scene_data = json.load(f)
                
            # 应用场景数据
            self._apply_zones_data(scene_data.get('zones', []))
            self._apply_sounds_data(scene_data.get('sounds', []))
            self._apply_effects_data(scene_data.get('effects', []))
            
            print(f"✓ 音频场景已从 {filepath} 加载")
            return True
            
        except Exception as e:
            print(f"✗ 加载音频场景失败: {e}")
            return False
            
    def _collect_zones_data(self) -> List[Dict[str, Any]]:
        """收集区域数据"""
        zones_data = []
        zones_info = self.plugin.environment_audio_manager.get_all_zones_info()
        
        for zone_info in zones_info:
            zone_id = zone_info['id']
            # 获取区域的完整信息
            zone = self.plugin.environment_audio_manager.zones[zone_id]
            
            zone_data = {
                'id': zone_id,
                'position': zone['position'],
                'radius': zone['radius'],
                'properties': zone['properties'],
                'active': zone['active']
            }
            zones_data.append(zone_data)
            
        return zones_data
        
    def _collect_sounds_data(self) -> List[Dict[str, Any]]:
        """收集音效数据"""
        sounds_data = []
        
        for sound_id, sound_info in self.plugin.audio_source_manager.audio_sources.items():
            sound_data = {
                'id': sound_id,
                'filepath': sound_info['filepath'],
                'type': sound_info['type'],
                'position': sound_info['position'],
                'loop': sound_info['loop'],
                'volume': sound_info['volume']
            }
            sounds_data.append(sound_data)
            
        return sounds_data
        
    def _collect_effects_data(self) -> List[Dict[str, Any]]:
        """收集效果数据"""
        effects_data = []
        
        for effect_id, effect_info in self.plugin.audio_effect_processor.effects.items():
            effect_data = {
                'id': effect_id,
                'type': effect_info['type'],
                'parameters': effect_info['parameters'],
                'active': effect_info['active']
            }
            effects_data.append(effect_data)
            
        return effects_data
        
    def _apply_zones_data(self, zones_data: List[Dict[str, Any]]):
        """应用区域数据"""
        for zone_data in zones_data:
            zone_id = zone_data['id']
            position = zone_data['position']
            radius = zone_data['radius']
            properties = zone_data['properties']
            
            # 创建区域
            self.plugin.environment_audio_manager.create_zone(
                zone_id, position, radius, properties)
                
            # 设置活动状态
            if not zone_data.get('active', True):
                self.plugin.environment_audio_manager.disable_zone(zone_id)
                
    def _apply_sounds_data(self, sounds_data: List[Dict[str, Any]]):
        """应用音效数据"""
        for sound_data in sounds_data:
            sound_id = sound_data['id']
            filepath = sound_data['filepath']
            sound_type = sound_data['type']
            position = sound_data['position']
            loop = sound_data['loop']
            volume = sound_data['volume']
            
            # 创建音效
            if sound_type == '3d':
                new_sound_id = self.plugin.audio_source_manager.create_3d_sound(
                    filepath, position, loop, volume)
            else:
                new_sound_id = self.plugin.audio_source_manager.create_2d_sound(
                    filepath, loop, volume)
                    
            # 注意：由于ID可能已更改，需要处理关联关系
            if new_sound_id:
                # 播放音效
                self.plugin.audio_source_manager.play_sound(new_sound_id)
                
    def _apply_effects_data(self, effects_data: List[Dict[str, Any]]):
        """应用效果数据"""
        for effect_data in effects_data:
            effect_id = effect_data['id']
            effect_type = effect_data['type']
            parameters = effect_data['parameters']
            
            # 创建效果
            new_effect_id = self.plugin.audio_effect_processor.create_effect(
                effect_type, parameters)
                
            # 设置活动状态
            if not effect_data.get('active', True):
                if new_effect_id:
                    self.plugin.audio_effect_processor.disable_effect(new_effect_id)