"""Structured JSON logging configuration with correlation IDs.

Features:
- JSON formatted logs
- Correlation ID tracking
- Log level configuration
- Centralized logging support
"""

import json
import logging
import logging.config
import sys
import uuid
from typing import Any, Optional
from contextvars import ContextVar
from datetime import datetime

from pythonjsonlogger import jsonlogger

from src.core.config import settings


# Context variable for correlation ID
correlation_id_var: ContextVar[Optional[str]] = ContextVar(
    "correlation_id", default=None
)


class CorrelationIdFilter(logging.Filter):
    """Filter that adds correlation ID to log records."""

    def filter(self, record: logging.LogRecord) -> bool:
        correlation_id = correlation_id_var.get()
        record.correlation_id = correlation_id or "N/A"
        return True


class CustomJsonFormatter(jsonlogger.JsonFormatter):
    """Custom JSON formatter for structured logging."""

    def add_fields(
        self,
        log_record: dict[str, Any],
        record: logging.LogRecord,
        message_dict: dict[str, Any],
    ) -> None:
        super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)

        # Add timestamp
        log_record["timestamp"] = datetime.utcnow().isoformat()
        log_record["level"] = record.levelname
        log_record["logger"] = record.name
        log_record["source"] = f"{record.filename}:{record.lineno}"

        # Add correlation ID
        log_record["correlation_id"] = getattr(record, "correlation_id", "N/A")

        # Add environment info
        log_record["environment"] = (
            "production" if not getattr(settings, "debug", False) else "development"
        )
        log_record["service"] = getattr(settings, "app_name", "mockupAWS")
        log_record["version"] = getattr(settings, "app_version", "1.0.0")

        # Rename fields for consistency
        if "asctime" in log_record:
            del log_record["asctime"]
        if "levelname" in log_record:
            del log_record["levelname"]
        if "name" in log_record:
            del log_record["name"]


def setup_logging() -> None:
    """Configure structured JSON logging."""

    log_level = getattr(settings, "log_level", "INFO").upper()
    enable_json = getattr(settings, "json_logging", True)

    if enable_json:
        formatter = "json"
        format_string = "%(message)s"
    else:
        formatter = "standard"
        format_string = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"

    logging_config = {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "json": {
                "()": CustomJsonFormatter,
            },
            "standard": {
                "format": format_string,
            },
        },
        "filters": {
            "correlation_id": {
                "()": CorrelationIdFilter,
            },
        },
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "stream": sys.stdout,
                "formatter": formatter,
                "filters": ["correlation_id"],
                "level": log_level,
            },
        },
        "root": {
            "handlers": ["console"],
            "level": log_level,
        },
        "loggers": {
            "uvicorn": {
                "handlers": ["console"],
                "level": log_level,
                "propagate": False,
            },
            "uvicorn.access": {
                "handlers": ["console"],
                "level": log_level,
                "propagate": False,
            },
            "sqlalchemy.engine": {
                "handlers": ["console"],
                "level": "WARNING" if not getattr(settings, "debug", False) else "INFO",
                "propagate": False,
            },
            "celery": {
                "handlers": ["console"],
                "level": log_level,
                "propagate": False,
            },
        },
    }

    logging.config.dictConfig(logging_config)


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


def set_correlation_id(correlation_id: Optional[str] = None) -> str:
    """Set the correlation ID for the current context.

    Args:
        correlation_id: Optional correlation ID, generates UUID if not provided

    Returns:
        The correlation ID
    """
    cid = correlation_id or str(uuid.uuid4())
    correlation_id_var.set(cid)
    return cid


def get_correlation_id() -> Optional[str]:
    """Get the current correlation ID."""
    return correlation_id_var.get()


def clear_correlation_id() -> None:
    """Clear the current correlation ID."""
    correlation_id_var.set(None)


class LoggingContext:
    """Context manager for correlation ID tracking."""

    def __init__(self, correlation_id: Optional[str] = None):
        self.correlation_id = correlation_id or str(uuid.uuid4())
        self.token = None

    def __enter__(self):
        self.token = correlation_id_var.set(self.correlation_id)
        return self.correlation_id

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.token:
            correlation_id_var.reset(self.token)


# Convenience functions for structured logging


def log_request(
    logger: logging.Logger,
    method: str,
    path: str,
    status_code: int,
    duration_ms: float,
    user_id: Optional[str] = None,
    extra: Optional[dict] = None,
) -> None:
    """Log an HTTP request."""
    log_data = {
        "event": "http_request",
        "method": method,
        "path": path,
        "status_code": status_code,
        "duration_ms": duration_ms,
        "user_id": user_id,
    }
    if extra:
        log_data.update(extra)

    if status_code >= 500:
        logger.error(log_data)
    elif status_code >= 400:
        logger.warning(log_data)
    else:
        logger.info(log_data)


def log_error(
    logger: logging.Logger,
    error: Exception,
    context: Optional[dict] = None,
) -> None:
    """Log an error with context."""
    log_data = {
        "event": "error",
        "error_type": type(error).__name__,
        "error_message": str(error),
    }
    if context:
        log_data["context"] = context

    logger.exception(log_data)


def log_security_event(
    logger: logging.Logger,
    event_type: str,
    user_id: Optional[str] = None,
    details: Optional[dict] = None,
) -> None:
    """Log a security-related event."""
    log_data = {
        "event": "security",
        "event_type": event_type,
        "user_id": user_id,
        "timestamp": datetime.utcnow().isoformat(),
    }
    if details:
        log_data["details"] = details

    logger.warning(log_data)


# Initialize logging on module import
setup_logging()
