#!/usr/bin/env python3
"""Schreibt badge-data.json aus der Releases-API (OmniNX-Pack + NX_Firmware-Tag, Gitea/GitHub-kompatibel)."""

from __future__ import annotations

import json
import os
import sys
import urllib.error
import urllib.request

BADGE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "badge-data.json")


def api_get(url: str, token: str) -> bytes:
    req = urllib.request.Request(url)
    if token:
        req.add_header("Authorization", f"Bearer {token}")
    req.add_header("Accept", "application/json")
    with urllib.request.urlopen(req, timeout=120) as resp:
        return resp.read()


def fetch_releases(api_base: str, repo: str, token: str) -> list:
    out: list = []
    page = 1
    while True:
        url = f"{api_base}/repos/{repo}/releases?limit=100&page={page}"
        batch = json.loads(api_get(url, token))
        if not batch:
            break
        out.extend(batch)
        if len(batch) < 100:
            break
        page += 1
    return out


def _token_attempt_order(pack_token: str) -> list[str]:
    """Repos/branches the job token cannot see on Gitea often return 404; public /releases works without auth."""
    pat = os.environ.get("FIRMWARE_API_TOKEN", "").strip()
    order = [pat, "", pack_token] if pat else ["", pack_token]
    seen: set[str] = set()
    out: list[str] = []
    for t in order:
        if t in seen:
            continue
        seen.add(t)
        out.append(t)
    return out


def fetch_releases_with_token_fallback(
    api_base: str, repo: str, pack_token: str
) -> tuple[list | None, urllib.error.HTTPError | None]:
    last_err: urllib.error.HTTPError | None = None
    for t in _token_attempt_order(pack_token):
        try:
            return fetch_releases(api_base, repo, t), None
        except urllib.error.HTTPError as e:
            last_err = e
            if e.code in (401, 403, 404):
                continue
            raise
    return None, last_err


def sum_zip_downloads(releases: list) -> int:
    total = 0
    for rel in releases:
        for asset in rel.get("assets") or []:
            name = str(asset.get("name", ""))
            if name.endswith(".zip"):
                total += int(asset.get("download_count") or 0)
    return total


def first_non_draft_tag(releases: list) -> str | None:
    for rel in releases:
        if rel.get("draft"):
            continue
        tag = str(rel.get("tag_name") or "").strip()
        if tag:
            return tag
    return None


def load_existing_firmware() -> str | None:
    if not os.path.isfile(BADGE_PATH):
        return None
    try:
        with open(BADGE_PATH, encoding="utf-8") as f:
            return json.load(f).get("switch_firmware")
    except (OSError, json.JSONDecodeError, TypeError):
        return None


def main() -> int:
    api_base = os.environ.get("GITHUB_API_URL", "").rstrip("/")
    repo = os.environ.get("GITHUB_REPOSITORY", "")
    fw_repo = os.environ.get("FIRMWARE_REPOSITORY", "OmniNX/NX_Firmware").strip()
    token = os.environ.get("GITHUB_TOKEN", "")

    if not api_base or not repo:
        print("GITHUB_API_URL und GITHUB_REPOSITORY werden benötigt.", file=sys.stderr)
        return 1

    try:
        omninx_releases = fetch_releases(api_base, repo, token)
    except urllib.error.HTTPError as e:
        print(f"API: HTTP {e.code} — {e.reason}", file=sys.stderr)
        return 1

    if not omninx_releases:
        print("Keine Releases gefunden.", file=sys.stderr)
        return 1

    omninx_tag = first_non_draft_tag(omninx_releases)
    if not omninx_tag:
        print("Kein nicht-Draft-Release.", file=sys.stderr)
        return 1

    fw: str | None = None
    fw_releases, fw_err = fetch_releases_with_token_fallback(api_base, fw_repo, token)
    if fw_releases is not None:
        fw = first_non_draft_tag(fw_releases)
    elif fw_err is not None:
        print(f"Firmware-Repo ({fw_repo}): HTTP {fw_err.code} — {fw_err.reason}", file=sys.stderr)

    if not fw:
        fw = load_existing_firmware() or "unknown"

    data = {
        "switch_firmware": fw,
        "release_zip_downloads_total": sum_zip_downloads(omninx_releases),
        "omninx_pack_version": omninx_tag,
    }

    with open(BADGE_PATH, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)
        f.write("\n")

    print(json.dumps(data, indent=2))
    return 0


if __name__ == "__main__":
    sys.exit(main())
