"""Structured logging setup for TipSharks Elo API.

Provides JSON and text logging with contextual fields for traceability.
"""

import logging
import sys
from typing import Any

from pythonjsonlogger import jsonlogger

from packages.core.common.settings import get_settings


class CustomJsonFormatter(jsonlogger.JsonFormatter):
    """Custom JSON formatter with additional fields."""

    def add_fields(
        self,
        log_record: dict[str, Any],
        record: logging.LogRecord,
        message_dict: dict[str, Any],
    ) -> None:
        """Add custom fields to log record."""
        super().add_fields(log_record, record, message_dict)
        log_record["level"] = record.levelname
        log_record["logger"] = record.name


def setup_logging() -> None:
    """Configure application logging based on settings."""
    settings = get_settings()

    # Get root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, settings.logging.level.upper()))

    # Remove existing handlers
    root_logger.handlers = []

    # Create console handler
    handler = logging.StreamHandler(sys.stdout)

    # Set formatter based on config
    if settings.logging.format.lower() == "json":
        formatter = CustomJsonFormatter(
            "%(timestamp)s %(level)s %(name)s %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )
    else:
        formatter = logging.Formatter(
            "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )

    handler.setFormatter(formatter)
    root_logger.addHandler(handler)

    # Reduce noise from third-party libraries
    logging.getLogger("httpx").setLevel(logging.WARNING)
    logging.getLogger("httpcore").setLevel(logging.WARNING)
    logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING)


def get_logger(name: str) -> logging.Logger:
    """Get a logger instance with the given name.

    Args:
        name: Logger name (typically __name__)

    Returns:
        Logger instance
    """
    return logging.getLogger(name)


def log_slow_query(
    query: str,
    duration_ms: float,
    params: Any = None,
) -> None:
    """Log a slow query at WARNING level with structured fields.

    Args:
        query: The SQL query text.
        duration_ms: Query duration in milliseconds.
        params: Optional query parameters (sanitized before logging).
    """
    sanitized_params = params
    if params is not None and not isinstance(params, (str, bytes)):
        if isinstance(params, dict):
            sanitized_params = {k: _trunc_log_value(v) for k, v in params.items()}
        elif isinstance(params, (list, tuple)):
            sanitized_params = [_trunc_log_value(v) for v in params]

    extra = {
        "query_type": "slow_query",
        "duration_ms": round(duration_ms, 2),
        "query": str(query)[:500],
        "params": sanitized_params,
    }
    logger = get_logger("slow_query")
    logger.warning(
        "Slow query (%.1f ms): %s",
        duration_ms,
        query[:200],
        extra=extra,
    )


def log_api_request(
    method: str,
    path: str,
    status_code: int,
    duration_ms: float,
    request_id: str | None = None,
) -> None:
    """Log an API request at INFO level with structured fields.

    Args:
        method: HTTP method (GET, POST, etc.).
        path: Request path.
        status_code: HTTP response status code.
        duration_ms: Request duration in milliseconds.
        request_id: Optional request identifier for traceability.
    """
    extra: dict[str, Any] = {
        "query_type": "api_request",
        "http_method": method.upper(),
        "path": path,
        "status_code": status_code,
        "duration_ms": round(duration_ms, 2),
    }
    if request_id:
        extra["request_id"] = request_id

    logger = get_logger("api")
    level = logging.WARNING if status_code >= 500 else logging.INFO
    logger.log(
        level,
        "%s %s -> %d (%.1f ms)",
        method.upper(),
        path,
        status_code,
        duration_ms,
        extra=extra,
    )


def _trunc_log_value(value: Any, max_len: int = 100) -> Any:
    """Truncate a value for safe log output."""
    s = str(value)
    return s[:max_len] + "..." if len(s) > max_len else s
