"""
Base class for all search strategies.
Defines the common interface and shared functionality for different search approaches.
"""

from abc import ABC, abstractmethod
from typing import Callable, Dict, List, Optional

from loguru import logger


class BaseSearchStrategy(ABC):
    """Abstract base class for all search strategies."""

    def __init__(self, all_links_of_system=None):
        """Initialize the base strategy with common attributes."""
        self.progress_callback = None
        self.questions_by_iteration = {}
        # Create a new list if None is provided (avoiding mutable default argument)
        self.all_links_of_system = (
            all_links_of_system if all_links_of_system is not None else []
        )

    def set_progress_callback(
        self, callback: Callable[[str, int, dict], None]
    ) -> None:
        """Set a callback function to receive progress updates."""
        self.progress_callback = callback

    def _update_progress(
        self,
        message: str,
        progress_percent: Optional[int] = None,
        metadata: Optional[dict] = None,
    ) -> None:
        """Send a progress update via the callback if available."""
        if self.progress_callback:
            self.progress_callback(message, progress_percent, metadata or {})

    @abstractmethod
    def analyze_topic(self, query: str) -> Dict:
        """
        Analyze a topic using the strategy's specific approach.

        Args:
            query: The research query to analyze

        Returns:
            Dict containing:
            - findings: List of research findings
            - iterations: Number of iterations completed
            - questions: Questions generated by iteration
            - formatted_findings: Formatted output
            - current_knowledge: Accumulated knowledge
            - error: Optional error message
        """
        pass

    def _validate_search_engine(self) -> bool:
        """
        Validate that the search engine is available and configured.

        Returns:
            bool: True if search engine is available, False otherwise
        """
        if not hasattr(self, "search") or self.search is None:
            error_msg = "Error: No search engine available. Please check your configuration."
            self._update_progress(
                error_msg,
                100,
                {
                    "phase": "error",
                    "error": "No search engine available",
                    "status": "failed",
                },
            )
            return False
        return True

    def _handle_search_error(
        self, error: Exception, question: str, progress_base: int
    ) -> List:
        """
        Handle errors during search execution.

        Args:
            error: The exception that occurred
            question: The question being searched
            progress_base: The current progress percentage

        Returns:
            List: Empty list to continue processing
        """
        error_msg = f"Error during search: {str(error)}"
        logger.error(f"SEARCH ERROR: {error_msg}")
        self._update_progress(
            error_msg,
            progress_base + 2,
            {"phase": "search_error", "error": str(error)},
        )
        return []

    def _handle_analysis_error(
        self, error: Exception, question: str, progress_base: int
    ) -> None:
        """
        Handle errors during result analysis.

        Args:
            error: The exception that occurred
            question: The question being analyzed
            progress_base: The current progress percentage
        """
        error_msg = f"Error analyzing results: {str(error)}"
        logger.info(f"ANALYSIS ERROR: {error_msg}")
        self._update_progress(
            error_msg,
            progress_base + 10,
            {"phase": "analysis_error", "error": str(error)},
        )
