import logging
import re

from fastmcp import FastMCP

from gsearch_mcp_cli import shared
from gsearch_mcp_cli.exceptions import GSearchError

logger = logging.getLogger(__name__)

MCP_INSTRUCTIONS = """Google Search MCP — search Google and fetch web pages.

Tools:
- gsearch_search: Combined Google Search with AI Overview + organic results
- gsearch_ai: Google AI Mode (g.ai) synthesized response with citations
- gsearch_fetch: Fetch any URL and convert to clean Markdown

First search may take ~10s (browser warmup). Subsequent searches are fast (~3s).
Rate limited to 1 search/2 seconds by default.
"""

mcp = FastMCP("gsearch-mcp", instructions=MCP_INSTRUCTIONS)


def sanitize_error(e: Exception) -> str:
    """Strip file paths, PIDs, port numbers from error messages."""
    msg = str(e)
    msg = re.sub(r'/[\w/.\-]+', '<path>', msg)
    msg = re.sub(r'\bpid\s*\d+', 'pid <hidden>', msg, flags=re.IGNORECASE)
    msg = re.sub(r'\bport\s*\d+', 'port <hidden>', msg, flags=re.IGNORECASE)
    msg = re.sub(r'\b\d{4,5}\b', '<num>', msg)
    return msg


@mcp.tool()
async def gsearch_search(
    query: str,
    max_results: int = 10,
    include_ai: bool = True,
    language: str = "en",
    region: str | None = None,
    search_type: str | None = None,
    time_filter: str | None = None,
    date_from: str | None = None,
    date_to: str | None = None,
    timeout_seconds: int = 30,
) -> dict:
    """Search Google: returns AI Overview + organic results with snippets and URLs.

    Use this for general web searches. Returns structured results with titles,
    URLs, snippets, AI-generated overview, People Also Ask, and related searches.

    Args:
        query: Search query
        max_results: Maximum organic results to return
        include_ai: Include AI Overview in results
        language: Search language code (e.g., "en", "fr", "de")
        region: Search region code (e.g., "US", "CA", "GB")
        search_type: Search vertical — "all" (default), "news", "images", "videos",
                     "shopping", "books", "forums", "short_videos"
        time_filter: Filter by time — "hour", "day", "week", "month", "year"
        date_from: Custom date range start — "YYYY-MM-DD"
        date_to: Custom date range end — "YYYY-MM-DD"
        timeout_seconds: Operation timeout
    """
    try:
        result = await shared.search(
            query=query,
            max_results=max_results,
            include_ai=include_ai,
            language=language,
            region=region,
            search_type=search_type,
            time_filter=time_filter,
            date_from=date_from,
            date_to=date_to,
            timeout=float(timeout_seconds),
        )
        return result.model_dump()
    except GSearchError as e:
        logger.error(f"gsearch_search error: {e}")
        return {"error": sanitize_error(e)}


@mcp.tool()
async def gsearch_ai(
    query: str,
    language: str = "en",
    time_filter: str | None = None,
    date_from: str | None = None,
    date_to: str | None = None,
    timeout_seconds: int = 30,
) -> dict:
    """Google AI Mode search: returns synthesized AI response with cited sources.

    Use this for questions that benefit from AI synthesis. Returns a comprehensive
    AI-generated answer with structured sections, bullet points, and source citations.
    Equivalent to searching on g.ai.

    Args:
        query: Search query
        language: Search language code
        time_filter: Filter by time — "hour", "day", "week", "month", "year"
        date_from: Custom date range start — "YYYY-MM-DD"
        date_to: Custom date range end — "YYYY-MM-DD"
        timeout_seconds: Operation timeout
    """
    try:
        result = await shared.ai_search(
            query=query,
            language=language,
            time_filter=time_filter,
            date_from=date_from,
            date_to=date_to,
            timeout=float(timeout_seconds),
        )
        return result.model_dump()
    except GSearchError as e:
        logger.error(f"gsearch_ai error: {e}")
        return {"error": sanitize_error(e)}


@mcp.tool()
async def gsearch_fetch(
    url: str,
    format: str = "md",
    use_browser: str = "auto",
    timeout_seconds: int = 30,
) -> dict:
    """Fetch a URL and convert to clean Markdown (or text).

    Use after searching to get full page content from a result URL.
    Extracts main content, strips navigation/ads, converts to Markdown.

    Args:
        url: URL to fetch (https:// only for security)
        format: "md" for Markdown, "text" for plain text, "raw_html" for raw HTML
        use_browser: "auto", "always" (JS-heavy sites), or "never" (faster)
        timeout_seconds: Request timeout
    """
    try:
        result = await shared.fetch(
            url=url,
            format=format,
            use_browser=use_browser,
            timeout=float(timeout_seconds),
        )
        return result.model_dump()
    except GSearchError as e:
        logger.error(f"gsearch_fetch error: {e}")
        return {"error": sanitize_error(e)}
