import asyncio
import logging
import traceback
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

import structlog

from jazzmine.logging.config import ConfigLoader, ConfigValidator, LoggingConfigurator
from jazzmine.logging.exceptions import LoggerError
from jazzmine.logging.workers import AsyncHttpWorker


class BaseLogger:
    def __init__(self, raw_config: Union[Dict[str, Any], str, Path]):
        self._raw = raw_config
        self.config: Dict[str, Any] = {}
        self._struct_logger: Optional[structlog.BoundLogger] = None
        self._stdlib_logger: Optional[logging.Logger] = None
        self._async_workers: Dict[str, AsyncHttpWorker] = {}
        self._sink_loggers: List[Any] = []

    def resolve_config(self) -> Dict[str, Any]:
        cfg = ConfigLoader.load(self._raw)
        cfg = ConfigLoader.merge_defaults(cfg)
        ConfigValidator.validate(cfg)
        
        self._async_workers = LoggingConfigurator.create_async_workers(cfg)
        self._sink_loggers = LoggingConfigurator.create_sink_loggers(cfg)
        LoggingConfigurator.configure_stdlib(cfg)
        LoggingConfigurator.configure_structlog(cfg, self._async_workers)
        
        name = cfg.get("name", "base")
        self._struct_logger = structlog.get_logger(name)
        self._stdlib_logger = logging.getLogger(name)
        self.config = cfg
        return cfg

    async def start_async_workers(self) -> None:
        for worker in self._async_workers.values():
            await worker.start()
        
        for sink in self._sink_loggers:
            sink.initialize()

    async def shutdown(self, timeout: float = 2.0) -> None:
        for worker in self._async_workers.values():
            try:
                await worker.stop(timeout=timeout)
            except Exception:
                print("Error stopping async http worker:", traceback.format_exc())
        
        for sink in self._sink_loggers:
            try:
                sink.shutdown()
            except Exception:
                print("Error shutting down sink:", traceback.format_exc())

    def _ensure_ready(self) -> None:
        if self._struct_logger is None:
            raise LoggerError("Logger not configured. Call resolve_config() before using it.")

    def debug(self, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        self._struct_logger.debug(msg, **kwargs)
        for sink in self._sink_loggers:
            try:
                sink.debug(msg, **kwargs)
            except Exception:
                pass

    def info(self, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        self._struct_logger.info(msg, **kwargs)
        for sink in self._sink_loggers:
            try:
                sink.info(msg, **kwargs)
            except Exception:
                pass

    def warning(self, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        self._struct_logger.warning(msg, **kwargs)
        for sink in self._sink_loggers:
            try:
                sink.warning(msg, **kwargs)
            except Exception:
                pass

    def error(self, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        self._struct_logger.error(msg, **kwargs)
        for sink in self._sink_loggers:
            try:
                sink.error(msg, **kwargs)
            except Exception:
                pass

    def critical(self, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        self._struct_logger.critical(msg, **kwargs)
        for sink in self._sink_loggers:
            try:
                sink.critical(msg, **kwargs)
            except Exception:
                pass

    async def _async_log(self, level: str, msg: str, **kwargs: Any) -> None:
        self._ensure_ready()
        fn = getattr(self._struct_logger, level)
        await asyncio.to_thread(fn, msg, **kwargs)

    async def adebug(self, msg: str, **kwargs: Any) -> None:
        await self._async_log("debug", msg, **kwargs)
        await asyncio.gather(*[sink.adebug(msg, **kwargs) for sink in self._sink_loggers], return_exceptions=True)

    async def ainfo(self, msg: str, **kwargs: Any) -> None:
        await self._async_log("info", msg, **kwargs)
        await asyncio.gather(*[sink.ainfo(msg, **kwargs) for sink in self._sink_loggers], return_exceptions=True)

    async def awarning(self, msg: str, **kwargs: Any) -> None:
        await self._async_log("warning", msg, **kwargs)
        await asyncio.gather(*[sink.awarning(msg, **kwargs) for sink in self._sink_loggers], return_exceptions=True)

    async def aerror(self, msg: str, **kwargs: Any) -> None:
        await self._async_log("error", msg, **kwargs)
        await asyncio.gather(*[sink.aerror(msg, **kwargs) for sink in self._sink_loggers], return_exceptions=True)

    async def acritical(self, msg: str, **kwargs: Any) -> None:
        await self._async_log("critical", msg, **kwargs)
        await asyncio.gather(*[sink.acritical(msg, **kwargs) for sink in self._sink_loggers], return_exceptions=True)

    def get_structlog(self) -> structlog.BoundLogger:
        self._ensure_ready()
        return self._struct_logger

    def get_stdlib(self) -> logging.Logger:
        self._ensure_ready()
        return self._stdlib_logger
