import os
import sys
import threading
from pynput import keyboard
import time
import platform

# 添加当前目录到Python路径，使其可以直接运行
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# 导入日志模块
from shortcutkey.logger import logger

class HotkeyListener:
    """快捷键监听器"""
    
    # 用于检查程序是否已经在运行
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls, *args, **kwargs):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(HotkeyListener, cls).__new__(cls)
        return cls._instance
    
    def __init__(self, config, app_manager):
        """初始化快捷键监听器"""
        with self._lock:
            if not hasattr(self, '_initialized'):
                self.config = config
                self.app_manager = app_manager
                self.listener = None
                self.hotkeys = {}
                self.current_keys = set()
                self._initialized = True
                self._running = False
                logger.info(f"HotkeyListener初始化完成，准备监听快捷键")
    
    @classmethod
    def is_running(cls):
        """检查程序是否已经在运行"""
        is_running = cls._instance is not None and cls._instance._running
        logger.debug(f"检查HotkeyListener运行状态: {is_running}")
        return is_running
    
    def _check_permissions(self):
        """检查是否有必要的系统权限"""
        if platform.system() == 'Darwin':  # macOS
            logger.info("在macOS上检查辅助功能权限")
            try:
                # 尝试创建一个临时监听器来测试权限
                temp_listener = keyboard.Listener()
                temp_listener.start()
                temp_listener.stop()
                temp_listener.join(timeout=1)
                logger.info("辅助功能权限检查通过")
                return True
            except Exception as e:
                logger.warning(f"辅助功能权限检查失败: {str(e)}")
                print("\n重要提示: 该程序需要辅助功能权限才能监听键盘输入")
                print("\n正在自动打开系统偏好设置的辅助功能页面...")
                
                try:
                    # 使用subprocess运行AppleScript命令打开辅助功能设置页面
                    import subprocess
                    # 使用open命令打开系统偏好设置的辅助功能页面
                    subprocess.run(["open", "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"])
                    logger.info("已成功打开系统偏好设置的辅助功能页面")
                except Exception as open_error:
                    logger.error(f"无法打开系统偏好设置: {str(open_error)}")
                
                print("请按照以下步骤授权:")
                print("1. 点击左下角的锁定图标并输入您的管理员密码解锁设置")
                print("2. 点击右下角的'+'按钮")
                print("3. 找到并添加当前运行的Python进程或终端应用")
                print("4. 确保添加的应用程序已勾选")
                print("5. 授权后，请重新启动程序")
                print("\n授权后，快捷键监听功能将正常工作")
                return False
        return True  # 非macOS平台默认返回True
    
    def start(self):
        """启动快捷键监听"""
        if self._running:
            logger.warning("快捷键监听器已经在运行中，无需重复启动")
            return
        
        # 检查系统权限
        if not self._check_permissions():
            logger.warning("缺少必要的系统权限，热键监听无法正常工作")
            print("\n请先完成权限授权，然后按Enter键继续...")
            input()  # 等待用户按Enter键
            
            # 再次检查权限
            if not self._check_permissions():
                logger.error("权限检查再次失败，无法启动快捷键监听")
                print("错误: 权限检查失败，无法启动快捷键监听功能")
                print("请确保已经正确授权辅助功能权限，然后重新启动程序")
                return
        
        # 解析快捷键配置
        logger.info("开始解析快捷键配置")
        self._parse_hotkeys()
        logger.info(f"成功解析 {len(self.hotkeys)} 个快捷键配置")
        
        # 创建键盘监听器
        logger.info("创建键盘监听器")
        self.listener = keyboard.Listener(
            on_press=self._on_press,
            on_release=self._on_release,
            suppress=False  # 不阻止事件传递给其他应用
        )
        
        # 启动监听
        logger.info("启动快捷键监听")
        self._running = True
        self.listener.start()
        logger.info("快捷键监听器已启动")
        
        # 创建并启动一个后台线程来保持运行，避免阻塞调用线程
        self._main_thread = threading.Thread(target=self._main_loop, daemon=True)
        self._main_thread.start()
        
    def _main_loop(self):
        """主循环，保持监听器运行"""
        try:
            logger.info("进入主循环，持续监听快捷键")
            while self._running:
                time.sleep(3)  # 增加休眠时间，减少CPU使用率
                # 检查监听器线程是否还在运行
                if self.listener and not self.listener.is_alive():
                    logger.warning("键盘监听器线程已意外退出，正在重新启动")
                    try:
                        # 重新创建并启动监听器
                        self.listener = keyboard.Listener(
                            on_press=self._on_press,
                            on_release=self._on_release,
                            suppress=False
                        )
                        self.listener.start()
                        logger.info("键盘监听器已重新启动")
                    except Exception as restart_error:
                        logger.error(f"重新启动键盘监听器失败: {restart_error}")
                        # 连续失败时增加重试间隔
                        time.sleep(5)
        except KeyboardInterrupt:
            logger.info("接收到键盘中断信号，正在停止监听")
            self.stop()
        except Exception as e:
            logger.error(f"主循环发生异常: {str(e)}", exc_info=True)
            # 确保在异常情况下也设置_running=False，避免无限递归
            self._running = False
            # 尝试清理资源
            if self.listener:
                try:
                    self.listener.stop()
                except Exception:
                    pass
            # 重置实例引用
            with self._lock:
                HotkeyListener._instance = None
            logger.error("主循环异常，监听器已停止并重置")
    
    def stop(self):
        """停止快捷键监听"""
        if not self._running:
            logger.warning("快捷键监听器未运行，无需停止")
            return
        
        logger.info("开始停止快捷键监听")
        self._running = False
        
        # 停止监听器线程
        if self.listener:
            try:
                self.listener.stop()
                # 等待监听器线程结束，设置超时
                self.listener.join(timeout=3)
                logger.info("键盘监听器已停止")
            except Exception as e:
                logger.error(f"停止监听器线程时出错: {e}")
        
        # 等待主循环线程结束，设置超时
        if hasattr(self, '_main_thread') and self._main_thread.is_alive():
            try:
                self._main_thread.join(timeout=3)
                logger.info("主循环线程已结束")
            except Exception as e:
                logger.error(f"等待主循环线程结束时出错: {e}")
        
        # 重置实例引用
        with self._lock:
            HotkeyListener._instance = None
        logger.info("HotkeyListener实例已重置，监听完全停止")
    
    def _parse_hotkeys(self):
        """解析快捷键配置"""
        shortcuts = self.config.get('shortcuts', [])
        logger.debug(f"获取到 {len(shortcuts)} 个快捷键配置项")
        
        for shortcut in shortcuts:
            try:
                hotkey_str = shortcut['hotkey']
                app_path = shortcut.get('location', shortcut.get('path'))  # 兼容旧配置
                logger.debug(f"处理快捷键配置: 热键={hotkey_str}, 应用路径={app_path}")
                
                # 解析快捷键字符串
                key_parts = hotkey_str.split('+')
                keys = set()
                
                # 支持两种格式：
                # 1. 单个字符格式 - 自动转换为ctrl+shift+字符的组合
                # 2. 完整格式 - ctrl+shift+字符 或 cmd+shift+字符
                
                # 检查是否为单个字符格式
                if len(key_parts) == 1 and len(hotkey_str.strip()) == 1 and hotkey_str.strip().isalpha():
                    logger.info(f"检测到单个字符快捷键，将自动转换为ctrl+shift+{hotkey_str}组合")
                    # 自动添加ctrl和shift键，以及单个字母
                    keys.add(keyboard.Key.ctrl)
                    keys.add(keyboard.Key.shift)
                    keys.add(hotkey_str.strip().lower())  # 转换为小写以确保大小写不敏感
                    effective_hotkey = f"ctrl+shift+{hotkey_str}"
                else:
                    # 处理完整格式
                    if len(key_parts) != 3:
                        logger.warning(f"快捷键格式不正确，必须为单个字符或 '修饰键+shift+字母' 格式: {hotkey_str}")
                        continue
                        
                    modifiers = [part.strip().lower() for part in key_parts[:2]]
                    last_key = key_parts[-1].strip().lower()
                    
                    # 检查是否包含修饰键(ctrl或cmd)和shift键，且最后一个是单个字母
                    has_modifier = any(mod in ['ctrl', 'cmd'] for mod in modifiers)
                    has_shift = 'shift' in modifiers
                    is_single_alpha = len(last_key) == 1 and last_key.isalpha()
                    
                    is_standard_format = has_modifier and has_shift and is_single_alpha
                    
                    if not is_standard_format:
                        logger.warning(f"快捷键必须包含修饰键(ctrl/cmd)、shift和单个字母: {hotkey_str}")
                        continue
                        
                    logger.debug(f"识别到标准格式快捷键: {hotkey_str}")
                    effective_hotkey = hotkey_str
                    
                    for part in key_parts:
                        part = part.strip().lower()
                        
                        # 处理修饰键
                        if part == 'ctrl':
                            keys.add(keyboard.Key.ctrl)
                        elif part == 'alt':
                            keys.add(keyboard.Key.alt)
                        elif part == 'shift':
                            keys.add(keyboard.Key.shift)
                        elif part == 'cmd' or part == 'win':
                            if sys.platform == 'darwin':  # macOS
                                keys.add(keyboard.Key.cmd)
                                logger.debug(f"为macOS平台添加cmd键")
                            else:  # Windows/Linux
                                keys.add(keyboard.Key.cmd)
                                logger.debug(f"为{sys.platform}平台添加cmd键")
                        else:
                            # 处理普通键 - 转换为小写以确保大小写不敏感
                            if len(part) == 1:
                                keys.add(part.lower())
                            else:
                                # 尝试解析特殊键
                                try:
                                    special_key = getattr(keyboard.Key, part)
                                    keys.add(special_key)
                                    logger.debug(f"成功解析特殊键: {part}")
                                except AttributeError:
                                    logger.warning(f"无法解析快捷键部分 {part}")
                
                # 保存快捷键配置
                if keys:
                    key_set = frozenset(keys)
                    self.hotkeys[key_set] = app_path
                    logger.info(f"成功添加快捷键配置: {effective_hotkey} -> {app_path}")
            except Exception as e:
                logger.error(f"处理快捷键配置时出错: {str(e)}", exc_info=True)
    
    def _on_press(self, key):
        """按键按下时的处理"""
        # 将按键添加到当前按键集合
        try:
            key_repr = str(key)
            if hasattr(key, 'char') and key.char:
                self.current_keys.add(key.char.lower())  # 转换为小写以确保大小写不敏感
                logger.debug(f"按下普通键: {key.char}, 当前按键集合: {self.current_keys}")
            else:
                self.current_keys.add(key)
                logger.debug(f"按下特殊键: {key_repr}, 当前按键集合大小: {len(self.current_keys)}")
            
            # 检查是否匹配某个快捷键 - 确保只在完整组合按下时触发
            current_set = frozenset(self.current_keys)
            
            # 检查是否完全匹配一个快捷键配置
            for shortcut_set, app_location in self.hotkeys.items():
                # 只有当当前按键集合恰好等于快捷键集合时才触发
                if current_set == shortcut_set:
                    logger.info(f"完全匹配快捷键组合，启动应用: {app_location}")
                    self.app_manager.open_app(app_location)
                    # 添加一个短暂延迟，防止重复触发
                    time.sleep(0.3)
                    break
        except Exception as e:
            logger.error(f"按键处理错误: {str(e)}", exc_info=True)
            print(f"按键处理错误: {e}")
    
    def _on_release(self, key):
        """按键释放时的处理"""
        # 从当前按键集合中移除按键
        try:
            key_repr = str(key)
            if hasattr(key, 'char') and key.char:
                # 使用lower()确保与添加时格式一致
                self.current_keys.discard(key.char.lower())
                logger.debug(f"释放普通键: {key.char}, 当前按键集合: {self.current_keys}")
            else:
                self.current_keys.discard(key)
                logger.debug(f"释放特殊键: {key_repr}, 当前按键集合大小: {len(self.current_keys)}")
        except Exception as e:
            logger.error(f"按键释放处理错误: {str(e)}", exc_info=True)
            print(f"按键释放处理错误: {e}")