"""Incident metrics calculator — MTTR, MTTA, MTBF analysis."""

from __future__ import annotations

from datetime import datetime, timedelta
from typing import List, Optional

import yaml

from sre_beacon.models import Incident, IncidentMetrics, IncidentSeverity


def load_incidents(path: str) -> List[Incident]:
    """Load incidents from a YAML file.

    Expected format::

        incidents:
          - id: INC-001
            title: API gateway outage
            severity: P1
            service: api-gateway
            detected_at: "2025-01-15T02:30:00"
            acknowledged_at: "2025-01-15T02:35:00"
            resolved_at: "2025-01-15T03:15:00"
            root_cause: Memory leak in connection pool
            action_items:
              - Add memory limit alerts
    """
    with open(path, "r", encoding="utf-8") as fh:
        data = yaml.safe_load(fh)

    incidents: List[Incident] = []
    for entry in data.get("incidents", []):
        incidents.append(
            Incident(
                id=str(entry["id"]),
                title=entry.get("title", ""),
                severity=IncidentSeverity(entry.get("severity", "P3")),
                service=entry.get("service", "unknown"),
                detected_at=_parse_dt(entry["detected_at"]),
                acknowledged_at=_parse_dt(entry.get("acknowledged_at")),
                resolved_at=_parse_dt(entry.get("resolved_at")),
                root_cause=entry.get("root_cause", ""),
                action_items=entry.get("action_items", []),
            )
        )
    return incidents


def calculate_incident_metrics(incidents: List[Incident]) -> IncidentMetrics:
    """Calculate aggregate incident metrics."""
    if not incidents:
        return IncidentMetrics(
            total_incidents=0, mttr=None, mtta=None, mtbf=None,
        )

    # MTTR — Mean Time to Resolve
    ttr_values = [i.ttr for i in incidents if i.ttr is not None]
    mttr = _avg_timedelta(ttr_values) if ttr_values else None

    # MTTA — Mean Time to Acknowledge
    tta_values = [i.tta for i in incidents if i.tta is not None]
    mtta = _avg_timedelta(tta_values) if tta_values else None

    # MTBF — Mean Time Between Failures
    sorted_incidents = sorted(incidents, key=lambda i: i.detected_at)
    gaps: List[timedelta] = []
    for idx in range(1, len(sorted_incidents)):
        prev_resolved = sorted_incidents[idx - 1].resolved_at
        curr_detected = sorted_incidents[idx].detected_at
        if prev_resolved and curr_detected > prev_resolved:
            gaps.append(curr_detected - prev_resolved)
    mtbf = _avg_timedelta(gaps) if gaps else None

    # By severity
    by_severity: dict = {}
    for inc in incidents:
        sev = inc.severity.value
        if sev not in by_severity:
            by_severity[sev] = {"count": 0, "avg_ttr": None, "ttr_values": []}
        by_severity[sev]["count"] += 1
        if inc.ttr:
            by_severity[sev]["ttr_values"].append(inc.ttr)

    for sev, data in by_severity.items():
        if data["ttr_values"]:
            data["avg_ttr"] = _avg_timedelta(data["ttr_values"])
        del data["ttr_values"]

    # By service
    by_service: dict = {}
    for inc in incidents:
        svc = inc.service
        if svc not in by_service:
            by_service[svc] = {"count": 0, "p1_p2": 0}
        by_service[svc]["count"] += 1
        if inc.severity in (IncidentSeverity.P1, IncidentSeverity.P2):
            by_service[svc]["p1_p2"] += 1

    # Action items coverage
    with_actions = sum(1 for i in incidents if i.action_items)
    actions_pct = (with_actions / len(incidents)) * 100.0

    p1_p2 = sum(
        1 for i in incidents
        if i.severity in (IncidentSeverity.P1, IncidentSeverity.P2)
    )

    return IncidentMetrics(
        total_incidents=len(incidents),
        mttr=mttr,
        mtta=mtta,
        mtbf=mtbf,
        by_severity=by_severity,
        by_service=by_service,
        incidents_with_action_items_pct=round(actions_pct, 1),
        p1_p2_count=p1_p2,
    )


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _parse_dt(value) -> Optional[datetime]:
    if value is None:
        return None
    if isinstance(value, datetime):
        return value
    return datetime.fromisoformat(str(value))


def _avg_timedelta(deltas: List[timedelta]) -> timedelta:
    total_seconds = sum(d.total_seconds() for d in deltas)
    return timedelta(seconds=total_seconds / len(deltas))
