from typing import Any, Dict, List, Optional

from langchain_community.tools import BraveSearch
from langchain_core.language_models import BaseLLM
from loguru import logger

from ..rate_limiting import RateLimitError
from ..search_engine_base import BaseSearchEngine


class BraveSearchEngine(BaseSearchEngine):
    """Brave search engine implementation with two-phase approach"""

    # Mark as public search engine
    is_public = True
    # Mark as generic search engine (general web search)
    is_generic = True
    # secrets to redact from error messages (see BaseSearchEngine._scrub_error)
    _secret_attrs = ("_brave_api_key",)

    def __init__(
        self,
        max_results: int = 10,
        region: str = "US",
        time_period: str = "y",
        safe_search: bool = True,
        search_language: str = "English",
        api_key: Optional[str] = None,
        language_code_mapping: Optional[Dict[str, str]] = None,
        llm: Optional[BaseLLM] = None,
        include_full_content: bool = True,
        max_filtered_results: Optional[int] = None,
        settings_snapshot: Optional[Dict[str, Any]] = None,
        **kwargs,
    ):
        """
        Initialize the Brave search engine.

        Args:
            max_results: Maximum number of search results
            region: Region code for search results
            time_period: Time period for search results
            safe_search: Whether to enable safe search
            search_language: Language for search results
            api_key: Brave Search API key (can also be set via LDR_SEARCH_ENGINE_WEB_BRAVE_API_KEY env var or in UI settings)
            language_code_mapping: Mapping from language names to codes
            llm: Language model for relevance filtering
            include_full_content: Whether to include full webpage content in results
            max_filtered_results: Maximum number of results to keep after filtering
            settings_snapshot: Settings snapshot for thread context
            **kwargs: Additional parameters (ignored but accepted for compatibility)
        """
        # Initialize the BaseSearchEngine with LLM, max_filtered_results, and max_results
        super().__init__(
            llm=llm,
            max_filtered_results=max_filtered_results,
            max_results=max_results,
            include_full_content=include_full_content,
            settings_snapshot=settings_snapshot,
        )

        # Set up language code mapping
        if language_code_mapping is None:
            from ...utilities.search_utilities import LANGUAGE_CODE_MAP

            language_code_mapping = LANGUAGE_CODE_MAP

        # Get API key - check params, settings, or env vars
        brave_api_key = self._resolve_api_key(
            api_key,
            "search.engine.web.brave.api_key",
            engine_name="Brave Search",
            settings_snapshot=settings_snapshot,
        )
        self._brave_api_key = brave_api_key

        # Get language code
        language_code = language_code_mapping.get(search_language.lower(), "en")

        # Convert time period format to Brave's format
        brave_time_period = f"p{time_period}"

        # Convert safe search to Brave's format
        brave_safe_search = "moderate" if safe_search else "off"

        # Initialize Brave Search
        self.engine = BraveSearch.from_api_key(
            api_key=brave_api_key,
            search_kwargs={
                "count": min(20, max_results),
                "country": region.upper(),
                "search_lang": language_code,
                "safesearch": brave_safe_search,
                "freshness": brave_time_period,
            },
        )

        # User agent is not needed for Brave Search API

        # If full content is requested, initialize FullSearchResults
        self._init_full_search(
            web_search=self.engine,
            language=search_language,
            max_results=max_results,
            region=region,
            time_period=time_period,
            safe_search=brave_safe_search,
        )

    def _get_previews(self, query: str) -> List[Dict[str, Any]]:
        """
        Get preview information from Brave Search.

        Args:
            query: The search query

        Returns:
            List of preview dictionaries
        """
        logger.info("Getting search results from Brave Search")

        try:
            # Get search results from Brave Search
            raw_results = self.engine.run(query[:400])

            # Parse results if they're in string format
            if isinstance(raw_results, str):
                try:
                    import json

                    raw_results = json.loads(raw_results)
                except json.JSONDecodeError as e:
                    safe_msg = self._scrub_error(e)
                    logger.warning(
                        f"Unable to parse BraveSearch response as JSON: {safe_msg}"
                    )
                    return []

            # Format results as previews
            previews = []
            for i, result in enumerate(raw_results):
                preview = {
                    "id": i,  # Use index as ID
                    "title": result.get("title", ""),
                    "link": result.get("link", ""),
                    "snippet": result.get("snippet", ""),
                    "displayed_link": result.get("link", ""),
                    "position": i,
                }

                # Store full Brave result for later
                preview["_full_result"] = result

                previews.append(preview)

            # Store the previews for potential full content retrieval
            self._search_results = previews

            return previews

        except RateLimitError:
            raise
        except Exception as e:
            safe_msg = self._scrub_error(e)
            logger.warning(f"Error getting Brave Search results: {safe_msg}")
            self._raise_if_rate_limit(e)
            return []
