"""
ErrorReporter - Main error categorization and handling logic
"""

import re
from enum import Enum
from typing import Any, Dict, Optional

from loguru import logger


class ErrorCategory(Enum):
    """Categories of errors that can occur during research"""

    CONNECTION_ERROR = "connection_error"
    MODEL_ERROR = "model_error"
    SEARCH_ERROR = "search_error"
    SYNTHESIS_ERROR = "synthesis_error"
    FILE_ERROR = "file_error"
    RATE_LIMIT_ERROR = "rate_limit_error"
    UNKNOWN_ERROR = "unknown_error"


class ErrorReporter:
    """
    Analyzes and categorizes errors to provide better user feedback
    """

    def __init__(self):
        self.error_patterns = {
            ErrorCategory.CONNECTION_ERROR: [
                r"POST predict.*EOF",
                r"Connection refused",
                r"timeout",
                r"Connection.*failed",
                r"HTTP error \d+",
                r"network.*error",
                r"\[Errno 111\]",
                r"host\.docker\.internal",
                r"host.*localhost.*Docker",
                r"127\.0\.0\.1.*Docker",
                r"localhost.*1234.*Docker",
                r"LM.*Studio.*Docker.*Mac",
            ],
            ErrorCategory.MODEL_ERROR: [
                r"Model.*not found",
                r"Invalid.*model",
                r"Ollama.*not available",
                r"API key.*invalid",
                r"Authentication.*error",
                r"max_workers must be greater than 0",
                r"TypeError.*Context.*Size",
                r"'<' not supported between",
                r"No auth credentials found",
                r"401.*API key",
            ],
            ErrorCategory.RATE_LIMIT_ERROR: [
                r"429.*resource.*exhausted",
                r"429.*too many requests",
                r"rate limit",
                r"rate_limit",
                r"ratelimit",
                r"quota.*exceeded",
                r"resource.*exhausted.*quota",
                r"threshold.*requests",
                r"LLM rate limit",
                r"API rate limit",
                r"maximum.*requests.*minute",
                r"maximum.*requests.*hour",
            ],
            ErrorCategory.SEARCH_ERROR: [
                r"Search.*failed",
                r"No search results",
                r"Search engine.*error",
                r"The search is longer than 256 characters",
                r"Failed to create search engine",
                r"could not be found",
                r"GitHub API error",
                r"database.*locked",
            ],
            ErrorCategory.SYNTHESIS_ERROR: [
                r"Error.*synthesis",
                r"Failed.*generate",
                r"Synthesis.*timeout",
                r"detailed.*report.*stuck",
                r"report.*taking.*long",
                r"progress.*100.*stuck",
            ],
            ErrorCategory.FILE_ERROR: [
                r"Permission denied",
                r"File.*not found",
                r"Cannot write.*file",
                r"Disk.*full",
                r"No module named.*local_deep_research",
                r"HTTP error 404.*research results",
                r"Attempt to write readonly database",
            ],
        }

    def categorize_error(self, error_message: str) -> ErrorCategory:
        """
        Categorize an error based on its message

        Args:
            error_message: The error message to categorize

        Returns:
            ErrorCategory: The categorized error type
        """
        error_message = str(error_message).lower()

        for category, patterns in self.error_patterns.items():
            for pattern in patterns:
                if re.search(pattern.lower(), error_message):
                    logger.debug(
                        f"Categorized error as {category.value}: {pattern}"
                    )
                    return category

        return ErrorCategory.UNKNOWN_ERROR

    def get_user_friendly_title(self, category: ErrorCategory) -> str:
        """
        Get a user-friendly title for an error category

        Args:
            category: The error category

        Returns:
            str: User-friendly title
        """
        titles = {
            ErrorCategory.CONNECTION_ERROR: "Connection Issue",
            ErrorCategory.MODEL_ERROR: "LLM Service Error",
            ErrorCategory.SEARCH_ERROR: "Search Service Error",
            ErrorCategory.SYNTHESIS_ERROR: "Report Generation Error",
            ErrorCategory.FILE_ERROR: "File System Error",
            ErrorCategory.RATE_LIMIT_ERROR: "API Rate Limit Exceeded",
            ErrorCategory.UNKNOWN_ERROR: "Unexpected Error",
        }
        return titles.get(category, "Error")

    def get_suggested_actions(self, category: ErrorCategory) -> list:
        """
        Get suggested actions for resolving an error

        Args:
            category: The error category

        Returns:
            list: List of suggested actions
        """
        suggestions = {
            ErrorCategory.CONNECTION_ERROR: [
                "Check if the LLM service (Ollama/LM Studio) is running",
                "Verify network connectivity",
                "Try switching to a different model provider",
                "Check the service logs for more details",
            ],
            ErrorCategory.MODEL_ERROR: [
                "Verify the model name is correct",
                "Check if the model is downloaded and available",
                "Validate API keys if using external services",
                "Try switching to a different model",
            ],
            ErrorCategory.SEARCH_ERROR: [
                "Check internet connectivity",
                "Try reducing the number of search results",
                "Wait a moment and try again",
                "Check if search service is configured correctly",
                "For local documents: ensure the path is absolute and folder exists",
                "Try a different search engine if one is failing",
            ],
            ErrorCategory.SYNTHESIS_ERROR: [
                "The research data was collected successfully",
                "Try switching to a different model for report generation",
                "Check the partial results below",
                "Review the detailed logs for more information",
            ],
            ErrorCategory.FILE_ERROR: [
                "Check disk space availability",
                "Verify write permissions",
                "Try changing the output directory",
                "Restart the application",
            ],
            ErrorCategory.RATE_LIMIT_ERROR: [
                "The API has reached its rate limit",
                "Enable LLM Rate Limiting in Settings → Rate Limiting → Enable LLM Rate Limiting",
                "Once enabled, the system will automatically learn and adapt to API limits",
                "Consider upgrading to a paid API plan for higher limits",
                "Try using a different model temporarily",
            ],
            ErrorCategory.UNKNOWN_ERROR: [
                "Check the detailed logs below for more information",
                "Try running the research again",
                "Report this issue if it persists",
                "Contact support with the error details",
            ],
        }
        return suggestions.get(category, ["Check the logs for more details"])

    def analyze_error(
        self, error_message: str, context: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        Perform comprehensive error analysis

        Args:
            error_message: The error message to analyze
            context: Optional context information

        Returns:
            dict: Comprehensive error analysis
        """
        category = self.categorize_error(error_message)

        analysis = {
            "category": category,
            "title": self.get_user_friendly_title(category),
            "original_error": error_message,
            "suggestions": self.get_suggested_actions(category),
            "severity": self._determine_severity(category),
            "recoverable": self._is_recoverable(category),
        }

        # Add context-specific information
        if context:
            analysis["context"] = context
            analysis["has_partial_results"] = bool(
                context.get("findings")
                or context.get("current_knowledge")
                or context.get("search_results")
            )

        return analysis

    def _determine_severity(self, category: ErrorCategory) -> str:
        """Determine error severity level"""
        severity_map = {
            ErrorCategory.CONNECTION_ERROR: "high",
            ErrorCategory.MODEL_ERROR: "high",
            ErrorCategory.SEARCH_ERROR: "medium",
            ErrorCategory.SYNTHESIS_ERROR: "low",  # Can often show partial results
            ErrorCategory.FILE_ERROR: "medium",
            ErrorCategory.RATE_LIMIT_ERROR: "medium",  # Can be resolved with settings
            ErrorCategory.UNKNOWN_ERROR: "high",
        }
        return severity_map.get(category, "medium")

    def _is_recoverable(self, category: ErrorCategory) -> bool:
        """Determine if error is recoverable with user action"""
        recoverable = {
            ErrorCategory.CONNECTION_ERROR: True,
            ErrorCategory.MODEL_ERROR: True,
            ErrorCategory.SEARCH_ERROR: True,
            ErrorCategory.SYNTHESIS_ERROR: True,
            ErrorCategory.FILE_ERROR: True,
            ErrorCategory.RATE_LIMIT_ERROR: True,  # Can enable rate limiting
            ErrorCategory.UNKNOWN_ERROR: False,
        }
        return recoverable.get(category, False)
