import json
import asyncio
from typing import Any, Dict
import aiohttp
import requests
from jazzmine.logging.sinks.base_sink import BaseSink


class VectorLogger(BaseSink):
    """Vector HTTP sink"""
    
    def initialize(self) -> None:
        self.url = self.sink_config.get('url', 'http://localhost:8686')
        self.session = None
        self._initialized = True
    
    def shutdown(self) -> None:
        if self.session:
            asyncio.create_task(self.session.close())
    
    def _format_payload(self, level: str, msg: str, **kwargs) -> Dict[str, Any]:
        import time
        return {
            'timestamp': time.time(),
            'level': level,
            'message': msg,
            'logger': self.logger_name,
            **kwargs
        }
    
    def log(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            requests.post(self.url, json=payload, timeout=5)
        except Exception:
            pass
    
    async def alog(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        if not self.session:
            self.session = aiohttp.ClientSession()
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            await self.session.post(self.url, json=payload, timeout=aiohttp.ClientTimeout(total=5))
        except Exception:
            pass


class FluentBitLogger(BaseSink):
    """Fluent Bit HTTP input sink"""
    
    def initialize(self) -> None:
        self.url = self.sink_config.get('url', 'http://localhost:2020')
        self.tag = self.sink_config.get('tag', self.logger_name)
        self.session = None
        self._initialized = True
    
    def shutdown(self) -> None:
        if self.session:
            asyncio.create_task(self.session.close())
    
    def _format_payload(self, level: str, msg: str, **kwargs) -> list:
        import time
        return [{
            'date': time.time(),
            'level': level,
            'message': msg,
            'logger': self.logger_name,
            **kwargs
        }]
    
    def log(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            requests.post(f"{self.url}/{self.tag}", json=payload, timeout=5)
        except Exception:
            pass
    
    async def alog(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        if not self.session:
            self.session = aiohttp.ClientSession()
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            await self.session.post(
                f"{self.url}/{self.tag}",
                json=payload,
                timeout=aiohttp.ClientTimeout(total=5)
            )
        except Exception:
            pass


class PromtailLogger(BaseSink):
    """Grafana Promtail HTTP sink (forwards to Loki)"""
    
    def initialize(self) -> None:
        self.url = self.sink_config.get('url', 'http://localhost:3100/loki/api/v1/push')
        self.labels = self.sink_config.get('labels', {'job': self.logger_name})
        self.session = None
        self._initialized = True
    
    def shutdown(self) -> None:
        if self.session:
            asyncio.create_task(self.session.close())
    
    def _format_payload(self, level: str, msg: str, **kwargs) -> Dict[str, Any]:
        import time
        labels = {**self.labels, 'level': level}
        
        log_line = msg
        if kwargs:
            log_line = f"{msg} {json.dumps(kwargs)}"
        
        return {
            'streams': [{
                'stream': labels,
                'values': [[str(int(time.time() * 1e9)), log_line]]
            }]
        }
    
    def log(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            requests.post(self.url, json=payload, timeout=5)
        except Exception:
            pass
    
    async def alog(self, level: str, msg: str, **kwargs) -> None:
        if not self._initialized:
            return
        
        if not self.session:
            self.session = aiohttp.ClientSession()
        
        payload = self._format_payload(level, msg, **kwargs)
        
        try:
            await self.session.post(self.url, json=payload, timeout=aiohttp.ClientTimeout(total=5))
        except Exception:
            pass
