"""
Error handling utilities for the bot.
"""
import logging
import traceback
from typing import Optional, Callable, Any
from functools import wraps

from aiogram.types import Message, CallbackQuery

logger = logging.getLogger(__name__)


class BotError(Exception):
    """Base exception for bot-related errors."""
    pass


class SurveyError(BotError):
    """Survey-related errors."""
    pass


class StrategyError(BotError):
    """Strategy generation errors."""
    pass


class DatabaseError(BotError):
    """Database operation errors."""
    pass


class LLMError(BotError):
    """LLM service errors."""
    pass


def handle_errors(
    error_message: str = "Произошла ошибка. Попробуйте ещё раз.",
    log_error: bool = True
):
    """
    Decorator for handling errors in bot handlers.
    
    Args:
        error_message: Message to send to user on error
        log_error: Whether to log the error
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        async def wrapper(*args, **kwargs):
            try:
                return await func(*args, **kwargs)
            except Exception as e:
                if log_error:
                    logger.exception("Error in %s: %s", func.__name__, e)
                
                # Try to send error message to user
                try:
                    # Find message or callback query in args
                    for arg in args:
                        if isinstance(arg, (Message, CallbackQuery)):
                            await arg.answer(error_message)
                            break
                except Exception:
                    logger.exception("Failed to send error message to user")
                
                raise
        return wrapper
    return decorator


def safe_async_context_manager(func):
    """
    Decorator for safe async context manager usage.
    """
    @wraps(func)
    async def wrapper(*args, **kwargs):
        try:
            return await func(*args, **kwargs)
        except Exception as e:
            logger.exception("Error in async context manager %s: %s", func.__name__, e)
            raise
    return wrapper


class ErrorHandler:
    """Centralized error handling for the bot."""
    
    @staticmethod
    async def handle_survey_error(
        error: Exception, 
        message: Optional[Message] = None, 
        callback: Optional[CallbackQuery] = None
    ) -> None:
        """Handle survey-related errors."""
        logger.exception("Survey error: %s", error)
        
        error_msg = "Ошибка при обработке анкеты. Попробуйте ещё раз."
        
        if message:
            await message.answer(error_msg)
        elif callback:
            await callback.answer(error_msg, show_alert=True)
    
    @staticmethod
    async def handle_strategy_error(
        error: Exception, 
        message: Optional[Message] = None, 
        callback: Optional[CallbackQuery] = None
    ) -> None:
        """Handle strategy generation errors."""
        logger.exception("Strategy error: %s", error)
        
        error_msg = "Ошибка при генерации стратегии. Попробуйте ещё раз."
        
        if message:
            await message.answer(error_msg)
        elif callback:
            await callback.answer(error_msg, show_alert=True)
    
    @staticmethod
    async def handle_database_error(
        error: Exception, 
        message: Optional[Message] = None, 
        callback: Optional[CallbackQuery] = None
    ) -> None:
        """Handle database errors."""
        logger.exception("Database error: %s", error)
        
        error_msg = "Ошибка базы данных. Попробуйте позже."
        
        if message:
            await message.answer(error_msg)
        elif callback:
            await callback.answer(error_msg, show_alert=True)
    
    @staticmethod
    async def handle_llm_error(
        error: Exception, 
        message: Optional[Message] = None, 
        callback: Optional[CallbackQuery] = None
    ) -> None:
        """Handle LLM service errors."""
        logger.exception("LLM error: %s", error)
        
        error_msg = "Ошибка при обращении к AI. Попробуйте позже."
        
        if message:
            await message.answer(error_msg)
        elif callback:
            await callback.answer(error_msg, show_alert=True)
    
    @staticmethod
    async def handle_audio_error(
        error: Exception, 
        message: Optional[Message] = None, 
        callback: Optional[CallbackQuery] = None
    ) -> None:
        """Handle audio processing errors."""
        logger.exception("Audio error: %s", error)
        
        error_msg = "Ошибка при обработке аудио. Попробуйте отправить текстом."
        
        if message:
            await message.answer(error_msg)
        elif callback:
            await callback.answer(error_msg, show_alert=True)


def log_function_call(func_name: str, **kwargs):
    """
    Log function call with parameters.
    
    Args:
        func_name: Name of the function being called
        **kwargs: Function parameters to log
    """
    logger.debug("Calling %s with params: %s", func_name, kwargs)


def log_function_result(func_name: str, result: Any):
    """
    Log function result.
    
    Args:
        func_name: Name of the function
        result: Function result
    """
    logger.debug("Function %s completed with result: %s", func_name, type(result).__name__)
