"""
logger_setup.py

Central logging configuration for this project (trade_bot). Every
module calls get_logger(__name__) to get a consistently formatted
logger that writes to both console and a log file under logs/.

Deliberately its own logger namespace ("trade_bot", not "sip_bot") so
this project's logs can never be mixed up with or accidentally routed
into screener/premarket's logging even if both processes run on the
same host at the same time.

Log files are one dated file per trading day (logs/{filename_prefix}_
YYYY-MM-DD.log), the day boundary anchored to market_time's America/
New_York clock rather than naive server-local time. Old daily files
beyond logging.retention_days are pruned on startup.
"""

import glob
import logging
import os
from datetime import date
from pathlib import Path

import market_time
from config_loader import get_config

_CONFIGURED = False


class _DailyFileHandler(logging.Handler):
    def __init__(self, log_dir: Path, prefix: str, encoding: str = "utf-8"):
        super().__init__()
        self._log_dir = log_dir
        self._prefix = prefix
        self._encoding = encoding
        self._current_date = None
        self._file_handler = None

    def _path_for(self, day: date) -> Path:
        return self._log_dir / f"{self._prefix}_{day.isoformat()}.log"

    def _ensure_current_file(self):
        today = market_time.now_et().date()
        if self._file_handler is not None and self._current_date == today:
            return
        if self._file_handler is not None:
            self._file_handler.close()
        self._current_date = today
        self._file_handler = logging.FileHandler(
            self._path_for(today), mode="a", encoding=self._encoding
        )
        self._file_handler.setFormatter(self.formatter)

    def setFormatter(self, fmt):
        super().setFormatter(fmt)
        if self._file_handler is not None:
            self._file_handler.setFormatter(fmt)

    def emit(self, record):
        try:
            self._ensure_current_file()
            self._file_handler.emit(record)
        except Exception:
            self.handleError(record)

    def close(self):
        if self._file_handler is not None:
            self._file_handler.close()
        super().close()


def _prune_old_logs(log_dir: Path, prefix: str, retention_days):
    if not retention_days or retention_days <= 0:
        return
    cutoff_ordinal = market_time.now_et().date().toordinal() - retention_days
    for path in glob.glob(str(log_dir / f"{prefix}_*.log")):
        stem = os.path.basename(path)[len(prefix) + 1:-len(".log")]
        try:
            file_date = date.fromisoformat(stem)
        except ValueError:
            continue
        if file_date.toordinal() < cutoff_ordinal:
            try:
                os.remove(path)
            except OSError:
                pass


def _configure_root():
    global _CONFIGURED
    if _CONFIGURED:
        return
    cfg = get_config()
    log_cfg = cfg.get("logging", {})
    log_dir = Path(__file__).resolve().parent / log_cfg.get("log_dir", "logs")
    log_dir.mkdir(parents=True, exist_ok=True)

    level = getattr(logging, log_cfg.get("level", "INFO").upper(), logging.INFO)
    prefix = log_cfg.get("filename_prefix", "trade_bot")

    root = logging.getLogger("trade_bot")
    root.setLevel(level)
    root.propagate = False

    fmt = logging.Formatter(
        "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    console = logging.StreamHandler()
    console.setFormatter(fmt)
    root.addHandler(console)

    file_handler = _DailyFileHandler(log_dir, prefix)
    file_handler.setFormatter(fmt)
    root.addHandler(file_handler)

    _prune_old_logs(log_dir, prefix, log_cfg.get("retention_days", 30))

    _CONFIGURED = True


def get_logger(name: str) -> logging.Logger:
    _configure_root()
    return logging.getLogger(f"trade_bot.{name}")
