#!/usr/bin/env python3
"""
Generate a minisign Ed25519 keypair for the BIBIVIDI Tauri auto-updater.

Usage:
    python3 tools/gen_updater_keys.py

Output:
    Public key  → paste into bvd/ui/src-tauri/tauri.conf.json  "updater.pubkey"
    Private key → add as GitHub secret  TAURI_SIGNING_PRIVATE_KEY

The public key is committed to the repo (it's not secret).
The private key must NEVER be committed — keep it in GitHub Secrets only.
"""
import base64
import hashlib
import os
import struct

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import (
    Encoding,
    NoEncryption,
    PrivateFormat,
    PublicFormat,
)


def generate() -> tuple[str, str]:
    """Return (public_key_for_config, private_key_for_github_secret)."""
    priv = Ed25519PrivateKey.generate()
    pub  = priv.public_key()

    pub_bytes  = pub.public_bytes(Encoding.Raw, PublicFormat.Raw)    # 32 bytes
    priv_bytes = priv.private_bytes(                                  # 32 bytes
        Encoding.Raw, PrivateFormat.Raw, NoEncryption()
    )

    key_id     = os.urandom(8)
    key_id_hex = key_id.hex().upper()

    # ── Public key (minisign format, base64 for tauri.conf.json) ─────────────
    pub_raw  = b'Ed' + key_id + pub_bytes                   # 42 bytes
    pub_b64  = base64.b64encode(pub_raw).decode()
    pub_file = f"untrusted comment: minisign public key {key_id_hex}\n{pub_b64}\n"
    pub_tauri = base64.b64encode(pub_file.encode()).decode() # tauri.conf.json value

    # ── Private key (minisign format, no password) ────────────────────────────
    sk_and_pk = priv_bytes + pub_bytes                       # 64 bytes, no XOR
    checksum  = hashlib.blake2b(
        b'Ed' + key_id + sk_and_pk, digest_size=32
    ).digest()

    sk_raw = (
        b'Ed' + b'B2' + b'B2'        +   # algorithms (6 bytes)
        os.urandom(32)               +   # kdf_salt  (unused, no password)
        struct.pack('<Q', 0)         +   # kdf_opslimit = 0
        struct.pack('<Q', 0)         +   # kdf_memlimit = 0
        key_id                       +   # 8 bytes
        sk_and_pk                    +   # 64 bytes
        checksum                         # 32 bytes
    )                                    # total: 158 bytes

    sk_b64 = base64.b64encode(sk_raw).decode()
    sk_file = (
        f"untrusted comment: minisign secret key {key_id_hex}\n{sk_b64}\n"
    )

    return pub_tauri, sk_file


def main() -> None:
    pub, sk = generate()

    print("=" * 72)
    print("BIBIVIDI Tauri updater keypair")
    print("=" * 72)
    print()
    print("── PUBLIC KEY (commit this) ────────────────────────────────────────")
    print("Paste into bvd/ui/src-tauri/tauri.conf.json → plugins.updater.pubkey")
    print()
    print(pub)
    print()
    print("── PRIVATE KEY (keep secret) ───────────────────────────────────────")
    print("Add to GitHub → Settings → Secrets → TAURI_SIGNING_PRIVATE_KEY")
    print("NEVER commit this to the repository.")
    print()
    print(sk)
    print("=" * 72)


if __name__ == "__main__":
    main()
