"""BaiduSearchTool - 百度搜索工具，支持优雅降级

通过百度搜索 API 执行关键词搜索，返回搜索结果列表。
当百度搜索 API 不可用时，返回包含降级提示的错误信息。
"""

import json
import logging
import urllib.parse
from typing import Any

import httpx

from agentkit.tools.base import Tool

logger = logging.getLogger(__name__)


class BaiduSearchTool(Tool):
    """百度搜索工具 - 执行关键词搜索，返回搜索结果

    支持两种模式：
    1. 百度搜索 API（需要 API key 配置）
    2. 直接抓取百度搜索结果页（降级模式，无需 API key）

    当两种模式都不可用时，返回包含降级提示的错误信息。
    """

    def __init__(
        self,
        name: str = "baidu_search",
        description: str = "执行百度搜索，返回搜索结果列表",
        input_schema: dict[str, Any] | None = None,
        output_schema: dict[str, Any] | None = None,
        version: str = "1.0.0",
        tags: list[str] | None = None,
        api_key: str | None = None,
        api_url: str | None = None,
    ):
        super().__init__(
            name=name,
            description=description,
            input_schema=input_schema or self._default_input_schema(),
            output_schema=output_schema or self._default_output_schema(),
            version=version,
            tags=tags or ["search", "baidu"],
        )
        self._api_key = api_key
        self._api_url = api_url

    @staticmethod
    def _default_input_schema() -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "搜索关键词",
                },
                "max_results": {
                    "type": "integer",
                    "description": "最大返回结果数",
                    "default": 5,
                },
            },
            "required": ["query"],
        }

    @staticmethod
    def _default_output_schema() -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "results": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "title": {"type": "string"},
                            "url": {"type": "string"},
                            "snippet": {"type": "string"},
                        },
                    },
                    "description": "搜索结果列表",
                },
                "total": {"type": "integer", "description": "结果总数"},
                "success": {"type": "boolean", "description": "是否成功"},
                "error": {"type": "string", "description": "错误信息（仅失败时）"},
            },
        }

    async def execute(self, **kwargs) -> dict:
        """执行百度搜索

        Args:
            query: 搜索关键词（必需）
            max_results: 最大返回结果数（默认 5）

        Returns:
            包含 results 列表和 success 布尔值的字典
        """
        query = kwargs.get("query")
        if not query:
            return {"error": "query 参数是必需的", "results": [], "total": 0, "success": False}

        max_results = kwargs.get("max_results", 5)

        # 优先使用 API 模式
        if self._api_key and self._api_url:
            return await self._search_via_api(query, max_results)

        # 降级：直接抓取百度搜索结果页
        return await self._search_via_scrape(query, max_results)

    async def _search_via_api(self, query: str, max_results: int) -> dict:
        """通过百度搜索 API 执行搜索"""
        try:
            params = {
                "query": query,
                "num": max_results,
            }
            url = f"{self._api_url}?{urllib.parse.urlencode(params)}"
            async with httpx.AsyncClient(timeout=30) as client:
                resp = await client.get(
                    url,
                    headers={
                        "User-Agent": "AgentKit/1.0",
                        "Authorization": f"Bearer {self._api_key}",
                    },
                )
                resp.raise_for_status()
                data = resp.json()

            results = []
            for item in data.get("results", [])[:max_results]:
                results.append({
                    "title": item.get("title", ""),
                    "url": item.get("url", ""),
                    "snippet": item.get("snippet", ""),
                })

            return {"results": results, "total": len(results), "success": True}

        except Exception as e:
            logger.error(f"BaiduSearchTool API 搜索失败: {e}")
            # 降级到抓取模式
            return await self._search_via_scrape(query, max_results)

    async def _search_via_scrape(self, query: str, max_results: int) -> dict:
        """通过直接抓取百度搜索结果页执行搜索（降级模式）"""
        try:
            encoded_query = urllib.parse.quote(query)
            url = f"https://www.baidu.com/s?wd={encoded_query}&rn={max_results}"
            async with httpx.AsyncClient(timeout=30, follow_redirects=True) as client:
                resp = await client.get(
                    url,
                    headers={
                        "User-Agent": (
                            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                            "AppleWebKit/537.36 (KHTML, like Gecko) "
                            "Chrome/131.0.0.0 Safari/537.36"
                        ),
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
                        "Accept-Encoding": "gzip, deflate, br",
                        "Connection": "keep-alive",
                        "Cache-Control": "max-age=0",
                        "Sec-Fetch-Dest": "document",
                        "Sec-Fetch-Mode": "navigate",
                        "Sec-Fetch-Site": "none",
                        "Sec-Fetch-User": "?1",
                        "Upgrade-Insecure-Requests": "1",
                    },
                )
                html = resp.text

            # Check if we got a captcha page
            if "验证" in html and len(html) < 5000:
                logger.warning("Baidu returned captcha page, search unavailable")
                return {
                    "error": "Baidu search blocked by captcha",
                    "results": [],
                    "total": 0,
                    "success": False,
                }

            # 简单解析搜索结果（基于百度搜索结果页 HTML 结构）
            results = self._parse_baidu_html(html, max_results)

            if not results:
                # Try alternative parsing
                results = self._parse_baidu_html_alt(html, max_results)

            return {"results": results, "total": len(results), "success": True}

        except Exception as e:
            logger.error(f"BaiduSearchTool 抓取搜索失败: {e}")
            return {
                "error": f"百度搜索不可用: {e}",
                "results": [],
                "total": 0,
                "success": False,
            }

    @staticmethod
    def _parse_baidu_html(html: str, max_results: int) -> list[dict[str, str]]:
        """解析百度搜索结果页 HTML，提取标题、URL、摘要

        注意：百度 HTML 结构可能变化，此解析器尽力提取关键信息。
        """
        import re

        results: list[dict[str, str]] = []

        # 匹配百度搜索结果块 - multiple patterns for different Baidu page versions
        # Pattern 1: <h3 class="t"> with href
        pattern1 = re.compile(
            r'<h3[^>]*class="[^"]*t[^"]*"[^>]*>.*?href="([^"]*)"[^>]*>(.*?)</a>',
            re.DOTALL,
        )
        # Pattern 2: <h3> with data-url or inside <div class="result">
        pattern2 = re.compile(
            r'<h3[^>]*>.*?<a[^>]*href="([^"]*)"[^>]*>(.*?)</a>',
            re.DOTALL,
        )
        # Snippet patterns
        snippet_pattern1 = re.compile(
            r'<span[^>]*class="[^"]*content-right_[^"]*"[^>]*>(.*?)</span>',
            re.DOTALL,
        )
        snippet_pattern2 = re.compile(
            r'<div[^>]*class="[^"]*c-abstract[^"]*"[^>]*>(.*?)</div>',
            re.DOTALL,
        )
        snippet_pattern3 = re.compile(
            r'<span[^>]*class="[^"]*content-right_[^"]*"[^>]*>(.*?)</span>',
            re.DOTALL,
        )

        # Try pattern 1 first
        for match in pattern1.finditer(html):
            if len(results) >= max_results:
                break
            url = match.group(1)
            title = re.sub(r"<[^>]+>", "", match.group(2)).strip()
            if not title or len(title) < 2:
                continue
            # Skip Baidu internal links that aren't redirect links
            if "baidu.com" in url and "baidu.com/link?" not in url:
                continue
            if not url.startswith("http") and "baidu.com/link?" not in url:
                continue

            snippet = ""
            for sp in [snippet_pattern1, snippet_pattern2, snippet_pattern3]:
                snippet_match = sp.search(html[match.end():match.end() + 2000])
                if snippet_match:
                    snippet = re.sub(r"<[^>]+>", "", snippet_match.group(1)).strip()
                    if snippet:
                        break

            results.append({
                "title": title[:200],
                "url": url,
                "snippet": snippet[:300] if snippet else "",
            })

        # If pattern 1 found nothing, try pattern 2
        if not results:
            for match in pattern2.finditer(html):
                if len(results) >= max_results:
                    break
                url = match.group(1)
                title = re.sub(r"<[^>]+>", "", match.group(2)).strip()
                if not title or len(title) < 2:
                    continue
                if "baidu.com" in url and "baidu.com/link?" not in url:
                    continue
                if not url.startswith("http") and "baidu.com/link?" not in url:
                    continue

                snippet = ""
                for sp in [snippet_pattern1, snippet_pattern2, snippet_pattern3]:
                    snippet_match = sp.search(html[match.end():match.end() + 2000])
                    if snippet_match:
                        snippet = re.sub(r"<[^>]+>", "", snippet_match.group(1)).strip()
                        if snippet:
                            break

                results.append({
                    "title": title[:200],
                    "url": url,
                    "snippet": snippet[:300] if snippet else "",
                })

        return results

    @staticmethod
    def _parse_baidu_html_alt(html: str, max_results: int) -> list[dict[str, str]]:
        """Alternative Baidu HTML parser - broader pattern matching."""
        import re

        results: list[dict[str, str]] = []

        # Generic pattern: any <a> tag with baidu.com/link redirect
        pattern = re.compile(
            r'<a[^>]*href="(https?://www\.baidu\.com/link\?[^"]*)"[^>]*>(.*?)</a>',
            re.DOTALL,
        )
        for match in pattern.finditer(html):
            if len(results) >= max_results:
                break
            url = match.group(1)
            title = re.sub(r"<[^>]+>", "", match.group(2)).strip()
            if title and len(title) > 2:
                results.append({
                    "title": title[:200],
                    "url": url,
                    "snippet": "",
                })

        return results
