"""SLO compliance and error-budget calculator."""

from __future__ import annotations

import math
from typing import List

import yaml

from sre_beacon.models import SLIType, SLODefinition, SLOResult


def load_slo_definitions(path: str) -> List[SLODefinition]:
    """Load SLO definitions from a YAML file.

    Expected format::

        slos:
          - name: API Availability
            service: api-gateway
            sli_type: availability
            target: 99.9
            window_days: 30
            description: ...
    """
    with open(path, "r", encoding="utf-8") as fh:
        data = yaml.safe_load(fh)

    slos: List[SLODefinition] = []
    for entry in data.get("slos", []):
        slos.append(
            SLODefinition(
                name=entry["name"],
                service=entry.get("service", "unknown"),
                sli_type=SLIType(entry.get("sli_type", "availability")),
                target=float(entry["target"]),
                window_days=int(entry.get("window_days", 30)),
                description=entry.get("description", ""),
            )
        )
    return slos


def calculate_slo(slo: SLODefinition, actual_value: float, burn_rate: float = 0.0) -> SLOResult:
    """Calculate SLO compliance for a single objective."""
    return SLOResult(slo=slo, actual=actual_value, burn_rate=burn_rate)


def calculate_slos_from_yaml(slo_path: str, actuals_path: str) -> List[SLOResult]:
    """Load SLO definitions and actuals, return results.

    Actuals YAML::

        actuals:
          - name: API Availability
            value: 99.85
            burn_rate: 1.2
    """
    slos = load_slo_definitions(slo_path)
    with open(actuals_path, "r", encoding="utf-8") as fh:
        actuals_data = yaml.safe_load(fh)

    actuals_map = {}
    for entry in actuals_data.get("actuals", []):
        actuals_map[entry["name"]] = {
            "value": float(entry["value"]),
            "burn_rate": float(entry.get("burn_rate", 0.0)),
        }

    results: List[SLOResult] = []
    for slo in slos:
        if slo.name in actuals_map:
            a = actuals_map[slo.name]
            results.append(calculate_slo(slo, a["value"], a["burn_rate"]))
    return results


def project_error_budget_depletion(result: SLOResult) -> dict:
    """Project when error budget will be exhausted at current burn rate."""
    if result.burn_rate <= 0 or result.error_budget_remaining_pct <= 0:
        return {"depletes_in_days": None, "status": "stable"}

    # Nominal burn = 1.0 means budget consumed evenly over the window
    remaining_fraction = result.error_budget_remaining_pct / 100.0
    # At burn_rate X, budget depletes X times faster
    days_remaining = (remaining_fraction * result.slo.window_days) / result.burn_rate

    if days_remaining > result.slo.window_days:
        status = "healthy"
    elif days_remaining > result.slo.window_days * 0.5:
        status = "watch"
    elif days_remaining > result.slo.window_days * 0.25:
        status = "warning"
    else:
        status = "critical"

    return {
        "depletes_in_days": round(days_remaining, 1),
        "status": status,
    }


def nines_from_target(target: float) -> float:
    """Convert an availability target % to 'number of nines'."""
    if target >= 100.0:
        return float("inf")
    if target <= 0:
        return 0.0
    return -math.log10(1 - target / 100.0)
