"""System resource monitoring via Prometheus for heartbeat."""

from __future__ import annotations

import json
import logging
import os
import time

logger = logging.getLogger("health-heartbeat")

_PROMETHEUS_URL = os.environ.get("OPENDEVIATIONBAR_PROMETHEUS_URL", "http://localhost:9090")
RESOURCE_WINDOW_MINUTES = 15


def query_prometheus_range(query: str, minutes: int) -> list[float]:
    """Query Prometheus range API, return float values over last N minutes."""
    import urllib.parse
    import urllib.request

    end = time.time()
    start = end - minutes * 60
    params = urllib.parse.urlencode(
        {"query": query, "start": str(start), "end": str(end), "step": "15s"}
    )
    url = f"{_PROMETHEUS_URL}/api/v1/query_range?{params}"
    try:
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        with urllib.request.urlopen(req, timeout=5) as resp:
            data = json.loads(resp.read())
        if data.get("status") != "success":
            return []
        results_data = data.get("data", {}).get("result", [])
        if not results_data:
            return []
        import math

        values = [float(v[1]) for v in results_data[0].get("values", [])]
        return [v for v in values if not math.isnan(v)]
    except Exception:
        logger.warning("Prometheus query failed", exc_info=True)
        return []


def smart_peak(values: list[float]) -> float | None:
    """Return outlier-screened peak via Tukey IQR upper fence (Q3 + 1.5*IQR).

    Falls back to raw max when there are fewer than 4 samples.
    Does NOT require fitter — pure numpy IQR is magic-number-free.
    """
    if not values:
        return None
    try:
        import numpy as np

        arr = np.array(values)
        if len(arr) < 4:
            return float(arr.max())
        q1, q3 = float(np.percentile(arr, 25)), float(np.percentile(arr, 75))
        fence = q3 + 1.5 * (q3 - q1)
        inliers = arr[arr <= fence]
        return float(inliers.max()) if len(inliers) > 0 else float(arr.max())
    except ImportError:
        return max(values)


def collect_resource_peaks(results: dict[str, bool | str]) -> None:
    """Query Prometheus for CPU/RAM/load peaks over the last 15 min.

    Populates:
      resource_cpu_avg, resource_cpu_abs_peak, resource_cpu_typ_peak  (%)
      resource_ram_used_gb, resource_ram_abs_peak_gb, resource_ram_typ_peak_gb
      resource_load_avg, resource_load_abs_peak, resource_load_typ_peak
    All values are best-effort: if Prometheus is unreachable the keys are absent.
    """
    w = RESOURCE_WINDOW_MINUTES

    # CPU busy (100 - idle)
    cpu_vals = query_prometheus_range(
        '100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)',
        w,
    )
    if cpu_vals:
        import statistics

        results["resource_cpu_avg"] = f"{statistics.mean(cpu_vals):.1f}"
        results["resource_cpu_abs_peak"] = f"{max(cpu_vals):.1f}"
        sp = smart_peak(cpu_vals)
        if sp is not None:
            results["resource_cpu_typ_peak"] = f"{sp:.1f}"

    # RAM used (GB)
    ram_vals = query_prometheus_range(
        "(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 1073741824",
        w,
    )
    if ram_vals:
        import statistics

        results["resource_ram_used_gb"] = f"{statistics.mean(ram_vals):.1f}"
        results["resource_ram_abs_peak_gb"] = f"{max(ram_vals):.1f}"
        sp = smart_peak(ram_vals)
        if sp is not None:
            results["resource_ram_typ_peak_gb"] = f"{sp:.1f}"

    # 1-min load average
    load_vals = query_prometheus_range("node_load1", w)
    if load_vals:
        import statistics

        results["resource_load_avg"] = f"{statistics.mean(load_vals):.2f}"
        results["resource_load_abs_peak"] = f"{max(load_vals):.2f}"
        sp = smart_peak(load_vals)
        if sp is not None:
            results["resource_load_typ_peak"] = f"{sp:.2f}"
