from abc import ABC, abstractmethod
from typing import Any, Dict, Optional
import structlog


class BaseSink(ABC):
    """Base class for all logging sinks. Each sink type should inherit from this."""
    
    LEVEL_ORDER = {
        'debug': 10,
        'info': 20,
        'warning': 30,
        'error': 40,
        'critical': 50
    }
    
    def __init__(self, sink_config: Dict[str, Any], logger_name: str, level: str, use_json: bool):
        self.sink_config = sink_config
        self.logger_name = logger_name
        # Allow per-sink level override
        self.level = sink_config.get('level', level).lower()
        self.use_json = use_json
        self._struct_logger: Optional[structlog.BoundLogger] = None
        self._initialized = False
        self._level_num = self.LEVEL_ORDER.get(self.level, 20)
    
    @abstractmethod
    def initialize(self) -> None:
        """Initialize the sink (connect, setup resources, etc.)"""
        pass
    
    @abstractmethod
    def shutdown(self) -> None:
        """Cleanup resources"""
        pass
    
    @abstractmethod
    def log(self, level: str, msg: str, **kwargs) -> None:
        """Synchronous logging"""
        pass
    
    @abstractmethod
    async def alog(self, level: str, msg: str, **kwargs) -> None:
        """Asynchronous logging"""
        pass
    
    def _should_log(self, level: str) -> bool:
        """Check if this log level should be processed by this sink"""
        level_num = self.LEVEL_ORDER.get(level.lower(), 20)
        return level_num >= self._level_num
    
    def debug(self, msg: str, **kwargs) -> None:
        if self._should_log('debug'):
            self.log('debug', msg, **kwargs)
    
    def info(self, msg: str, **kwargs) -> None:
        if self._should_log('info'):
            self.log('info', msg, **kwargs)
    
    def warning(self, msg: str, **kwargs) -> None:
        if self._should_log('warning'):
            self.log('warning', msg, **kwargs)
    
    def error(self, msg: str, **kwargs) -> None:
        if self._should_log('error'):
            self.log('error', msg, **kwargs)
    
    def critical(self, msg: str, **kwargs) -> None:
        if self._should_log('critical'):
            self.log('critical', msg, **kwargs)
    
    async def adebug(self, msg: str, **kwargs) -> None:
        if self._should_log('debug'):
            await self.alog('debug', msg, **kwargs)
    
    async def ainfo(self, msg: str, **kwargs) -> None:
        if self._should_log('info'):
            await self.alog('info', msg, **kwargs)
    
    async def awarning(self, msg: str, **kwargs) -> None:
        if self._should_log('warning'):
            await self.alog('warning', msg, **kwargs)
    
    async def aerror(self, msg: str, **kwargs) -> None:
        if self._should_log('error'):
            await self.alog('error', msg, **kwargs)
    
    async def acritical(self, msg: str, **kwargs) -> None:
        if self._should_log('critical'):
            await self.alog('critical', msg, **kwargs)
