"""Checks a Gitea repo's releases for newer frame firmware, and can pull a
new release's binary into the local firmware.bin slot -- from the device's
point of view an auto-applied update is indistinguishable from a manual
`POST /api/firmware` upload, it self-updates on its next wake either way
(see firmware/main/ota_update.c).

The release-side counterpart is `.gitea/workflows/firmware-release-build.yml`,
which builds one binary per supported board and publishes them as release
assets named `firmware-<board_variant>.bin` -- asset_name_for_board() below
must keep matching that naming exactly.
"""

from __future__ import annotations

import httpx

UPDATE_CHECK_INTERVAL_S = 15 * 60  # don't hit the Gitea API more often than this
HTTP_TIMEOUT_S = 15.0
DOWNLOAD_TIMEOUT_S = 60.0


def asset_name_for_board(board_variant: str) -> str:
    return f"firmware-{board_variant}.bin"


def _api_base(repo_url: str) -> str:
    """"https://git.example.com/owner/repo" (optionally with a trailing
    slash or ".git") -> that repo's Gitea REST API base."""
    url = repo_url.strip().rstrip("/")
    if url.endswith(".git"):
        url = url[: -len(".git")]
    scheme, _, rest = url.partition("://")
    host, _, path = rest.partition("/")
    owner, _, repo = path.rpartition("/")
    return f"{scheme}://{host}/api/v1/repos/{owner}/{repo}"


def _headers(token: str) -> dict:
    return {"Authorization": f"token {token}"} if token else {}


def fetch_latest_release(repo_url: str, token: str = "") -> dict | None:
    """Returns {"version": "1.2.3", "assets": {name: download_url}} for the
    repo's latest release, or None if it has no releases yet."""
    resp = httpx.get(
        f"{_api_base(repo_url)}/releases/latest", headers=_headers(token), timeout=HTTP_TIMEOUT_S
    )
    if resp.status_code == 404:
        return None
    resp.raise_for_status()
    data = resp.json()
    tag = data["tag_name"]
    version = tag[1:] if tag.startswith("v") else tag
    assets = {a["name"]: a["browser_download_url"] for a in data.get("assets", [])}
    return {"version": version, "assets": assets}


def download_asset(url: str, token: str = "") -> bytes:
    resp = httpx.get(url, headers=_headers(token), timeout=DOWNLOAD_TIMEOUT_S, follow_redirects=True)
    resp.raise_for_status()
    return resp.content
