import asyncio
import logging
import subprocess
import os
import json
import sys
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import re
from pathlib import Path

# 添加项目路径
sys.path.append(str(Path(__file__).parent.parent.parent))

from utils.claude_code_client import ClaudeCodeClient
from utils.token_reader import TokenReader

logger = logging.getLogger(__name__)

class TerminalHandler:
    """Terminal命令处理器 - 实现AI控制的终端系统"""
    
    def __init__(self):
        self.work_dir = "/home/will/docker"
        self.restricted_paths = ["/home/will/docker/gitea"]
        self.conversation_memory: Dict[str, Dict] = {}
        self.conversation_timeout = timedelta(hours=1)
        
        # 初始化Claude Code CLI客户端
        self.claude_code_client = ClaudeCodeClient(self.work_dir)
        
        # 危险命令黑名单
        self.dangerous_commands = [
            r"rm\s+-rf\s+/",
            r"rm\s+-rf\s+\*",
            r"rm\s+-rf\s+~",
            r"chmod\s+-R\s+777",
            r"chown\s+-R",
            r"mkfs\.",
            r"dd\s+if=",
            r">\s*/dev/",
        ]
    
        
    async def handle_command(self, command: str, user_id: str) -> str:
        """处理terminal命令"""
        try:
            # 检查会话状态
            conversation = self._get_or_create_conversation(user_id)
            
            # 安全检查
            if not self._is_command_safe(command):
                return f"❌ **安全限制**: 命令被拒绝\n```\n{command}\n```\n该命令可能对系统造成危险。"
            
            # 记录命令到会话历史
            conversation['history'].append({
                'type': 'user_command',
                'content': command,
                'timestamp': datetime.now().isoformat()
            })
            
            # 处理命令
            if self._is_direct_shell_command(command):
                # 直接shell命令
                result = await self._execute_shell_command(command)
            else:
                # AI解释和执行
                result = await self._ai_interpret_and_execute(command, conversation)
            
            # 记录结果
            conversation['history'].append({
                'type': 'system_response',
                'content': result,
                'timestamp': datetime.now().isoformat()
            })
            
            # 压缩历史记录以控制token消耗
            self._compress_conversation_history(conversation)
            
            return result
            
        except Exception as e:
            logger.error(f"处理terminal命令错误: {e}")
            return f"❌ **执行错误**: {str(e)}"
    
    def _get_or_create_conversation(self, user_id: str) -> Dict:
        """获取或创建用户会话"""
        now = datetime.now()
        
        if user_id in self.conversation_memory:
            conversation = self.conversation_memory[user_id]
            last_activity = datetime.fromisoformat(conversation['last_activity'])
            
            # 检查是否超时
            if now - last_activity > self.conversation_timeout:
                logger.info(f"用户 {user_id} 会话超时，创建新会话")
                conversation = self._create_new_conversation()
            else:
                conversation['last_activity'] = now.isoformat()
        else:
            conversation = self._create_new_conversation()
        
        self.conversation_memory[user_id] = conversation
        return conversation
    
    def _create_new_conversation(self) -> Dict:
        """创建新会话"""
        return {
            'last_activity': datetime.now().isoformat(),
            'history': [],
            'context': {
                'current_dir': self.work_dir,
                'last_commands': [],
                'important_info': []
            }
        }
    
    def _is_command_safe(self, command: str) -> bool:
        """检查命令是否安全"""
        command_lower = command.lower()
        
        # 检查危险命令模式
        for pattern in self.dangerous_commands:
            if re.search(pattern, command_lower):
                logger.warning(f"拒绝危险命令: {command}")
                return False
        
        # 检查路径限制
        if any(restricted in command for restricted in self.restricted_paths):
            logger.warning(f"拒绝访问受限路径: {command}")
            return False
        
        return True
    
    def _is_direct_shell_command(self, command: str) -> bool:
        """判断是否为直接shell命令"""
        # 简单的shell命令模式
        shell_patterns = [
            r"^ls(\s|$)",
            r"^pwd(\s|$)",
            r"^cd\s+",
            r"^cat\s+",
            r"^grep\s+",
            r"^find\s+",
            r"^docker\s+",
            r"^docker-compose\s+",
            r"^tail\s+",
            r"^head\s+",
            r"^ps(\s|$)",
            r"^df(\s|$)",
            r"^du\s+",
            r"^top(\s|$)",
            r"^htop(\s|$)",
        ]
        
        return any(re.match(pattern, command.lower()) for pattern in shell_patterns)
    
    async def _execute_shell_command(self, command: str) -> str:
        """执行shell命令"""
        try:
            # 设置工作目录和环境
            env = os.environ.copy()
            
            # 执行命令
            process = await asyncio.create_subprocess_shell(
                command,
                cwd=self.work_dir,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                env=env
            )
            
            stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=30.0)
            
            # 处理输出
            output = ""
            if stdout:
                output += stdout.decode('utf-8', errors='replace')
            if stderr:
                output += "\n" + stderr.decode('utf-8', errors='replace')
            
            if process.returncode == 0:
                result = f"✅ **命令执行成功**\n```bash\n$ {command}\n{output}\n```"
            else:
                result = f"⚠️ **命令执行完成 (退出码: {process.returncode})**\n```bash\n$ {command}\n{output}\n```"
            
            return result
            
        except asyncio.TimeoutError:
            return f"⏰ **命令超时**: 执行时间超过30秒\n```bash\n$ {command}\n```"
        except Exception as e:
            return f"❌ **执行错误**: {str(e)}\n```bash\n$ {command}\n```"
    
    async def _ai_interpret_and_execute(self, command: str, conversation: Dict) -> str:
        """使用Claude Code CLI解释自然语言命令并执行"""
        
        # 使用Claude Code CLI处理命令
        return await self.claude_code_client.run_claude_command(command)
    
    
    async def _basic_command_mapping(self, command: str) -> str:
        """基础命令映射（无AI时的回退方案）"""
        command_lower = command.lower()
        
        # 基础命令映射
        if "查看" in command and ("文件" in command or "目录" in command):
            return await self._execute_shell_command("ls -la")
        elif "当前目录" in command or "当前位置" in command:
            return await self._execute_shell_command("pwd")
        elif "查看容器" in command or "docker容器" in command or "容器状态" in command:
            return await self._execute_shell_command("docker ps")
        elif "查看日志" in command and "容器" in command:
            return await self._execute_shell_command("docker ps --format 'table {{.Names}}\\t{{.Status}}'")
        elif "磁盘使用" in command or "存储空间" in command:
            return await self._execute_shell_command("df -h")
        else:
            # 未识别的命令，提供帮助
            return f"""🤔 **未能理解命令**: {command}

**建议使用以下格式:**
• 直接shell命令: `ls`, `docker ps`, `pwd`
• 自然语言: "查看当前目录文件", "查看Docker容器状态"

**常用命令示例:**
```bash
ls -la                    # 查看文件列表
docker ps                 # 查看容器状态
docker-compose ps         # 查看compose服务
tail -f /var/log/syslog   # 查看系统日志
df -h                     # 查看磁盘使用
```

💡 **提示**: 当前未启用AI模式，仅支持基础命令映射"""
    
    def _compress_conversation_history(self, conversation: Dict):
        """压缩会话历史以控制token消耗"""
        history = conversation['history']
        
        # 如果历史记录超过20条，进行压缩
        if len(history) > 20:
            # 保留最近10条完整记录
            recent_history = history[-10:]
            
            # 压缩较早的记录，只保留重要信息
            compressed_history = []
            for item in history[:-10]:
                if item['type'] == 'user_command':
                    # 保留所有用户命令
                    compressed_history.append(item)
                elif item['type'] == 'system_response':
                    # 只保留成功的重要操作结果
                    if '✅' in item['content'] and any(keyword in item['content'].lower() 
                        for keyword in ['docker', 'container', 'service', 'config']):
                        # 压缩输出，只保留关键信息
                        compressed_item = item.copy()
                        compressed_item['content'] = self._extract_key_info(item['content'])
                        compressed_history.append(compressed_item)
            
            # 更新历史记录
            conversation['history'] = compressed_history + recent_history
            
            logger.info(f"压缩会话历史: {len(history)} -> {len(conversation['history'])} 条记录")
    
    def _extract_key_info(self, content: str) -> str:
        """提取内容中的关键信息"""
        # 简单的关键信息提取
        lines = content.split('\n')
        key_lines = []
        
        for line in lines:
            # 保留状态信息、错误信息、重要路径等
            if any(keyword in line.lower() for keyword in 
                   ['status', 'running', 'stopped', 'error', 'success', 'docker', 'container']):
                key_lines.append(line)
        
        if key_lines:
            return '\n'.join(key_lines[:3])  # 最多保留3行
        else:
            return content[:100] + "..." if len(content) > 100 else content