"""
Prometheus Metrics for AI Chatbot Pen-Test Framework

Provides instrumentation for:
- LLM request latencies
- Connector request latencies
- Attack round durations
- Findings counts by severity/category
- Decline detection events
- Circuit breaker state changes
- Active WebSocket connections
"""

from urllib.parse import urlparse
from time import perf_counter
from prometheus_client import Counter, Histogram, Gauge

LLM_LATENCY = Histogram(
    "llm_request_latency_seconds",
    "Latency of LLM requests in seconds",
    labelnames=("model",),
    buckets=(0.1, 0.25, 0.5, 1, 2, 4, 8, 15, float("inf")),
)

CONNECTOR_LATENCY = Histogram(
    "connector_request_latency_seconds",
    "Latency of connector API requests in seconds",
    labelnames=("endpoint_host", "success"),
    buckets=(0.05, 0.1, 0.25, 0.5, 1, 2, 4, 8, float("inf")),
)

ATTACK_ROUND_LATENCY = Histogram(
    "attack_round_duration_seconds",
    "End-to-end duration of an attack round (coordination + execution + analysis)",
    buckets=(0.5, 1, 2, 4, 8, 15, 30, 60, float("inf")),
)

ATTACKS_TOTAL = Counter(
    "attacks_generated_total",
    "Total attacks generated by agent and source",
    labelnames=("agent_name", "source"),  # source: llm|L1B3RT4S|ultra_advanced|advanced|core
)

FINDINGS_TOTAL = Counter(
    "findings_total",
    "Total security findings by severity and category",
    labelnames=("severity", "category"),
)

DECLINES_DETECTED_TOTAL = Counter(
    "declines_detected_total",
    "Detected target declines/refusals by match type",
    labelnames=("match_type",),  # exact|substr
)

CIRCUIT_OPEN_TOTAL = Counter(
    "circuit_breaker_open_total",
    "Circuit breaker opens per endpoint host",
    labelnames=("endpoint_host",),
)

ACTIVE_WS_CONNECTIONS = Gauge("active_ws_connections", "Number of active WebSocket connections")

CURRENT_TEST_SESSIONS = Gauge("current_test_sessions", "Number of currently running test sessions")


def endpoint_host(url: str) -> str:
    """
    Extract host from URL for metrics labeling.

    Args:
        url: Full URL

    Returns:
        Hostname or "unknown"
    """
    try:
        parsed = urlparse(url)
        return parsed.netloc or "unknown"
    except Exception:
        return "unknown"


class Timer:
    """
    Context manager for timing operations and recording to Prometheus histogram.

    Usage:
        with Timer(LLM_LATENCY, model="claude-3"):
            response = await llm.ainvoke(...)
    """

    def __init__(self, histogram: Histogram, **labels):
        """
        Initialize timer.

        Args:
            histogram: Prometheus Histogram to record to
            **labels: Label values for the histogram
        """
        self.histogram = histogram
        self.labels = labels
        self.t0 = None

    def __enter__(self):
        """Start timing."""
        self.t0 = perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Stop timing and record."""
        if self.t0 is not None:
            dt = perf_counter() - self.t0
            self.histogram.labels(**self.labels).observe(dt)


def record_llm_latency(model: str, duration_seconds: float) -> None:
    """
    Record LLM request latency.

    Args:
        model: Model name (e.g., "claude-sonnet-4-5")
        duration_seconds: Request duration
    """
    LLM_LATENCY.labels(model=model).observe(duration_seconds)


def record_connector_latency(url: str, duration_seconds: float, success: bool) -> None:
    """
    Record connector request latency.

    Args:
        url: Target URL
        duration_seconds: Request duration
        success: Whether request succeeded
    """
    host = endpoint_host(url)
    CONNECTOR_LATENCY.labels(endpoint_host=host, success=str(success).lower()).observe(
        duration_seconds
    )


def record_attack_round(duration_seconds: float) -> None:
    """
    Record full attack round duration.

    Args:
        duration_seconds: Total round duration
    """
    ATTACK_ROUND_LATENCY.observe(duration_seconds)


def record_attack_generated(agent_name: str, source: str) -> None:
    """
    Record attack generation.

    Args:
        agent_name: Name of agent that generated attack
        source: Pattern source (llm|L1B3RT4S|ultra_advanced|advanced|core)
    """
    ATTACKS_TOTAL.labels(agent_name=agent_name, source=source).inc()


def record_finding(severity: str, category: str) -> None:
    """
    Record security finding.

    Args:
        severity: Finding severity (critical|high|medium|low|info)
        category: Finding category
    """
    FINDINGS_TOTAL.labels(severity=severity, category=category).inc()


def record_decline_detected(match_type: str) -> None:
    """
    Record decline/refusal detection.

    Args:
        match_type: Match type (exact|substr)
    """
    DECLINES_DETECTED_TOTAL.labels(match_type=match_type).inc()


def record_circuit_breaker_open(url: str) -> None:
    """
    Record circuit breaker opening.

    Args:
        url: Target URL
    """
    host = endpoint_host(url)
    CIRCUIT_OPEN_TOTAL.labels(endpoint_host=host).inc()


def increment_ws_connections() -> None:
    """Increment active WebSocket connection count."""
    ACTIVE_WS_CONNECTIONS.inc()


def decrement_ws_connections() -> None:
    """Decrement active WebSocket connection count."""
    ACTIVE_WS_CONNECTIONS.dec()


def increment_test_sessions() -> None:
    """Increment active test session count."""
    CURRENT_TEST_SESSIONS.inc()


def decrement_test_sessions() -> None:
    """Decrement active test session count."""
    CURRENT_TEST_SESSIONS.dec()
