#!/usr/bin/env python3
"""Encrypted log writer for SystemMonitor. Named bb_logging to avoid shadowing stdlib logging."""

import logging
import os
import time
from pathlib import Path
from typing import Optional


LOG_FORMAT = "[{timestamp}] [{module}] [{level}] {message}"
MAX_LOG_SIZE = 10 * 1024 * 1024  # 10MB default rotation size
LOG_DIR = "storage/logs"


class EncryptedLogHandler(logging.Handler):
    def __init__(
        self,
        module_name: str,
        log_dir: str = LOG_DIR,
        max_bytes: int = MAX_LOG_SIZE,
        encrypt: bool = False,
        crypto_engine=None,
    ):
        super().__init__()
        self.module_name = module_name
        self.log_dir = Path(log_dir)
        self.log_dir.mkdir(parents=True, exist_ok=True)
        self.max_bytes = max_bytes
        self.encrypt = encrypt
        self.crypto_engine = crypto_engine
        self._log_path = self.log_dir / f"{module_name}.log"
        self._file = None
        self._current_size = 0
        self._open_file()

    def _open_file(self):
        if self._file:
            self._file.close()
        mode = "ab" if self.encrypt else "a"
        self._file = open(self._log_path, mode)
        self._current_size = self._log_path.stat().st_size if self._log_path.exists() else 0

    def _rotate(self):
        if self._file:
            self._file.close()
        rotated = self._log_path.with_suffix(f".log.{int(time.time())}")
        if self._log_path.exists():
            self._log_path.rename(rotated)
        self._open_file()

    def emit(self, record):
        try:
            ts = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(record.created))
            line = LOG_FORMAT.format(
                timestamp=ts,
                module=self.module_name,
                level=record.levelname,
                message=record.getMessage(),
            )
            if self.encrypt and self.crypto_engine:
                data = self.crypto_engine.encrypt(line.encode("utf-8"))
                length_prefix = len(data).to_bytes(4, "big")
                self._file.write(length_prefix)
                self._file.write(data)
                self._current_size += 4 + len(data)
            else:
                line += "\n"
                self._file.write(line)
                self._current_size += len(line.encode("utf-8"))

            self._file.flush()

            if self._current_size >= self.max_bytes:
                self._rotate()
        except Exception:
            self.handleError(record)

    def close(self):
        if self._file:
            self._file.close()
            self._file = None
        super().close()


class BBLogger:
    def __init__(
        self,
        module_name: str,
        log_dir: str = LOG_DIR,
        max_bytes: int = MAX_LOG_SIZE,
        level: int = logging.INFO,
        encrypt: bool = False,
        crypto_engine=None,
        suppress_stdout: bool = True,
    ):
        self.module_name = module_name
        self.logger = logging.getLogger(f"sensor.{module_name}")
        self.logger.setLevel(level)
        self.logger.propagate = False

        # Clear existing handlers to prevent duplicates
        self.logger.handlers.clear()

        self._file_handler = EncryptedLogHandler(
            module_name=module_name,
            log_dir=log_dir,
            max_bytes=max_bytes,
            encrypt=encrypt,
            crypto_engine=crypto_engine,
        )
        self._file_handler.setLevel(level)
        self.logger.addHandler(self._file_handler)

        if not suppress_stdout:
            console = logging.StreamHandler()
            console.setLevel(level)
            fmt = logging.Formatter(
                "[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s",
                datefmt="%Y-%m-%d %H:%M:%S",
            )
            console.setFormatter(fmt)
            self.logger.addHandler(console)

    def debug(self, msg: str, *args, **kwargs):
        self.logger.debug(msg, *args, **kwargs)

    def info(self, msg: str, *args, **kwargs):
        self.logger.info(msg, *args, **kwargs)

    def warning(self, msg: str, *args, **kwargs):
        self.logger.warning(msg, *args, **kwargs)

    def error(self, msg: str, *args, **kwargs):
        self.logger.error(msg, *args, **kwargs)

    def critical(self, msg: str, *args, **kwargs):
        self.logger.critical(msg, *args, **kwargs)

    def set_level(self, level: int):
        self.logger.setLevel(level)
        self._file_handler.setLevel(level)

    def close(self):
        self._file_handler.close()
        self.logger.removeHandler(self._file_handler)
