#!/usr/bin/env python3
"""上传 release 资产到 gitcode(两步:取签名 URL → PUT 到 OBS)。

用法: upload_assets.py <version> <token> [file...]
不传 file 时上传该版本目录下全部发布产物:
  tar.gz / zip / deb / rpm / pkg / -setup.exe / SHA256SUMS
"""
import json
import os
import sys
import urllib.request
import urllib.parse

REPO = "JianFeeeee/webui4frpc"
API = "https://gitcode.com/api/v5/repos"


def get_upload_url(version: str, token: str, filename: str) -> tuple[str, dict]:
    q = urllib.parse.urlencode({"file_name": filename})
    url = f"{API}/{REPO}/releases/v{version}/upload_url?{q}"
    req = urllib.request.Request(url, headers={"private-token": token})
    with urllib.request.urlopen(req, timeout=20) as r:
        data = json.loads(r.read())
    return data["url"], data.get("headers", {})


def put_file(url: str, headers: dict, path: str) -> tuple[int, str]:
    size = os.path.getsize(path)
    with open(path, "rb") as f:
        body = f.read()
    req = urllib.request.Request(url, data=body, method="PUT")
    for k, v in headers.items():
        req.add_header(k, v)
    req.add_header("Content-Length", str(size))
    try:
        with urllib.request.urlopen(req, timeout=300) as r:
            return r.status, r.read().decode("utf-8", "replace")[:300]
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode("utf-8", "replace")[:300]


# 发布产物后缀:免安装包 + 原生安装包。
# 注意 -setup.exe 而不是裸 .exe,避开 bin/ 里的裸二进制。
ARTIFACT_SUFFIXES = (
    ".tar.gz", ".zip",              # 免安装
    ".deb", ".rpm", ".pkg",         # linux / macOS 安装包
    "-setup.exe",                   # windows 安装器
)


def is_artifact(name: str) -> bool:
    return name == "SHA256SUMS" or name.endswith(ARTIFACT_SUFFIXES)


def main() -> int:
    if len(sys.argv) < 3:
        print(__doc__)
        return 2
    version, token = sys.argv[1], sys.argv[2]
    outdir = os.path.join(
        os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
        "dist", "artifacts", version,
    )
    files = sys.argv[3:] or sorted(f for f in os.listdir(outdir) if is_artifact(f))
    failed = 0
    for name in files:
        path = os.path.join(outdir, name)
        if not os.path.isfile(path):
            print(f"skip (missing): {name}")
            continue
        print(f"==> {name} ({os.path.getsize(path)/1048576:.1f} MiB)")
        try:
            url, headers = get_upload_url(version, token, name)
        except Exception as e:  # noqa: BLE001
            print(f"    upload_url FAILED: {e}")
            failed += 1
            continue
        status, body = put_file(url, headers, path)
        ok = 200 <= status < 300
        print(f"    PUT -> {status} {'OK' if ok else body}")
        if not ok:
            failed += 1
    print(f"\n{'ALL OK' if failed == 0 else f'{failed} FAILED'}")
    return 1 if failed else 0


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