# SPDX-License-Identifier: AGPL-3.0-or-later
"""Engine to search using the Brave (WEB) Search API.

.. _Brave Search API: https://api-dashboard.search.brave.com/documentation

Configuration
=============

The engine has the following mandatory setting:

- :py:obj:`api_key`

Optional settings are:

- :py:obj:`results_per_page`

.. code:: yaml

  - name: braveapi
    engine: braveapi
    api_key: 'YOUR-API-KEY'  # required
    results_per_page: 20     # optional

The API supports paging and time filters.
"""

import typing as t

from urllib.parse import urlencode
from dateutil import parser

from searx.exceptions import SearxEngineAPIException
from searx.result_types import EngineResults
from searx.utils import html_to_text

if t.TYPE_CHECKING:
    from searx.extended_types import SXNG_Response
    from searx.search.processors import OnlineParams

about = {
    "website": "https://api.search.brave.com/",
    "wikidata_id": None,
    "official_api_documentation": "https://api-dashboard.search.brave.com/documentation",
    "use_official_api": True,
    "require_api_key": True,
    "results": "JSON",
}

api_key: str = ""
"""API key for Brave Search API (required)."""

categories = ["general", "web"]
paging = True
safesearch = True
time_range_support = True

results_per_page: int = 20
"""Maximum number of results per page (default 20)."""

base_url = "https://api.search.brave.com/res/v1/web/search"
"""Base URL for the Brave Search API."""

time_range_map = {"day": "past_day", "week": "past_week", "month": "past_month", "year": "past_year"}
"""Mapping of SearXNG time ranges to Brave API time ranges."""


def init(_):
    """Initialize the engine."""
    if not api_key:
        raise SearxEngineAPIException("No API key provided")


def request(query: str, params: "OnlineParams") -> None:
    """Create the API request."""
    search_args: dict[str, str | int | None] = {
        "q": query,
        "count": results_per_page,
        "offset": (params["pageno"] - 1) * results_per_page,
        "text_decorations": False,
    }

    # Apply time filter if specified
    if params["time_range"]:
        search_args["time_range"] = time_range_map.get(params["time_range"])

    # Apply SafeSearch if enabled
    if params["safesearch"]:
        search_args["safesearch"] = "strict"

    params["url"] = f"{base_url}?{urlencode(search_args)}"
    params["headers"]["X-Subscription-Token"] = api_key


def _extract_published_date(published_date_raw: str):
    """Extract and parse the published date from the API response.

    Args:
        published_date_raw: Raw date string from the API

    Returns:
        Parsed datetime object or None if parsing fails
    """
    if not published_date_raw:
        return None

    try:
        return parser.parse(published_date_raw)
    except parser.ParserError:
        return None


def response(resp: "SXNG_Response") -> EngineResults:
    """Process the API response and return results."""
    res = EngineResults()
    data = resp.json()

    for result in (data.get("web") or {}).get("results", []):
        thumbnail_obj = result.get("thumbnail")
        thumbnail = ""
        if thumbnail_obj and not thumbnail_obj.get("logo", False):
            thumbnail = thumbnail_obj.get("src") or ""

        res.add(
            res.types.MainResult(
                url=result["url"],
                title=html_to_text(result["title"]),
                content=html_to_text(result.get("description", "")),
                publishedDate=_extract_published_date(result.get("age")),
                thumbnail=thumbnail,
            ),
        )

    return res
