"""
Browser 工具
- BrowserUseTool: 浏览器自动化工具
- TaskReportTool: 任务执行报告工具
"""

import json
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field

from tools.base import BaseTool, ToolOutput
from tools.system import BashTool
from core.paths import get_path_manager
from core.logger import log_event


# ==================== BrowserUseTool ====================

class BrowserUseArgs(BaseModel):
    """Browser Use 输入参数"""

    command: str = Field(
        ...,
        description="browser-use 子命令，如: open <url>, click <index>, run '<task>', state, screenshot 等"
    )
    session: Optional[str] = Field(default=None, description="会话名称")
    browser: Optional[str] = Field(
        default=None, description="浏览器模式: chromium (默认) / real (真实浏览器) / remote (远程云浏览器)"
    )
    headed: bool = Field(default=True, description="是否显示浏览器窗口")
    api_key: Optional[str] = Field(default=None, description="Browser-use API Key")


class BrowserUseTool(BaseTool):
    """Browser Use 工具 - 通过 Bash 调用 browser-use CLI"""

    name = "browser_use"
    description = """浏览器自动化工具。

使用前请先阅读 web.txt 提示词了解详细操作方法。

主要功能：
- 打开网页、点击元素、输入文本
- 滚动页面、截图、获取页面状态
- AI 驱动的任务执行 (run 命令)

安装检查：
- 如果提示未安装，请运行: curl -fsSL https://browser-use.com/cli/install.sh | bash
    """
    args_schema = BrowserUseArgs

    def __init__(self):
        self._bash_tool = BashTool()

    async def run(
        self,
        command: str,
        session: Optional[str] = None,
        browser: Optional[str] = None,
        headed: bool = True,
        api_key: Optional[str] = None,
    ) -> str:
        """直接通过 Bash 执行 browser-use 命令"""

        # 1. 检查 browser-use 是否安装
        check_result = await self._check_installation()
        if check_result:
            log_event("browser_use_install_check_failed", message=check_result)
            return check_result

        # 2. 构建命令
        cmd = self._build_command(command, session, browser, headed, api_key)
        log_event("browser_use_execute", command=cmd)

        # 3. 通过 Bash 执行
        result = await self._bash_tool.run(command=cmd)
        log_event("browser_use_result", result=result[:500] if len(result) > 500 else result)
        return result

    async def _check_installation(self) -> Optional[str]:
        """检查 browser-use 是否已安装"""
        try:
            result = await self._bash_tool.run(command="browser-use --version")
            if "not found" in result.lower() or "not recognized" in result.lower():
                return self._get_install_guide()
        except Exception:
            return self._get_install_guide()
        return None

    def _get_install_guide(self) -> str:
        """返回安装指南"""
        return """❌ browser-use 未安装或不可用。

请运行以下命令安装：

```bash
# macOS / Linux
curl -fsSL https://browser-use.com/cli/install.sh | bash

# 验证安装
browser-use doctor
```

如需配置远程模式，请设置环境变量：
```bash
export BROWSER_USE_API_KEY=your_key
```
"""

    def _build_command(
        self,
        command: str,
        session: Optional[str],
        browser: Optional[str],
        headed: bool,
        api_key: Optional[str],
    ) -> str:
        """构建 browser-use 命令"""
        parts = ["browser-use"]

        # 全局选项
        if session:
            parts.extend(["--session", session])
        if browser and browser != "chromium":
            parts.extend(["--browser", browser])
        if headed:
            parts.append("--headed")
        if api_key:
            parts.extend(["--api-key", api_key])

        # 子命令 - 直接添加原始命令
        parts.append(command)

        return " ".join(parts)


# ==================== TaskReportTool ====================

class TaskReportArgs(BaseModel):
    """任务报告工具输入参数"""

    action: str = Field(
        ...,
        description="操作类型: save (新建报告) / update (更新最优路径) / list (列出报告) / get (获取详情)"
    )

    # save & update 共用参数
    task_goal: Optional[str] = Field(default=None, description="任务目标描述")
    outcome: Optional[str] = Field(
        default=None,
        description="执行结果: success / failed / partial"
    )

    # save 专用参数
    steps: Optional[List[Dict[str, Any]]] = Field(
        default=None,
        description="执行步骤列表，每个步骤包含 command, result 等"
    )

    # update 专用参数
    report_id: Optional[str] = Field(default=None, description="要更新的报告 ID")
    optimal_path: Optional[List[Dict[str, Any]]] = Field(
        default=None,
        description="最优路径步骤列表"
    )
    notes: Optional[str] = Field(default=None, description="备注说明")

    # list 专用参数
    limit: int = Field(default=10, description="列出报告的数量")

    # get 专用参数
    get_report_id: Optional[str] = Field(default=None, description="报告 ID")


class TaskReportTool(BaseTool):
    """任务执行报告工具"""

    name = "task_report"
    description = """任务执行报告工具。

功能：
- save: 新建报告，记录实际执行的完整探索路径
- update: 更新最优路径，供未来参考
- list: 列出历史报告
- get: 获取报告详情

使用场景：
- 任务完成后使用 save 创建报告
- 找到更优路径后使用 update 更新
- 开始新任务前使用 list 参考历史
    """
    args_schema = TaskReportArgs

    def __init__(self):
        path_mgr = get_path_manager()
        self.storage_dir = path_mgr.get_data_dir() / "task_reports"
        self.storage_dir.mkdir(parents=True, exist_ok=True)

    async def run(
        self,
        action: str,
        task_goal: Optional[str] = None,
        outcome: Optional[str] = None,
        steps: Optional[List[Dict]] = None,
        report_id: Optional[str] = None,
        optimal_path: Optional[List[Dict]] = None,
        notes: Optional[str] = None,
        limit: int = 10,
        get_report_id: Optional[str] = None,
    ) -> str:
        """执行报告操作"""

        if action == "save":
            return await self._save_report(task_goal, steps, outcome)
        elif action == "update":
            return await self._update_report(report_id, optimal_path, notes)
        elif action == "list":
            return await self._list_reports(limit)
        elif action == "get":
            return await self._get_report(get_report_id or report_id)
        else:
            return f"未知操作: {action}，支持的操作为: save, update, list, get"

    async def _save_report(
        self,
        task_goal: Optional[str],
        steps: Optional[List[Dict]],
        outcome: Optional[str],
    ) -> str:
        """保存任务报告（记录实际探索路径）"""
        if not task_goal or not steps:
            return "错误: save 操作需要 task_goal 和 steps 参数"

        report_id = str(uuid.uuid4())[:8]
        timestamp = datetime.now().isoformat()

        # 统计无用步骤（简单统计：有 "失败" 或 "错误" 结果的步骤）
        wasted_steps = self._count_wasted_steps(steps)

        # 提取访问的 URL
        urls = self._extract_urls(steps)

        report = {
            "id": report_id,
            "timestamp": timestamp,
            "task_goal": task_goal,
            "outcome": outcome or "unknown",
            "actual_path": steps,
            "optimal_path": None,
            "notes": None,
            "urls_visited": urls,
            "total_steps": len(steps),
            "wasted_steps": wasted_steps,
            "update_count": 0,
        }

        # 持久化
        await self._save_report_file(report)
        await self._update_index(report)

        return f"""✅ 任务报告已保存: {report_id}

任务目标: {task_goal}
执行结果: {outcome or 'unknown'}
总步骤: {len(steps)} 步
无用探索: {wasted_steps} 步

后续可使用 task_report(action="update", ...) 记录最优路径"""

    async def _update_report(
        self,
        report_id: Optional[str],
        optimal_path: Optional[List[Dict]],
        notes: Optional[str] = None,
    ) -> str:
        """更新报告（记录最优路径）"""
        if not report_id:
            return "错误: update 操作需要 report_id 参数"
        if not optimal_path:
            return "错误: update 操作需要 optimal_path 参数"

        # 1. 读取现有报告
        report = await self._load_report(report_id)
        if not report:
            return f"报告不存在: {report_id}"

        # 2. 记录最优路径
        report["optimal_path"] = optimal_path
        report["notes"] = notes
        report["update_count"] += 1
        report["last_updated"] = datetime.now().isoformat()

        # 3. 统计节省的步骤
        original_steps = report.get("total_steps", 0)
        optimal_steps = len(optimal_path)
        saved_steps = original_steps - optimal_steps
        report["saved_steps"] = saved_steps

        # 4. 保存
        await self._save_report_file(report)
        await self._update_index(report)

        return f"""✅ 报告已更新: {report_id}

最优路径: {optimal_steps} 步（原始: {original_steps} 步）
节省: {saved_steps} 步
备注: {notes or '无'}"""

    async def _list_reports(self, limit: int = 10) -> str:
        """列出历史报告"""
        index = await self._load_index()

        if not index:
            return "暂无任务报告"

        # 返回最近 N 条
        recent = sorted(index, key=lambda x: x["timestamp"], reverse=True)[:limit]

        lines = [f"共 {len(index)} 条报告，显示最近 {len(recent)} 条:\n"]

        for i, item in enumerate(recent, 1):
            goal = item["task_goal"]
            if len(goal) > 40:
                goal = goal[:40] + "..."

            outcome_icon = {
                "success": "✅",
                "failed": "❌",
                "partial": "⚠️",
                "unknown": "❓",
            }.get(item.get("outcome", "unknown"), "❓")

            # 显示是否有最优路径
            has_optimal = "⭐" if item.get("optimal_path") else ""

            date = item["timestamp"][:10]
            lines.append(
                f"{i}. [{item['id']}] {outcome_icon} {item.get('outcome', '?')} | "
                f"{date} | {goal} {has_optimal}"
            )

        lines.append("\n使用 task_report(action='get', get_report_id='<id>') 查看详情")
        lines.append("使用 task_report(action='update', report_id='<id>', optimal_path=[...]) 更新最优路径")

        return "\n".join(lines)

    async def _get_report(self, report_id: Optional[str]) -> str:
        """获取报告详情"""
        if not report_id:
            return "错误: get 操作需要 get_report_id 参数"

        report = await self._load_report(report_id)
        if not report:
            return f"报告不存在: {report_id}"

        # 格式化输出
        lines = [
            f"# 任务报告: {report['id']}",
            "",
            f"**任务目标**: {report['task_goal']}",
            f"**执行结果**: {report['outcome']}",
            f"**创建时间**: {report['timestamp']}",
            "",
        ]

        # 最优路径
        if report.get("optimal_path"):
            lines.extend([
                "## ⭐ 最优路径",
                "",
            ])
            for i, step in enumerate(report["optimal_path"], 1):
                cmd = step.get("command", "")
                reason = step.get("reason", "")
                lines.append(f"{i}. `{cmd}`")
                if reason:
                    lines.append(f"   - {reason}")
            lines.append("")

        # 原始路径
        if report.get("actual_path"):
            lines.extend([
                f"## 完整探索路径 ({report['total_steps']} 步, {report.get('wasted_steps', 0)} 步无效)",
                "",
            ])
            for step in report["actual_path"]:
                cmd = step.get("command", "")
                result = step.get("result", "")
                # 截断结果
                if len(result) > 50:
                    result = result[:50] + "..."
                lines.append(f"- `{cmd}` → {result}")

        # URL
        if report.get("urls_visited"):
            lines.extend([
                "",
                "## 访问的 URL",
                "",
            ])
            for url in report["urls_visited"]:
                lines.append(f"- {url}")

        # 统计
        lines.extend([
            "",
            f"更新次数: {report.get('update_count', 0)}",
        ])

        if report.get("notes"):
            lines.extend([
                "",
                f"备注: {report['notes']}",
            ])

        return "\n".join(lines)

    async def _save_report_file(self, report: dict) -> None:
        """保存报告到文件"""
        report_file = self.storage_dir / f"{report['id']}.json"
        with open(report_file, "w", encoding="utf-8") as f:
            json.dump(report, f, indent=2, ensure_ascii=False)

    async def _load_report(self, report_id: str) -> Optional[dict]:
        """加载报告"""
        report_file = self.storage_dir / f"{report_id}.json"
        if not report_file.exists():
            return None

        with open(report_file, "r", encoding="utf-8") as f:
            return json.load(f)

    async def _load_index(self) -> List[dict]:
        """加载索引"""
        index_file = self.storage_dir / "index.json"
        if not index_file.exists():
            return []

        with open(index_file, "r", encoding="utf-8") as f:
            return json.load(f)

    async def _update_index(self, report: dict) -> None:
        """更新索引文件"""
        index = await self._load_index()

        # 查找是否已存在
        existing_idx = None
        for i, item in enumerate(index):
            if item["id"] == report["id"]:
                existing_idx = i
                break

        index_item = {
            "id": report["id"],
            "timestamp": report["timestamp"],
            "task_goal": report["task_goal"],
            "outcome": report["outcome"],
            "total_steps": report["total_steps"],
            "wasted_steps": report.get("wasted_steps", 0),
            "update_count": report.get("update_count", 0),
            "optimal_path": True if report.get("optimal_path") else False,
        }

        if existing_idx is not None:
            index[existing_idx] = index_item
        else:
            index.append(index_item)

        index_file = self.storage_dir / "index.json"
        with open(index_file, "w", encoding="utf-8") as f:
            json.dump(index, f, indent=2, ensure_ascii=False)

    def _count_wasted_steps(self, steps: List[Dict]) -> int:
        """统计无用步骤"""
        wasted = 0
        for step in steps:
            result = step.get("result", "").lower()
            if "失败" in result or "错误" in result or "error" in result or "failed" in result:
                wasted += 1
        return wasted

    def _extract_urls(self, steps: List[Dict]) -> List[str]:
        """从步骤中提取 URL"""
        urls = []
        for step in steps:
            cmd = step.get("command", "")
            if cmd.startswith("open ") and len(cmd.split()) > 1:
                url = cmd.split(None, 1)[1]
                if url not in urls:
                    urls.append(url)
        return urls
