"""LLMHosts observability -- optional Sentry integration and structured logging.

Sentry is an optional dependency. When ``sentry_dsn`` is configured and the
``sentry-sdk`` package is installed, unhandled exceptions and slow requests
are reported automatically. When not installed, a debug log message is emitted
and the app continues without error tracking.

This module is part of T-12 (World-Class Logging & Monitoring) compliance.
"""

from __future__ import annotations

import json
import logging
import re
import sys
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from llmhosts.config import ObservabilityConfig

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# PII redaction patterns
# ---------------------------------------------------------------------------

PII_PATTERNS = [
    # API keys (generic)
    (re.compile(r"\b(sk-[a-zA-Z0-9]{48})\b"), "sk-***REDACTED***"),
    (re.compile(r"\b(api[_-]?key[=:\s]+)([a-zA-Z0-9_-]{32,})\b", re.IGNORECASE), r"\1***REDACTED***"),
    # Bearer tokens
    (re.compile(r"\b(Bearer\s+)([a-zA-Z0-9_.-]+)\b"), r"\1***REDACTED***"),
    # Email addresses
    (re.compile(r"\b([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)\b"), "***@***.***"),
    # Phone numbers (US format)
    (re.compile(r"\b(\d{3}[-.]?\d{3}[-.]?\d{4})\b"), "***-***-****"),
    # SSN (US format)
    (re.compile(r"\b(\d{3}-\d{2}-\d{4})\b"), "***-**-****"),
    # Credit card numbers
    (re.compile(r"\b(\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4})\b"), "****-****-****-****"),
    # Passwords in common formats
    (re.compile(r"\b(password[=:\s]+)([^\s]+)\b", re.IGNORECASE), r"\1***REDACTED***"),
]


def redact_pii(text: str) -> str:
    """Redact personally identifiable information from log messages.

    Parameters
    ----------
    text:
        The text to redact.

    Returns
    -------
    str
        The redacted text with PII replaced by placeholder values.
    """
    for pattern, replacement in PII_PATTERNS:
        text = pattern.sub(replacement, text)
    return text


# ---------------------------------------------------------------------------
# JSON structured logging
# ---------------------------------------------------------------------------


class JsonFormatter(logging.Formatter):
    """Formats log records as single-line JSON objects (JSON Lines).

    Supports correlation IDs and PII redaction.
    """

    def format(self, record: logging.LogRecord) -> str:
        # Get correlation ID from context if available
        correlation_id = ""
        try:
            from llmhosts.middleware import get_correlation_id

            correlation_id = get_correlation_id()
        except ImportError:
            pass

        # Build base payload
        payload: dict[str, Any] = {
            "timestamp": datetime.fromtimestamp(record.created, tz=timezone.utc).isoformat(),
            "level": record.levelname,
            "logger": record.name,
            "message": redact_pii(record.getMessage()),
        }

        # Add correlation ID if available
        if correlation_id:
            payload["correlation_id"] = correlation_id

        # Add extra fields from log record
        if hasattr(record, "correlation_id") and record.correlation_id:
            payload["correlation_id"] = record.correlation_id

        # Add exception info if present
        if record.exc_info and record.exc_info[0] is not None:
            payload["exception"] = redact_pii(self.formatException(record.exc_info))

        return json.dumps(payload, default=str)


def _setup_json_logging() -> None:
    """Replace the first :class:`logging.StreamHandler` on the root logger with a JSON formatter.

    Only modifies an existing ``StreamHandler`` -- does **not** add new
    handlers so that handler configuration set elsewhere is preserved.
    """
    formatter = JsonFormatter()
    root = logging.getLogger()
    for handler in root.handlers:
        if isinstance(handler, logging.StreamHandler) and handler.stream in (sys.stdout, sys.stderr):
            handler.setFormatter(formatter)
            return


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


def init_observability(config: ObservabilityConfig) -> None:
    """Bootstrap observability subsystems based on *config*.

    * **Sentry** -- initialised when ``config.sentry_dsn`` is non-empty and
      the ``sentry-sdk`` package is importable.
    * **JSON logging** -- activated when ``config.log_format == "json"``.
    """
    sentry_enabled = False

    if config.sentry_dsn:
        try:
            import sentry_sdk

            sentry_sdk.init(
                dsn=config.sentry_dsn,
                traces_sample_rate=0.1,
                profiles_sample_rate=0.1,
                enable_tracing=True,
            )
            sentry_enabled = True
            logger.info("Sentry error tracking enabled")
        except ImportError:
            logger.warning("sentry-sdk not installed -- pip install llmhosts[monitoring]")

    if config.log_format == "json":
        _setup_json_logging()

    logger.info("Observability initialized (format=%s, sentry=%s)", config.log_format, sentry_enabled)
