from __future__ import annotations

import json
import time
from typing import Any
from urllib.error import URLError
from urllib.parse import urlencode
from urllib.request import urlopen

from flask import jsonify

from .. import settings

_LAB_STATUS_CACHE: dict[str, Any] = {"ts": 0.0, "value": None}


def _vm_query(expr: str) -> float | None:
    url = f"{settings.VM_BASE_URL}/api/v1/query?{urlencode({'query': expr})}"
    with urlopen(url, timeout=settings.VM_QUERY_TIMEOUT_SEC) as resp:
        payload = json.loads(resp.read().decode("utf-8"))

    if payload.get("status") != "success":
        return None

    result = (payload.get("data") or {}).get("result") or []
    if not result:
        return None

    values: list[float] = []
    for item in result:
        try:
            values.append(float(item["value"][1]))
        except (KeyError, IndexError, TypeError, ValueError):
            continue

    if not values:
        return None

    return max(values)


def _http_ok(url: str, expect_substring: str | None = None) -> bool:
    try:
        with urlopen(url, timeout=settings.HTTP_CHECK_TIMEOUT_SEC) as resp:
            if getattr(resp, "status", 200) != 200:
                return False
            if expect_substring:
                chunk = resp.read(4096).decode("utf-8", errors="ignore")
                return expect_substring in chunk
            return True
    except (URLError, TimeoutError, ValueError):
        return False


def register(app) -> None:
    @app.route("/api/lab/status")
    def lab_status() -> Any:
        now = time.time()
        cached = _LAB_STATUS_CACHE.get("value")
        if cached and (now - float(_LAB_STATUS_CACHE.get("ts", 0.0)) < settings.LAB_STATUS_CACHE_SEC):
            return jsonify(cached)

        t_total = time.perf_counter()
        timings_ms: dict[str, int] = {}

        connected = False
        atlas_up = False
        atlas_known = False
        atlas_source = "unknown"

        oceanus_up = False
        oceanus_known = False
        oceanus_source = "unknown"

        # Atlas
        try:
            t_probe = time.perf_counter()
            atlas_grafana_ok = _http_ok(settings.GRAFANA_HEALTH_URL, expect_substring="ok")
            timings_ms["grafana"] = int((time.perf_counter() - t_probe) * 1000)
            if atlas_grafana_ok:
                connected = True
                atlas_up = True
                atlas_known = True
                atlas_source = "grafana"
        except Exception:
            pass

        if not atlas_known:
            try:
                t_probe = time.perf_counter()
                value = _vm_query("up")
                timings_ms["victoria_metrics"] = int((time.perf_counter() - t_probe) * 1000)
                if value is not None:
                    connected = True
                    atlas_known = True
                    atlas_up = value > 0
                    atlas_source = "victoria-metrics"
            except Exception:
                pass

        # Oceanus (node-exporter direct probe)
        try:
            t_probe = time.perf_counter()
            if _http_ok(settings.OCEANUS_NODE_EXPORTER_URL):
                timings_ms["oceanus_node_exporter"] = int((time.perf_counter() - t_probe) * 1000)
                connected = True
                oceanus_known = True
                oceanus_up = True
                oceanus_source = "node-exporter"
        except Exception:
            pass

        timings_ms["total"] = int((time.perf_counter() - t_total) * 1000)

        payload = {
            "connected": connected,
            "atlas": {"up": atlas_up, "known": atlas_known, "source": atlas_source},
            "oceanus": {"up": oceanus_up, "known": oceanus_known, "source": oceanus_source},
            "checked_at": int(now),
            "timings_ms": timings_ms,
        }

        _LAB_STATUS_CACHE["ts"] = now
        _LAB_STATUS_CACHE["value"] = payload
        return jsonify(payload)
