"""Logging configuration for FenLiu application.

This module provides centralized logging setup with:
- DEBUG level logs written to file with daily rotation (3 versions kept), formatted as JSON
- Console output showing INFO and ERROR levels only, formatted as human-readable text
- Formatted logs including module, class/method, and line number information
"""

from __future__ import annotations

import json
import logging
import logging.handlers
import sys
from datetime import UTC
from datetime import datetime
from pathlib import Path


class ContextualLogFormatter(logging.Formatter):
    """Custom formatter that includes module, class/method, and line number."""

    def format(self, record: logging.LogRecord) -> str:
        """Format log record with contextual information."""
        # Remove 'fenliu.' prefix from module name for cleaner output
        module_name = record.name.replace("fenliu.", "") if record.name else "root"
        func_name = record.funcName if record.funcName != "<module>" else None

        # Build context string
        if func_name:
            context = f"{module_name}.{func_name}"
        else:
            context = module_name

        # Create formatted message
        timestamp = self.formatTime(record, self.datefmt)
        return f"{timestamp} - {context}:{record.lineno} - {record.levelname} - {record.getMessage()}"


class JSONFormatter(logging.Formatter):
    """Formats log records as JSON lines for structured debug logging."""

    # Fields added by LogRecord that are not useful in the JSON output
    _SKIP_FIELDS = frozenset(
        {
            "args",
            "created",
            "exc_info",
            "exc_text",
            "filename",
            "levelno",
            "lineno",
            "message",
            "module",
            "msecs",
            "msg",
            "name",
            "pathname",
            "process",
            "processName",
            "relativeCreated",
            "stack_info",
            "taskName",
            "thread",
            "threadName",
        }
    )

    def format(self, record: logging.LogRecord) -> str:
        """Serialize the log record to a JSON line."""
        record.message = record.getMessage()
        if record.exc_info:
            record.exc_text = self.formatException(record.exc_info)

        module_name = record.name.replace("fenliu.", "") if record.name else "root"
        func_name = record.funcName if record.funcName != "<module>" else None

        entry: dict[str, object] = {
            "timestamp": datetime.fromtimestamp(record.created, tz=UTC).isoformat(),
            "level": record.levelname,
            "logger": module_name,
            "function": func_name,
            "line": record.lineno,
            "message": record.message,
        }

        if record.exc_text:
            entry["exception"] = record.exc_text

        # Include any extra fields bound to the record
        for key, value in record.__dict__.items():
            if key not in self._SKIP_FIELDS and not key.startswith("_"):
                entry[key] = value

        return json.dumps(entry, default=str)


class _ExcludeUvicornFilter(logging.Filter):
    """Rejects log records emitted by uvicorn's own loggers."""

    def filter(self, record: logging.LogRecord) -> bool:
        return not record.name.startswith("uvicorn")


def setup_logging(debug: bool = False, log_dir: str | Path = "logs") -> logging.Logger:
    """Configure logging with file and console handlers.

    Args:
        debug: If True, enables debug mode with file logging at DEBUG level
        log_dir: Directory to store debug log files

    Returns:
        Configured logger instance for the fenliu module

    """
    # Ensure log directory exists
    log_path = Path(log_dir)
    log_path.mkdir(parents=True, exist_ok=True)

    # Get the root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)  # Capture all levels, handlers will filter

    # Remove any existing handlers to prevent duplicates
    root_logger.handlers.clear()

    # Create formatter
    formatter = ContextualLogFormatter(datefmt="%Y-%m-%d %H:%M:%S")

    # Console handler - INFO and ERROR only
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(formatter)
    root_logger.addHandler(console_handler)

    # File handler - DEBUG level with daily rotation, structured JSON (debug mode only)
    if debug:
        debug_log_file = log_path / "fenliu_debug.log"
        file_handler = logging.handlers.TimedRotatingFileHandler(
            filename=str(debug_log_file),
            when="midnight",  # Rotate at midnight daily
            interval=1,
            backupCount=3,  # Keep 3 old versions (current + 2 backups)
            encoding="utf-8",
        )
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(JSONFormatter())
        file_handler.addFilter(_ExcludeUvicornFilter())
        root_logger.addHandler(file_handler)

    return root_logger


def get_logger(name: str) -> logging.Logger:
    """Get a logger instance for a specific module.

    Args:
        name: The module name (__name__ typically)

    Returns:
        Logger instance for the module

    """
    return logging.getLogger(name)
