import json
import asyncio
from typing import Any, Dict, Optional
from jazzmine.logging.sinks.base_sink import BaseSink
from jazzmine.logging.exceptions import LoggerDependencyError


class RedisLogger(BaseSink):
    """Redis Streams sink"""
    
    def initialize(self) -> None:
        try:
            import redis.asyncio as aioredis
            import redis
            self.redis = redis
            self.aioredis = aioredis
        except ImportError:
            raise LoggerDependencyError(
                "redis is required for Redis sink. Install: pip install redis"
            )
        
        self.host = self.sink_config.get('host', 'localhost')
        self.port = self.sink_config.get('port', 6379)
        self.db = self.sink_config.get('db', 0)
        self.stream_key = self.sink_config.get('stream_key', f'logs:{self.logger_name}')
        self.password = self.sink_config.get('password')
        
        self.sync_client: Optional[Any] = None
        self.async_client: Optional[Any] = None
        self._initialized = True
    
    def shutdown(self) -> None:
        if self.sync_client:
            self.sync_client.close()
        if self.async_client:
            asyncio.create_task(self.async_client.close())
    
    def _format_message(self, level: str, msg: str, **kwargs) -> Dict[str, str]:
        import time
        data = {
            'timestamp': str(time.time()),
            'level': level,
            'logger': self.logger_name,
            'message': msg,
        }
        
        for key, value in kwargs.items():
            data[key] = json.dumps(value) if not isinstance(value, str) else value
        
        return data
    
    def log(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        if not self.sync_client:
            self.sync_client = self.redis.Redis(
                host=self.host,
                port=self.port,
                db=self.db,
                password=self.password,
                decode_responses=True
            )
        
        payload = self._format_message(level, msg, **kwargs)
        
        try:
            self.sync_client.xadd(self.stream_key, payload)
        except Exception:
            pass
    
    async def alog(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        if not self.async_client:
            self.async_client = await self.aioredis.from_url(
                f"redis://{self.host}:{self.port}/{self.db}",
                password=self.password,
                decode_responses=True
            )
        
        payload = self._format_message(level, msg, **kwargs)
        
        try:
            await self.async_client.xadd(self.stream_key, payload)
        except Exception:
            pass
