"""detect_drift — detecta drift estadistico por z-score comparando metricas contra historial."""

import math


def detect_drift(
    history: list[dict],
    current: dict,
    fields: list[str],
    threshold: float = 2.0,
) -> list[dict]:
    """Detecta drift estadistico comparando metricas actuales contra el historial.

    Usa z-score: si |z| > threshold, el campo ha drifteado. Pensado para
    comparar metrics de executions sucesivas en operations.db.

    Args:
        history: Lista de dicts con metricas historicas. Cada dict puede
                 contener cualquier combinacion de los campos indicados.
        current: Dict con las metricas de la ejecucion actual.
        fields: Lista de campos numericos a analizar.
        threshold: Umbral de z-score para considerar drift. Default 2.0.

    Returns:
        Lista de dicts con: field, current, mean, std, z_score, drifted.
        Si el historial tiene 0 o 1 punto, z_score=0.0 y drifted=False
        porque no hay suficiente informacion estadistica.
    """
    results = []

    for field in fields:
        values = [
            float(h[field])
            for h in history
            if field in h and h[field] is not None
        ]

        current_val = float(current.get(field, 0))

        if len(values) == 0:
            results.append({
                "field": field,
                "current": current_val,
                "mean": 0.0,
                "std": 0.0,
                "z_score": 0.0,
                "drifted": False,
            })
            continue

        n = len(values)
        mean = sum(values) / n

        if n < 2:
            # Un solo punto: no hay std, no podemos calcular z-score
            results.append({
                "field": field,
                "current": current_val,
                "mean": mean,
                "std": 0.0,
                "z_score": 0.0,
                "drifted": False,
            })
            continue

        variance = sum((v - mean) ** 2 for v in values) / n
        std = math.sqrt(variance)

        if std == 0.0:
            # Todos los valores identicos: z_score indeterminado, no drift
            z_score = 0.0
            drifted = False
        else:
            z_score = (current_val - mean) / std
            drifted = abs(z_score) > threshold

        results.append({
            "field": field,
            "current": current_val,
            "mean": mean,
            "std": std,
            "z_score": z_score,
            "drifted": drifted,
        })

    return results
