"""Centralized logging with rotating file handler and in-memory ring buffer.

Sets up the root logger with:
- Rotating file handler (configurable size and backup count)
- Console handler (stderr)
- Ring-buffer handler (last N lines, retrievable via ``get_ring_buffer()``)
"""

import logging
import os
import threading
from logging.handlers import RotatingFileHandler
from typing import List, Optional

log = logging.getLogger(__name__)

LOG_FORMAT = (
    "%(asctime)s UTC %(filename)s:%(lineno)d - %(levelname)s"
    " - PID %(process)d / %(threadName)s: %(message)s"
)


class RingbufferHandler(logging.Handler):
    """Logging handler that keeps the last *max_lines* formatted messages."""

    def __init__(self, max_lines: int = 1000) -> None:
        super().__init__()
        self._lines: List[str] = []
        self._lock_rw = threading.RLock()
        self._max_lines = max_lines

    def emit(self, record: logging.LogRecord) -> None:
        msg = self.format(record)
        with self._lock_rw:
            self._lines.append(msg)
            overflow = len(self._lines) - self._max_lines
            if overflow > 0:
                del self._lines[:overflow]

    def get(self) -> str:
        with self._lock_rw:
            return "\r\n".join(self._lines) + ("\r\n" if self._lines else "")


class LoggingHelper:
    """Configures the root logger and provides access to the ring buffer."""

    _instance: Optional["LoggingHelper"] = None

    def __init__(
        self,
        log_dir: str = "data/logs/",
        max_bytes: int = 10 * 1024 * 1024,
        backup_count: int = 50,
        ring_buffer_size: int = 1000,
        level: int = logging.INFO,
    ) -> None:
        os.makedirs(log_dir, exist_ok=True)
        log_file = os.path.join(log_dir, "applicationLog.txt")

        formatter = logging.Formatter(LOG_FORMAT)
        root = logging.getLogger()
        root.setLevel(level)

        # File handler
        fh = RotatingFileHandler(
            log_file, mode="a", maxBytes=max_bytes, backupCount=backup_count,
        )
        fh.setFormatter(formatter)
        fh.setLevel(level)
        root.addHandler(fh)

        # Console handler
        ch = logging.StreamHandler()
        ch.setFormatter(formatter)
        ch.setLevel(level)
        root.addHandler(ch)

        # Ring buffer handler
        self._ring = RingbufferHandler(max_lines=ring_buffer_size)
        self._ring.setFormatter(formatter)
        self._ring.setLevel(level)
        root.addHandler(self._ring)

        self._root = root

    # ------------------------------------------------------------------
    # Singleton
    # ------------------------------------------------------------------
    @staticmethod
    def get_instance() -> "LoggingHelper":
        if LoggingHelper._instance is None:
            LoggingHelper._instance = LoggingHelper()
        return LoggingHelper._instance

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------
    def get_ring_buffer(self) -> str:
        """Return the contents of the ring buffer as a single string."""
        return self._ring.get()

    def get_logger(self, name: str | None = None) -> logging.Logger:
        """Return a logger, optionally with a specific *name*."""
        return logging.getLogger(name)
