"""
输入映射器模块
负责将物理输入映射到逻辑动作
"""

import time
from typing import Dict, Any, List, Optional, Callable, Union
from enum import Enum
import json

class MappingType(Enum):
    """映射类型枚举"""
    BUTTON = "button"
    AXIS = "axis"
    GESTURE = "gesture"
    COMBINATION = "combination"
    SEQUENCE = "sequence"

class ActionType(Enum):
    """动作类型枚举"""
    SIMPLE = "simple"
    CONTINUOUS = "continuous"
    TOGGLE = "toggle"
    HOLD = "hold"

class InputMapper:
    """
    输入映射器
    负责将物理输入映射到逻辑动作
    """
    
    def __init__(self, plugin):
        """
        初始化输入映射器
        
        Args:
            plugin: 多平台输入支持插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 映射配置
        self.mappings = {}
        self.mapping_counter = 0
        
        # 动作定义
        self.actions = {}
        self.action_counter = 0
        
        # 映射配置
        self.mapping_config = {
            'enable_mapping': True,
            'enable_combinations': True,
            'enable_sequences': True,
            'combination_timeout': 0.5,  # 组合键超时时间(秒)
            'sequence_timeout': 1.0,     # 序列键超时时间(秒)
            'double_tap_timeout': 0.3,   # 双击超时时间(秒)
            'hold_threshold': 0.5        # 按住阈值时间(秒)
        }
        
        # 当前激活的输入
        self.active_inputs = {}
        self.active_combinations = {}
        self.active_sequences = {}
        
        # 输入历史（用于序列检测）
        self.input_history = []
        
        # 动作状态
        self.action_states = {}
        
        # 回调函数
        self.action_callbacks = {}
        
        # 统计信息
        self.mapping_stats = {
            'mappings_loaded': 0,
            'actions_triggered': 0,
            'combinations_detected': 0,
            'sequences_detected': 0,
            'mappings_updated': 0
        }
        
        # 时间戳记录
        self.last_input_time = {}
        self.action_start_time = {}
        
        print("✓ 输入映射器已创建")
        
    def initialize(self) -> bool:
        """
        初始化输入映射器
        
        Returns:
            是否初始化成功
        """
        try:
            # 创建默认映射
            self._create_default_mappings()
            
            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.mappings.clear()
            self.actions.clear()
            self.active_inputs.clear()
            self.active_combinations.clear()
            self.active_sequences.clear()
            self.input_history.clear()
            self.action_states.clear()
            self.action_callbacks.clear()
            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._check_hold_actions()
            
            # 检查组合键超时
            self._check_combination_timeouts()
            
            # 检查序列超时
            self._check_sequence_timeouts()
            
        except Exception as e:
            print(f"✗ 输入映射器更新失败: {e}")
            import traceback
            traceback.print_exc()
            
    def _create_default_mappings(self):
        """创建默认映射"""
        try:
            # 键盘默认映射
            self.create_mapping(
                name="前进",
                device_type="keyboard",
                input_id="w",
                action_name="move_forward",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="后退",
                device_type="keyboard",
                input_id="s",
                action_name="move_backward",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="左转",
                device_type="keyboard",
                input_id="a",
                action_name="turn_left",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="右转",
                device_type="keyboard",
                input_id="d",
                action_name="turn_right",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="跳跃",
                device_type="keyboard",
                input_id="space",
                action_name="jump",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.SIMPLE
            )
            
            self.create_mapping(
                name="蹲下",
                device_type="keyboard",
                input_id="c",
                action_name="crouch",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.TOGGLE
            )
            
            # 鼠标默认映射
            self.create_mapping(
                name="查看",
                device_type="mouse",
                input_id="movement",
                action_name="look",
                mapping_type=MappingType.AXIS,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="射击",
                device_type="mouse",
                input_id="button_1",  # 左键
                action_name="shoot",
                mapping_type=MappingType.BUTTON,
                action_type=ActionType.SIMPLE
            )
            
            # 手柄默认映射
            self.create_mapping(
                name="移动",
                device_type="gamepad",
                input_id="left_stick",
                action_name="move",
                mapping_type=MappingType.AXIS,
                action_type=ActionType.CONTINUOUS
            )
            
            self.create_mapping(
                name="视角",
                device_type="gamepad",
                input_id="right_stick",
                action_name="look",
                mapping_type=MappingType.AXIS,
                action_type=ActionType.CONTINUOUS
            )
            
            print("✓ 默认映射创建完成")
            
        except Exception as e:
            print(f"✗ 默认映射创建失败: {e}")
            
    def _check_hold_actions(self):
        """检查按住动作"""
        try:
            current_time = time.time()
            
            for action_name, state in self.action_states.items():
                if state.get('active', False) and state.get('type') == ActionType.HOLD:
                    start_time = self.action_start_time.get(action_name, current_time)
                    hold_duration = current_time - start_time
                    
                    if hold_duration >= self.mapping_config['hold_threshold']:
                        # 触发按住动作
                        self._trigger_action(action_name, {
                            'type': 'hold',
                            'duration': hold_duration
                        })
                        
        except Exception as e:
            print(f"✗ 按住动作检查失败: {e}")
            
    def _check_combination_timeouts(self):
        """检查组合键超时"""
        try:
            current_time = time.time()
            
            expired_combinations = []
            for combo_key, combo_data in self.active_combinations.items():
                if current_time - combo_data['timestamp'] > self.mapping_config['combination_timeout']:
                    expired_combinations.append(combo_key)
                    
            for combo_key in expired_combinations:
                del self.active_combinations[combo_key]
                
        except Exception as e:
            print(f"✗ 组合键超时检查失败: {e}")
            
    def _check_sequence_timeouts(self):
        """检查序列超时"""
        try:
            current_time = time.time()
            
            if self.input_history:
                last_input_time = self.input_history[-1]['timestamp']
                if current_time - last_input_time > self.mapping_config['sequence_timeout']:
                    self.input_history.clear()
                    
        except Exception as e:
            print(f"✗ 序列超时检查失败: {e}")
            
    def create_mapping(self, name: str, device_type: str, input_id: str,
                      action_name: str, mapping_type: MappingType,
                      action_type: ActionType, modifiers: List[str] = None,
                      parameters: Dict[str, Any] = None) -> int:
        """
        创建输入映射
        
        Args:
            name: 映射名称
            device_type: 设备类型
            input_id: 输入ID
            action_name: 动作名称
            mapping_type: 映射类型
            action_type: 动作类型
            modifiers: 修饰键列表
            parameters: 参数字典
            
        Returns:
            映射ID
        """
        try:
            mapping_id = self.mapping_counter
            self.mapping_counter += 1
            
            mapping = {
                'id': mapping_id,
                'name': name,
                'device_type': device_type,
                'input_id': input_id,
                'action_name': action_name,
                'mapping_type': mapping_type,
                'action_type': action_type,
                'modifiers': modifiers or [],
                'parameters': parameters or {},
                'enabled': True,
                'created_time': time.time()
            }
            
            self.mappings[mapping_id] = mapping
            self.mapping_stats['mappings_loaded'] += 1
            
            print(f"✓ 输入映射已创建: {name} (ID: {mapping_id})")
            return mapping_id
            
        except Exception as e:
            print(f"✗ 输入映射创建失败: {e}")
            return -1
            
    def remove_mapping(self, mapping_id: int) -> bool:
        """
        移除输入映射
        
        Args:
            mapping_id: 映射ID
            
        Returns:
            是否移除成功
        """
        try:
            if mapping_id in self.mappings:
                mapping_name = self.mappings[mapping_id]['name']
                del self.mappings[mapping_id]
                print(f"✓ 输入映射已移除: {mapping_name} (ID: {mapping_id})")
                return True
            else:
                print(f"✗ 输入映射不存在: ID {mapping_id}")
                return False
                
        except Exception as e:
            print(f"✗ 输入映射移除失败: {e}")
            return False
            
    def create_action(self, name: str, description: str = "",
                     parameters: Dict[str, Any] = None) -> int:
        """
        创建动作定义
        
        Args:
            name: 动作名称
            description: 动作描述
            parameters: 参数字典
            
        Returns:
            动作ID
        """
        try:
            action_id = self.action_counter
            self.action_counter += 1
            
            action = {
                'id': action_id,
                'name': name,
                'description': description,
                'parameters': parameters or {},
                'created_time': time.time()
            }
            
            self.actions[action_id] = action
            
            print(f"✓ 动作定义已创建: {name} (ID: {action_id})")
            return action_id
            
        except Exception as e:
            print(f"✗ 动作定义创建失败: {e}")
            return -1
            
    def remove_action(self, action_id: int) -> bool:
        """
        移除动作定义
        
        Args:
            action_id: 动作ID
            
        Returns:
            是否移除成功
        """
        try:
            if action_id in self.actions:
                action_name = self.actions[action_id]['name']
                del self.actions[action_id]
                print(f"✓ 动作定义已移除: {action_name} (ID: {action_id})")
                return True
            else:
                print(f"✗ 动作定义不存在: ID {action_id}")
                return False
                
        except Exception as e:
            print(f"✗ 动作定义移除失败: {e}")
            return False
            
    def handle_input_event(self, device_id: int, device_type: str, input_id: str,
                          value: Any, timestamp: float = None):
        """
        处理输入事件
        
        Args:
            device_id: 设备ID
            device_type: 设备类型
            input_id: 输入ID
            value: 输入值
            timestamp: 时间戳
        """
        try:
            if not self.enabled or not self.mapping_config['enable_mapping']:
                return
                
            if timestamp is None:
                timestamp = time.time()
                
            # 记录输入历史
            self.input_history.append({
                'device_id': device_id,
                'device_type': device_type,
                'input_id': input_id,
                'value': value,
                'timestamp': timestamp
            })
            
            # 保持历史记录大小
            if len(self.input_history) > 10:
                self.input_history.pop(0)
                
            # 查找匹配的映射
            matched_mappings = self._find_matching_mappings(device_type, input_id, value)
            
            # 处理匹配的映射
            for mapping in matched_mappings:
                self._process_mapping(mapping, device_id, value, timestamp)
                
        except Exception as e:
            print(f"✗ 输入事件处理失败: {e}")
            
    def _find_matching_mappings(self, device_type: str, input_id: str, value: Any) -> List[Dict[str, Any]]:
        """
        查找匹配的映射
        
        Args:
            device_type: 设备类型
            input_id: 输入ID
            value: 输入值
            
        Returns:
            匹配的映射列表
        """
        try:
            matched = []
            
            for mapping in self.mappings.values():
                if not mapping['enabled']:
                    continue
                    
                if (mapping['device_type'] == device_type and 
                    mapping['input_id'] == input_id):
                    matched.append(mapping)
                    
            return matched
        except Exception as e:
            print(f"✗ 匹配映射查找失败: {e}")
            return []
            
    def _process_mapping(self, mapping: Dict[str, Any], device_id: int,
                        value: Any, timestamp: float):
        """
        处理映射
        
        Args:
            mapping: 映射配置
            device_id: 设备ID
            value: 输入值
            timestamp: 时间戳
        """
        try:
            action_name = mapping['action_name']
            action_type = mapping['action_type']
            
            # 根据动作类型处理
            if action_type == ActionType.SIMPLE:
                # 简单动作：按下时触发
                if abs(value) > 0.1:  # 超过死区
                    self._trigger_action(action_name, {
                        'device_id': device_id,
                        'value': value,
                        'timestamp': timestamp
                    })
                    
            elif action_type == ActionType.CONTINUOUS:
                # 连续动作：根据值持续触发
                self._trigger_action(action_name, {
                    'device_id': device_id,
                    'value': value,
                    'timestamp': timestamp
                })
                
            elif action_type == ActionType.TOGGLE:
                # 切换动作：按下时切换状态
                if abs(value) > 0.1:
                    current_state = self.action_states.get(action_name, {}).get('active', False)
                    new_state = not current_state
                    self.action_states[action_name] = {
                        'active': new_state,
                        'type': ActionType.TOGGLE
                    }
                    
                    self._trigger_action(action_name, {
                        'device_id': device_id,
                        'value': new_state,
                        'timestamp': timestamp
                    })
                    
            elif action_type == ActionType.HOLD:
                # 按住动作：需要按住一定时间
                if abs(value) > 0.1:
                    # 按下
                    self.action_states[action_name] = {
                        'active': True,
                        'type': ActionType.HOLD
                    }
                    self.action_start_time[action_name] = timestamp
                else:
                    # 释放
                    if action_name in self.action_states:
                        del self.action_states[action_name]
                    if action_name in self.action_start_time:
                        del self.action_start_time[action_name]
                        
        except Exception as e:
            print(f"✗ 映射处理失败: {e}")
            
    def _trigger_action(self, action_name: str, action_data: Dict[str, Any]):
        """
        触发动作
        
        Args:
            action_name: 动作名称
            action_data: 动作数据
        """
        try:
            # 调用动作回调
            if action_name in self.action_callbacks:
                callback = self.action_callbacks[action_name]
                try:
                    callback(action_data)
                    self.mapping_stats['actions_triggered'] += 1
                except Exception as e:
                    print(f"✗ 动作回调执行失败: {e}")
            else:
                print(f"✗ 未找到动作回调: {action_name}")
                
        except Exception as e:
            print(f"✗ 动作触发失败: {e}")
            
    def register_action_callback(self, action_name: str, callback: Callable):
        """
        注册动作回调
        
        Args:
            action_name: 动作名称
            callback: 回调函数
        """
        try:
            self.action_callbacks[action_name] = callback
            print(f"✓ 动作回调已注册: {action_name}")
        except Exception as e:
            print(f"✗ 动作回调注册失败: {e}")
            
    def unregister_action_callback(self, action_name: str):
        """
        注销动作回调
        
        Args:
            action_name: 动作名称
        """
        try:
            if action_name in self.action_callbacks:
                del self.action_callbacks[action_name]
                print(f"✓ 动作回调已注销: {action_name}")
        except Exception as e:
            print(f"✗ 动作回调注销失败: {e}")
            
    def get_mapping(self, mapping_id: int) -> Optional[Dict[str, Any]]:
        """
        获取映射配置
        
        Args:
            mapping_id: 映射ID
            
        Returns:
            映射配置字典或None
        """
        return self.mappings.get(mapping_id)
        
    def get_all_mappings(self) -> Dict[int, Dict[str, Any]]:
        """
        获取所有映射配置
        
        Returns:
            所有映射配置字典
        """
        return self.mappings.copy()
        
    def get_action(self, action_id: int) -> Optional[Dict[str, Any]]:
        """
        获取动作定义
        
        Args:
            action_id: 动作ID
            
        Returns:
            动作定义字典或None
        """
        return self.actions.get(action_id)
        
    def get_all_actions(self) -> Dict[int, Dict[str, Any]]:
        """
        获取所有动作定义
        
        Returns:
            所有动作定义字典
        """
        return self.actions.copy()
        
    def update_mapping(self, mapping_id: int, updates: Dict[str, Any]) -> bool:
        """
        更新映射配置
        
        Args:
            mapping_id: 映射ID
            updates: 更新字典
            
        Returns:
            是否更新成功
        """
        try:
            if mapping_id in self.mappings:
                self.mappings[mapping_id].update(updates)
                self.mapping_stats['mappings_updated'] += 1
                print(f"✓ 映射已更新: ID {mapping_id}")
                return True
            else:
                print(f"✗ 映射不存在: ID {mapping_id}")
                return False
                
        except Exception as e:
            print(f"✗ 映射更新失败: {e}")
            return False
            
    def enable_mapping(self, mapping_id: int, enabled: bool = True) -> bool:
        """
        启用/禁用映射
        
        Args:
            mapping_id: 映射ID
            enabled: 是否启用
            
        Returns:
            是否操作成功
        """
        try:
            if mapping_id in self.mappings:
                self.mappings[mapping_id]['enabled'] = enabled
                status = "启用" if enabled else "禁用"
                print(f"✓ 映射已{status}: ID {mapping_id}")
                return True
            else:
                print(f"✗ 映射不存在: ID {mapping_id}")
                return False
                
        except Exception as e:
            print(f"✗ 映射启用/禁用失败: {e}")
            return False
            
    def load_mappings_from_file(self, file_path: str) -> bool:
        """
        从文件加载映射配置
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否加载成功
        """
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            mappings = data.get('mappings', [])
            actions = data.get('actions', [])
            
            # 加载动作定义
            for action_data in actions:
                self.create_action(
                    name=action_data['name'],
                    description=action_data.get('description', ''),
                    parameters=action_data.get('parameters', {})
                )
                
            # 加载映射配置
            for mapping_data in mappings:
                self.create_mapping(
                    name=mapping_data['name'],
                    device_type=mapping_data['device_type'],
                    input_id=mapping_data['input_id'],
                    action_name=mapping_data['action_name'],
                    mapping_type=MappingType(mapping_data['mapping_type']),
                    action_type=ActionType(mapping_data['action_type']),
                    modifiers=mapping_data.get('modifiers', []),
                    parameters=mapping_data.get('parameters', {})
                )
                
            print(f"✓ 映射配置已从文件加载: {file_path}")
            return True
            
        except Exception as e:
            print(f"✗ 映射配置加载失败: {e}")
            return False
            
    def save_mappings_to_file(self, file_path: str) -> bool:
        """
        保存映射配置到文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否保存成功
        """
        try:
            data = {
                'mappings': list(self.mappings.values()),
                'actions': list(self.actions.values())
            }
            
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
                
            print(f"✓ 映射配置已保存到文件: {file_path}")
            return True
            
        except Exception as e:
            print(f"✗ 映射配置保存失败: {e}")
            return False
            
    def set_mapping_config(self, config: Dict[str, Any]):
        """
        设置映射配置
        
        Args:
            config: 映射配置字典
        """
        try:
            self.mapping_config.update(config)
            print(f"✓ 映射配置已更新: {self.mapping_config}")
        except Exception as e:
            print(f"✗ 映射配置设置失败: {e}")
            
    def get_mapping_config(self) -> Dict[str, Any]:
        """
        获取映射配置
        
        Returns:
            映射配置字典
        """
        return self.mapping_config.copy()
        
    def get_mapping_stats(self) -> Dict[str, int]:
        """
        获取映射统计信息
        
        Returns:
            映射统计字典
        """
        return self.mapping_stats.copy()
        
    def reset_mapping_stats(self):
        """重置映射统计信息"""
        try:
            self.mapping_stats = {
                'mappings_loaded': len(self.mappings),
                'actions_triggered': 0,
                'combinations_detected': 0,
                'sequences_detected': 0,
                'mappings_updated': 0
            }
            print("✓ 映射统计信息已重置")
        except Exception as e:
            print(f"✗ 映射统计信息重置失败: {e}")
            
    def get_action_state(self, action_name: str) -> Dict[str, Any]:
        """
        获取动作状态
        
        Args:
            action_name: 动作名称
            
        Returns:
            动作状态字典
        """
        return self.action_states.get(action_name, {}).copy()