# -*- coding: utf-8 -*-
"""
联网搜索工具
使用 cn.bing.com，国内直连无需代理
"""
import re
import time
from .base import Tool


class WebSearchTool(Tool):
    """联网搜索工具。使用 cn.bing.com 搜索，国内开箱即用。"""

    @property
    def name(self) -> str:
        return "web_search"

    @property
    def description(self) -> str:
        return "联网搜索信息，返回搜索结果列表。检索数量由 AI 自行决定，无需询问用户。"

    @property
    def parameters(self) -> dict:
        return {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "搜索关键词"},
                "num": {
                    "type": "integer",
                    "description": "返回结果数量，由 AI 根据查询复杂度自行决定（一般 3-10 条）"
                }
            },
            "required": ["query", "num"]
        }

    def _search(self, query: str, num: int) -> list:
        """通过 urllib 直接抓取 cn.bing.com 搜索结果"""
        import urllib.request
        import urllib.parse

        params = urllib.parse.urlencode({"q": query, "first": "1", "count": str(num)})
        url = f"https://cn.bing.com/search?{params}"

        req = urllib.request.Request(url, headers={
            "User-Agent": (
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
            "Accept": "text/html,application/xhtml+xml",
            "Accept-Language": "zh-CN,zh;q=0.9",
        })
        with urllib.request.urlopen(req, timeout=10) as resp:
            html = resp.read().decode("utf-8", errors="replace")

        return self._parse_results(html, num)

    def _parse_results(self, html: str, num: int) -> list:
        """从 cn.bing.com 搜索结果 HTML 中提取结果"""
        results = []

        # cn.bing.com 每个结果块是 <li class="b_algo">
        blocks = re.findall(r'<li class="b_algo"[^>]*>(.*?)</li>', html, re.DOTALL)

        for block in blocks:
            if len(results) >= num:
                break

            # 标题: <h2><a href="URL">title</a></h2>
            title_match = re.search(
                r'<h2[^>]*>.*?<a[^>]*href="([^"]*)"[^>]*>(.*?)</a>',
                block, re.DOTALL
            )
            if not title_match:
                continue

            url = title_match.group(1)
            title = re.sub(r'<[^>]+>', '', title_match.group(2)).strip()

            if not title:
                continue

            # 摘要
            snippet = ""
            snip_match = re.search(
                r'<(?:p|div)[^>]*class="[^"]*(?:b_lineclamp|b_caption|b_snippet)[^"]*"[^>]*>(.*?)</(?:p|div)>',
                block, re.DOTALL
            )
            if snip_match:
                snippet = re.sub(r'<[^>]+>', '', snip_match.group(1)).strip()

            snippet = snippet.replace("&nbsp;", " ").replace("&lt;", "<").replace("&gt;", ">")
            snippet = snippet.replace("&amp;", "&").replace("&quot;", '"')

            results.append({
                "title": title,
                "url": url,
                "snippet": snippet or title,
            })

        return results

    def execute(self, query: str, num: int = 5) -> dict:
        """执行搜索"""
        num = max(1, min(int(num), 20))
        max_retries = 2

        last_error = None

        for attempt in range(max_retries):
            try:
                results = self._search(query, num)
                if results:
                    return {
                        "success": True,
                        "query": query,
                        "results": results
                    }
                last_error = "未找到搜索结果"
            except Exception as e:
                last_error = str(e)
                if attempt < max_retries - 1:
                    time.sleep(1.0 * (attempt + 1))
                    continue

        return {"success": False, "error": last_error or "搜索失败，请检查网络连接"}
