"""
浏览器与搜索功能的Function Call包装器

提供访问网页内容或进行简单搜索的工具函数。
"""

import re
import logging
from typing import Optional, Dict

import requests
import base64
import urllib.parse

from ketacli.sdk.ai.function_call import function_registry

logger = logging.getLogger("ketacli.tool.browser")


def _normalize_url(url: str) -> str:
    url = (url or "").strip()
    if not url:
        return url
    if not re.match(r"^https?://", url):
        return f"https://{url}"
    return url


def _extract_title(html: str) -> str:
    m = re.search(r"<title[^>]*>([\s\S]*?)</title>", html, flags=re.IGNORECASE)
    return (m.group(1).strip() if m else "").replace("\n", " ")




@function_registry.register(
    name="browser",
    description="访问网页内容（仅fetch），支持预览、分页与全文输出（由模型选择是否继续）",
    parameters={
        "type": "object",
        "properties": {
            "url": {
                "type": "string",
                "description": "要访问的URL（支持自动补全https://）"
            },
            "timeout": {
                "type": "integer",
                "description": "请求超时时间（秒）",
                "default": 10
            },
            "full": {
                "type": "boolean",
                "description": "是否返回全文（默认false，仅预览）",
                "default": False
            },
            "preview_limit": {
                "type": "integer",
                "description": "预览长度（字符数，默认2000）",
                "default": 2000
            },
            "chunk_size": {
                "type": "integer",
                "description": "分页返回的片段长度（字符数）"
            },
            "cursor": {
                "type": "integer",
                "description": "分页起始光标（默认0）",
                "default": 0
            },
            "raw": {
                "type": "boolean",
                "description": "是否使用原始HTML作为输出（默认false，输出去标签纯文本）",
                "default": False
            },
            "output_file": {
                "type": "string",
                "description": "若提供则将内容写入该文件（按raw选择写入原始或纯文本）"
            },
            "headers": {
                "type": "object",
                "description": "附加HTTP请求头"
            },
        },
        "required": ["url"]
    }
)
def browser(
            url: Optional[str] = None,
            timeout: int = 10,
            headers: Optional[Dict[str, str]] = None,
            full: bool = False,
            preview_limit: int = 2000,
            chunk_size: Optional[int] = None,
            cursor: int = 0,
            raw: bool = False,
            output_file: Optional[str] = None) -> str:
    """访问网页并返回文本结果（支持预览/分页/全文）。搜索功能已禁用。"""

    logger.info(f"browser start: url={url}, timeout={timeout}, full={full}, preview_limit={preview_limit}, chunk_size={chunk_size}, cursor={cursor}, raw={raw}, has_headers={bool(headers)}")

    norm_url = _normalize_url(url or "")
    if not norm_url:
        return "fetch模式需要提供url参数"

    req_headers = {
        "User-Agent": "ketacli/1.0 (+https://github.com/ketaops/ketacli)",
    }
    if headers and isinstance(headers, dict):
        req_headers.update(headers)

    logger.info(f"fetch request: url={norm_url}, headers_keys={list(req_headers.keys())}, timeout={timeout}")
    try:
        resp = requests.get(norm_url, headers=req_headers, timeout=timeout, allow_redirects=True)
    except Exception as e:
        logger.info(f"fetch error: url={norm_url}, error={e}")
        return f"抓取失败: {str(e)}"
    text = resp.text or ""
    title = _extract_title(text)
    content_plain = re.sub(r"<[^>]+>", " ", text)
    content_plain = re.sub(r"\s+", " ", content_plain).strip()
    content = text if raw else content_plain
    content_len = len(content)

    meta = (
        f"status={resp.status_code} size={len(text)} final_url={resp.url}"
    )
    logger.info(f"fetch response: status={resp.status_code}, len={len(text)}, final_url={resp.url}, title={title}, raw={raw}, content_len={content_len}")

    lines = []
    if title:
        lines.append(f"标题: {title}")
    lines.append(f"元信息: {meta}")
    # 写文件（全文）
    if output_file and isinstance(output_file, str) and output_file.strip():
        try:
            import os
            d = os.path.dirname(output_file)
            if d:
                os.makedirs(d, exist_ok=True)
            with open(output_file, "w", encoding="utf-8") as f:
                f.write(content)
            logger.info(f"fetch write_file: path={output_file} bytes={len(content)}")
            lines.append(f"[green]内容已写入: {output_file}[/green]")
        except Exception as fe:
            logger.info(f"fetch write_file error: path={output_file}, error={fe}")
            lines.append(f"写入文件失败: {fe}")

    # 全文
    if full:
        lines.append("内容全文:")
        lines.append(content)
        return "\n".join(lines)

    # 分页
    if isinstance(chunk_size, int) and chunk_size > 0:
        start = max(0, int(cursor or 0))
        end = min(content_len, start + chunk_size)
        chunk = content[start:end]
        has_more = end < content_len
        next_cursor = end if has_more else None
        logger.info(f"fetch chunk: start={start} end={end} chunk_len={len(chunk)} has_more={has_more} next_cursor={next_cursor}")
        lines.append("内容片段:")
        lines.append(chunk)
        lines.append(f"片段信息: start={start} end={end} total={content_len} has_more={has_more} next_cursor={next_cursor}")
        lines.append("提示: 继续查看可再次调用 browser 设置 cursor=next_cursor")
        return "\n".join(lines)

    # 预览
    pl = preview_limit if isinstance(preview_limit, int) and preview_limit > 0 else 800
    preview = content[:pl]
    logger.info(f"fetch preview: preview_limit={pl} preview_len={len(preview)} total={content_len}")
    lines.append("内容预览:")
    lines.append(preview)
    if content_len > pl:
        lines.append(f"提示: 内容较长(total={content_len})；可设置 full=true 或 chunk_size=1024 进行分页查看")
    return "\n".join(lines)
