#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# 20-apt — 42i-hc Drop-in: prueft, ob das 42i-Repo und der Debian-Mirror
# erreichbar (und eingerichtet) sind.
# hc-tags: checks, apt
# hc-ttl: 300
#
# Testet ueber `apt-helper download-file` der jeweiligen InRelease — das nutzt
# GENAU die apt-Konfiguration (inkl. Proxy/auth.conf), deckt also auch einen
# toten apt-Proxy oder ein fehlendes/falsches Repo auf, das `curl` direkt nicht
# sieht. Liefert {"checks": [...]}:
#   - 42i-repo: fail, wenn nicht eingerichtet ODER nicht erreichbar.
#   - debian-mirror: warn, wenn nicht erreichbar.
# Cache macht der hc-Daemon (`# hc-ttl: 300`), damit der haeufige Health-Poll die
# Mirrors nicht flutet. Geliefert von 42i-hc.

import glob
import json
import os
import subprocess
import sys

APT_HELPER = "/usr/lib/apt/apt-helper"


def sources():
    """Liefert [(url, suite, is_42i)] aus klassischen .list und deb822 .sources."""
    out = []
    for f in ["/etc/apt/sources.list"] + glob.glob("/etc/apt/sources.list.d/*.list"):
        try:
            with open(f, encoding="utf-8", errors="replace") as fh:
                for line in fh:
                    line = line.strip()
                    if not line.startswith("deb ") or line.startswith("deb-src"):
                        continue
                    parts = line.split()
                    url = suite = None
                    for i, p in enumerate(parts):
                        if p.startswith("http"):
                            url = p
                            suite = parts[i + 1] if i + 1 < len(parts) else None
                            break
                    if url and suite:
                        out.append((url, suite, "42i.org" in url))
        except OSError:
            pass
    for f in glob.glob("/etc/apt/sources.list.d/*.sources"):
        try:
            for blk in open(f, encoding="utf-8", errors="replace").read().split("\n\n"):
                d = {}
                for line in blk.splitlines():
                    if ":" in line:
                        k, v = line.split(":", 1)
                        d[k.strip().lower()] = v.strip()
                for u in d.get("uris", "").split():
                    for s in d.get("suites", "").split():
                        out.append((u, s, "42i.org" in u))
        except OSError:
            pass
    return out


def reachable(url, suite):
    """Laedt die InRelease via apt-helper (respektiert apt-Proxy/Auth) -> bool."""
    inrel = url.rstrip("/") + "/dists/" + suite + "/InRelease"
    dest = "/tmp/.hc-apt-dl"
    try:
        r = subprocess.run([APT_HELPER, "download-file", inrel, dest],
                          capture_output=True, timeout=12)
        ok = (r.returncode == 0)
    except Exception:
        ok = False
    try:
        os.remove(dest)
    except OSError:
        pass
    return ok


def build():
    """Erzeugt die checks fuer 42i-Repo und Debian-Mirror."""
    srcs = sources()
    checks = []
    src42 = next(((u, s) for u, s, is42 in srcs if is42), None)
    if src42 is None:
        checks.append({"name": "42i-repo", "status": "fail",
                      "message": "42i-Repo nicht in den apt-Sources eingerichtet"})
    elif reachable(*src42):
        checks.append({"name": "42i-repo", "status": "ok",
                      "detail": {"url": src42[0]}})
    else:
        checks.append({"name": "42i-repo", "status": "fail",
                      "message": "%s nicht erreichbar (Proxy/Netz/Repo?)" % src42[0]})

    deb = next(((u, s) for u, s, is42 in srcs
                if not is42 and "debian" in u.lower()), None)
    if deb is not None:
        if reachable(*deb):
            checks.append({"name": "debian-mirror", "status": "ok",
                          "detail": {"url": deb[0]}})
        else:
            checks.append({"name": "debian-mirror", "status": "warn",
                          "message": "%s nicht erreichbar" % deb[0]})
    return {"checks": checks}


def main():
    """Gibt {"checks": ...} als JSON aus (Cache macht der hc-Daemon via hc-ttl)."""
    sys.stdout.write(json.dumps(build(), ensure_ascii=False) + "\n")


if __name__ == "__main__":
    main()
