"""Logging initialisation — file + console handlers with session isolation."""

from __future__ import annotations

import logging
import platform
import sys
from pathlib import Path

from app.config import APP_NAME, APP_VERSION, MAX_LOG_FILES

_LOG_FORMAT = "%(asctime)s.%(msecs)03d [%(levelname)-7s] %(name)s: %(message)s"
_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"

_console_handler: logging.StreamHandler | None = None


def setup_logging(log_dir: Path, session_id: str) -> Path:
    """
    Configure the root logger for a new session.

    Creates:
        <log_dir>/duck-preview_<session_id>.log  — DEBUG level, all messages
        console StreamHandler                     — WARNING by default

    Prunes oldest log files when count exceeds MAX_LOG_FILES.

    Args:
        log_dir:    Directory where log files are stored.
        session_id: Timestamp string used as filename suffix (e.g. "2026-05-12_14-30-00").

    Returns:
        Path to the created log file.
    """
    global _console_handler

    log_dir.mkdir(parents=True, exist_ok=True)
    log_path = log_dir / f"duck-preview_{session_id}.log"

    root = logging.getLogger()
    root.setLevel(logging.DEBUG)  # handlers filter individually

    formatter = logging.Formatter(_LOG_FORMAT, datefmt=_DATE_FORMAT)

    # --- File handler — always DEBUG ---
    file_handler = logging.FileHandler(log_path, encoding="utf-8")
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(formatter)
    root.addHandler(file_handler)

    # --- Console handler — WARNING by default, toggled by Debug menu ---
    _console_handler = logging.StreamHandler(sys.stdout)
    _console_handler.setLevel(logging.WARNING)
    _console_handler.setFormatter(formatter)
    root.addHandler(_console_handler)

    # Write session header to file
    _write_session_header(log_path, session_id)

    # Prune old log files
    _prune_old_logs(log_dir, log_path)

    return log_path


def set_console_level(debug: bool) -> None:
    """Toggle console handler between DEBUG and WARNING (called from Debug menu)."""
    if _console_handler is not None:
        _console_handler.setLevel(logging.DEBUG if debug else logging.WARNING)


def _write_session_header(log_path: Path, session_id: str) -> None:
    """Write a human-readable header block at the top of the log file."""
    try:
        import PySide6
        pyside_version = PySide6.__version__
    except Exception:
        pyside_version = "unknown"

    try:
        import psutil
        mem = psutil.virtual_memory()
        cpu_count = psutil.cpu_count(logical=True)
        mem_total_gb = mem.total / (1024 ** 3)
        hw_info = f"{cpu_count} logical CPUs, {mem_total_gb:.1f} GB RAM"
    except Exception:
        hw_info = "unknown"

    lines = [
        "=" * 72,
        f"  {APP_NAME} {APP_VERSION}",
        f"  Session: {session_id}",
        "=" * 72,
        f"  Platform : {platform.platform()}",
        f"  Python   : {sys.version.split()[0]}",
        f"  PySide6  : {pyside_version}",
        f"  Hardware : {hw_info}",
        f"  Log file : {log_path.resolve()}",
        "=" * 72,
        "",
    ]
    with log_path.open("w", encoding="utf-8") as f:
        f.write("\n".join(lines) + "\n")


def _prune_old_logs(log_dir: Path, current: Path) -> None:
    """Delete oldest .log files if total count exceeds MAX_LOG_FILES."""
    log_files = sorted(
        [p for p in log_dir.glob("duck-preview_*.log") if p != current],
        key=lambda p: p.stat().st_mtime,
    )
    excess = len(log_files) - (MAX_LOG_FILES - 1)
    for path in log_files[:excess]:
        try:
            path.unlink()
            logging.getLogger(__name__).debug("Pruned old log: %s", path.name)
        except OSError:
            pass
