from __future__ import annotations

import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path

from .settings import AppSettings, get_settings


class _MaxLevelFilter(logging.Filter):
    """只允许指定等级及以下日志进入 handler，用于拆分 info 和 error 文件。"""

    def __init__(self, max_level: int):
        super().__init__()
        self.max_level = max_level

    def filter(self, record: logging.LogRecord) -> bool:
        return record.levelno <= self.max_level


class AppLogger:
    """项目统一日志入口，负责初始化 handler 并返回模块 logger。"""

    _configured = False
    _handler_marker = "_financial_system_handler"

    @classmethod
    def configure(cls, settings: AppSettings | None = None) -> None:
        settings = settings or get_settings()
        log_level = getattr(logging, settings.log_level, logging.INFO)
        settings.log_dir.mkdir(parents=True, exist_ok=True)

        handlers = cls._build_handlers(settings)
        app_logger = logging.getLogger("financial_system")
        app_logger.setLevel(log_level)
        app_logger.propagate = False
        cls._replace_handlers(app_logger, handlers)

        cls._configured = True

    @classmethod
    def get_logger(cls, name: str) -> logging.Logger:
        if not cls._configured:
            cls.configure()
        if not name.startswith("financial_system"):
            name = f"financial_system.{name}"
        return logging.getLogger(name)

    @classmethod
    def _build_handlers(cls, settings: AppSettings) -> list[logging.Handler]:
        formatter = logging.Formatter(
            fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )

        info_handler = cls._file_handler(
            settings.log_dir / settings.log_info_file,
            logging.INFO,
            settings,
        )
        info_handler.addFilter(_MaxLevelFilter(logging.WARNING))
        info_handler.setFormatter(formatter)

        error_handler = cls._file_handler(
            settings.log_dir / settings.log_error_file,
            logging.ERROR,
            settings,
        )
        error_handler.setFormatter(formatter)

        handlers: list[logging.Handler] = [info_handler, error_handler]
        if settings.log_console_enabled:
            console_handler = logging.StreamHandler()
            console_handler.setLevel(getattr(logging, settings.log_level, logging.INFO))
            console_handler.setFormatter(formatter)
            setattr(console_handler, cls._handler_marker, True)
            handlers.append(console_handler)

        for handler in handlers:
            setattr(handler, cls._handler_marker, True)
        return handlers

    @staticmethod
    def _file_handler(path: Path, level: int, settings: AppSettings) -> RotatingFileHandler:
        handler = RotatingFileHandler(
            path,
            maxBytes=settings.log_max_bytes,
            backupCount=settings.log_backup_count,
            encoding="utf-8",
        )
        handler.setLevel(level)
        return handler

    @classmethod
    def _replace_handlers(cls, logger: logging.Logger, handlers: list[logging.Handler]) -> None:
        for handler in list(logger.handlers):
            if getattr(handler, cls._handler_marker, False):
                logger.removeHandler(handler)
                handler.close()
        for handler in handlers:
            logger.addHandler(handler)
