# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Brave Search Skill

Web search, news search, and suggestions via the Brave Search API.
High-quality results with privacy focus. Requires API key.

Setup:
    BRAVE_SEARCH_API_KEY=your_key   (get at https://brave.com/search/api/)
    Free tier: ~1,000 queries/month

API: https://api.search.brave.com/res/v1/
"""

import logging

from familiar.core.api_cache import cached
from familiar.skills._api_utils import (
    RATE_LIMITERS,
    APIError,
    api_get,
    get_env,
)

logger = logging.getLogger(__name__)

BASE_URL = "https://api.search.brave.com/res/v1"

_limiter = RATE_LIMITERS["brave_search"]


def _api_key() -> str:
    return get_env("BRAVE_SEARCH_API_KEY") or ""


def _headers() -> dict:
    return {
        "Accept": "application/json",
        "Accept-Encoding": "gzip",
        "X-Subscription-Token": _api_key(),
    }


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def brave_search(data: dict) -> str:
    """Search the web via Brave Search."""
    query = data.get("query", "").strip()
    if not query:
        return "Please provide a search query."

    key = _api_key()
    if not key:
        return (
            "Brave Search API key not configured.\n"
            "Set BRAVE_SEARCH_API_KEY in your environment.\n"
            "Get a free key at: https://brave.com/search/api/"
        )

    count = min(int(data.get("count", 10)), 20)
    freshness = data.get("freshness", "")

    if not _limiter.acquire():
        return f"Brave Search rate limit reached. Try again in {_limiter.wait_time():.0f} seconds."

    try:
        result = _brave_search_cached(query, count, freshness)

        web_results = result.get("web", {}).get("results", [])
        if not web_results:
            return f"No results found for '{query}'."

        lines = [f"**Brave Search: {query}**", ""]

        for i, r in enumerate(web_results[:count], 1):
            title = r.get("title", "Untitled")
            url = r.get("url", "")
            description = r.get("description", "")
            age = r.get("age", "")

            lines.append(f"{i}. **{title}**")
            if url:
                lines.append(f"   {url}")
            if description:
                lines.append(f"   {description[:250]}")
            if age:
                lines.append(f"   _{age}_")
            lines.append("")

        # Include infobox if present
        infobox = result.get("infobox", {})
        if infobox:
            lines.append("---")
            lines.append(f"**{infobox.get('title', '')}**")
            desc = infobox.get("long_desc") or infobox.get("description", "")
            if desc:
                lines.append(desc[:500])
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Brave Search error: %s", e)
        return f"Error searching Brave: {e}"


@cached(prefix="brave_search", ttl=3600)
def _brave_search_cached(query: str, count: int, freshness: str) -> dict:
    params = {"q": query, "count": count}
    if freshness:
        params["freshness"] = freshness
    return api_get(
        f"{BASE_URL}/web/search",
        params=params,
        headers=_headers(),
        service_name="Brave Search",
    )


def brave_news(data: dict) -> str:
    """Search news articles via Brave Search."""
    query = data.get("query", "").strip()
    if not query:
        return "Please provide a news search query."

    key = _api_key()
    if not key:
        return "Brave Search API key not configured.\nSet BRAVE_SEARCH_API_KEY in your environment."

    count = min(int(data.get("count", 10)), 20)
    freshness = data.get("freshness", "pd")  # Default: past day

    if not _limiter.acquire():
        return f"Brave Search rate limit reached. Try again in {_limiter.wait_time():.0f} seconds."

    try:
        result = _brave_news_cached(query, count, freshness)

        news_results = result.get("results", [])
        if not news_results:
            return f"No news found for '{query}'."

        lines = [f"**News: {query}**", ""]

        for i, r in enumerate(news_results[:count], 1):
            title = r.get("title", "Untitled")
            url = r.get("url", "")
            description = r.get("description", "")
            source = r.get("meta_url", {}).get("hostname", "")
            age = r.get("age", "")

            lines.append(f"{i}. **{title}**")
            if source:
                lines.append(f"   Source: {source}")
            if url:
                lines.append(f"   {url}")
            if description:
                lines.append(f"   {description[:250]}")
            if age:
                lines.append(f"   _{age}_")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Brave News error: %s", e)
        return f"Error searching Brave News: {e}"


@cached(prefix="brave_news", ttl=1800)
def _brave_news_cached(query: str, count: int, freshness: str) -> dict:
    params = {"q": query, "count": count}
    if freshness:
        params["freshness"] = freshness
    return api_get(
        f"{BASE_URL}/news/search",
        params=params,
        headers=_headers(),
        service_name="Brave News",
    )


def brave_suggest(data: dict) -> str:
    """Get search suggestions from Brave."""
    query = data.get("query", "").strip()
    if not query:
        return "Please provide a query for suggestions."

    key = _api_key()
    if not key:
        return "Brave Search API key not configured."

    if not _limiter.acquire():
        return "Brave Search rate limit reached."

    try:
        result = _brave_suggest_cached(query)

        suggestions = result.get("results", [])
        if not suggestions:
            return f"No suggestions for '{query}'."

        lines = [f"**Suggestions for '{query}':**", ""]
        for s in suggestions[:10]:
            text = s.get("query", s) if isinstance(s, dict) else str(s)
            lines.append(f"  - {text}")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Brave Suggest error: %s", e)
        return f"Error getting suggestions: {e}"


@cached(prefix="brave_suggest", ttl=3600)
def _brave_suggest_cached(query: str) -> dict:
    return api_get(
        f"{BASE_URL}/suggest/search",
        params={"q": query},
        headers=_headers(),
        service_name="Brave Suggest",
    )


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "brave_search",
        "description": (
            "Search the web using Brave Search API. High-quality, privacy-focused results."
            " Supports freshness filtering (pd=past day, pw=past week, pm=past month,"
            " py=past year). Requires BRAVE_SEARCH_API_KEY."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search query",
                },
                "count": {
                    "type": "integer",
                    "description": "Number of results (1-20, default 10)",
                    "default": 10,
                },
                "freshness": {
                    "type": "string",
                    "description": (
                        "Time filter: pd (past day), pw (past week),"
                        " pm (past month), py (past year). Leave empty for all."
                    ),
                    "default": "",
                },
            },
            "required": ["query"],
        },
        "handler": brave_search,
        "category": "brave_search",
    },
    {
        "name": "brave_news",
        "description": (
            "Search recent news articles via Brave Search."
            " Returns headlines with sources, descriptions, and timestamps."
            " Great for current events and trending topics."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "News search query",
                },
                "count": {
                    "type": "integer",
                    "description": "Number of results (1-20, default 10)",
                    "default": 10,
                },
                "freshness": {
                    "type": "string",
                    "description": "Time filter: pd (past day), pw (past week), pm (past month)",
                    "default": "pd",
                },
            },
            "required": ["query"],
        },
        "handler": brave_news,
        "category": "brave_search",
    },
    {
        "name": "brave_suggest",
        "description": (
            "Get search query suggestions from Brave Search."
            " Useful for expanding search terms or exploring related queries."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Partial query to get suggestions for",
                },
            },
            "required": ["query"],
        },
        "handler": brave_suggest,
        "category": "brave_search",
    },
]
