from __future__ import annotations

import json
import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path
from typing import List, Optional


class LoggingService:
    """
    Central logging setup with optional rotating file output and a small in-memory buffer.
    Designed to be light-weight for on-prem customers; file logging is opt-in via log_dir.
    """

    def __init__(
        self,
        log_dir: Optional[str] = None,
        level: int = logging.INFO,
        log_format: str = "text",
        max_bytes: int = 5 * 1024 * 1024,
        backup_count: int = 3,
        buffer_size: int = 200,
    ) -> None:
        self.level = level
        self.log_dir = Path(log_dir) if log_dir else None
        self.max_bytes = max_bytes
        self.backup_count = backup_count
        self.buffer_size = buffer_size
        self.buffer: List[str] = []
        self.log_format = log_format

        self._formatter = self._build_formatter(log_format)
        self._setup_root()

    def _build_formatter(self, log_format: str) -> logging.Formatter:
        if log_format == "json":
            return _JsonFormatter()
        return logging.Formatter(fmt="%(asctime)s %(levelname)s [%(name)s] %(message)s", datefmt="%Y-%m-%dT%H:%M:%S")

    def _setup_root(self) -> None:
        root = logging.getLogger()
        root.setLevel(self.level)
        # Avoid duplicate handlers if re-initialized
        if not any(isinstance(h, logging.StreamHandler) for h in root.handlers):
            sh = logging.StreamHandler()
            sh.setLevel(self.level)
            sh.setFormatter(self._formatter)
            root.addHandler(sh)

        # Optional file handler
        if self.log_dir:
            self.log_dir.mkdir(parents=True, exist_ok=True)
            file_path = self.log_dir / "agent.log"
            fh = RotatingFileHandler(file_path, maxBytes=self.max_bytes, backupCount=self.backup_count)
            fh.setLevel(self.level)
            fh.setFormatter(self._formatter)
            root.addHandler(fh)

        # In-memory buffer via custom handler
        if not any(isinstance(h, _BufferHandler) for h in root.handlers):
            buf = _BufferHandler(self.buffer, self.buffer_size)
            buf.setLevel(logging.INFO)
            buf.setFormatter(self._formatter)
            root.addHandler(buf)

    def get_logger(self, name: str) -> logging.Logger:
        """Return a logger with the configured handlers."""
        return logging.getLogger(name)

    def get_buffer(self) -> List[str]:
        """Return the current in-memory buffer of recent log lines."""
        return list(self.buffer)


class _BufferHandler(logging.Handler):
    """Simple ring buffer handler to retain recent log lines for CLI display."""

    def __init__(self, store: List[str], max_size: int) -> None:
        super().__init__()
        self.store = store
        self.max_size = max_size

    def emit(self, record: logging.LogRecord) -> None:  # pragma: no cover - trivial
        msg = self.format(record)
        self.store.append(msg)
        if len(self.store) > self.max_size:
            del self.store[0 : len(self.store) - self.max_size]


class _JsonFormatter(logging.Formatter):
    """JSON log formatter with stable keys for enterprise log shipping."""

    def format(self, record: logging.LogRecord) -> str:
        payload = {
            "ts": self.formatTime(record, "%Y-%m-%dT%H:%M:%S"),
            "level": record.levelname,
            "logger": record.name,
            "msg": record.getMessage(),
        }
        return json.dumps(payload)
