"""aiops.py: turn an alert storm into a few incidents (AIOps, the operations side).

One root cause fires dozens of alerts: a provider outage trips the error-rate alert, the latency
alert, and the health-check alert, for every replica, every minute. Paging on each one is how you
burn out a team and miss the signal in the noise. AIOps correlation groups alerts that share a cause
(same service + symptom, close in time) into a single incident, so 40 alerts become 3.

This is deterministic, dependency-free grouping, the bread-and-butter of an AIOps pipeline, without
the ML. (A fancier version clusters by learned similarity; the idea is identical.)
"""


def correlation_key(alert: dict):
    """What makes two alerts 'the same problem'. Here: same service and same symptom."""
    return (alert["service"], alert["symptom"])


def correlate(alerts, window=5):
    """Group alerts sharing a correlation key that fall within `window` minutes of the group's start.

    alerts: dicts with keys `t` (minute), `service`, `symptom`, `message`.
    Returns a list of incident groups in the order they opened.
    """
    open_group = {}        # correlation_key -> the currently-open group for that key
    incidents = []
    for a in sorted(alerts, key=lambda x: x["t"]):
        key = correlation_key(a)
        g = open_group.get(key)
        if g is not None and a["t"] - g["start"] <= window:
            g["alerts"].append(a)
            g["end"] = a["t"]
        else:
            g = {"key": key, "service": a["service"], "symptom": a["symptom"],
                 "start": a["t"], "end": a["t"], "alerts": [a]}
            open_group[key] = g
            incidents.append(g)
    return incidents


def noise_reduction(alerts, incidents) -> float:
    """Fraction of pages avoided: 1 - incidents/alerts. 40 alerts -> 4 incidents = 0.90."""
    if not alerts:
        return 0.0
    return round(1 - len(incidents) / len(alerts), 2)


def summarize(incidents):
    """One line per incident: what it is and how many alerts it absorbed."""
    out = []
    for i, g in enumerate(incidents, start=1):
        n = len(g["alerts"])
        out.append(f"INC#{i} {g['service']}/{g['symptom']}: "
                   f"{n} alert{'s' if n != 1 else ''} over t={g['start']}-{g['end']}m")
    return out
