"""Produce LIC1-...-... keys the service would accept — used to verify the
SDK parsers round-trip correctly.

Emits two fixtures now: v1 (legacy fixed-74 payload) and v2 (variable-length
payload with expires_at + entitlements). SDKs must accept both.

Byte layout (matches licensing-service/src/crypto/mod.rs exactly):

v1 (74 bytes, fixed):
  [0]        version = 1
  [1]        flags
  [2..18]    product_id (UUID BE, 16 bytes)
  [18..34]   license_id (UUID BE, 16 bytes)
  [34..42]   issued_at (u64 BE, unix seconds)
  [42..74]   fingerprint_hash (SHA-256, zero if unbound)

v2 (83 bytes + variable entitlements):
  [0]        version = 2
  [1]        flags
  [2..18]    product_id
  [18..34]   license_id
  [34..42]   issued_at (u64 BE)
  [42..50]   expires_at (u64 BE, 0 = perpetual)
  [50..82]   fingerprint_hash (SHA-256, zero if unbound)
  [82]       num_entitlements (u8)
  [83..]     for each: [u8 len][len bytes of UTF-8 slug]

Signature:  64 bytes over the raw payload bytes.
Encoding:   LIC1-<base32(payload)>-<base32(signature)>
            RFC 4648 base32, uppercase, no padding.
"""

import base64
import hashlib
import json
import sys
import uuid

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

KEY_VERSION_V1 = 1
KEY_VERSION_V2 = 2

FLAG_FINGERPRINT_BOUND = 0b0000_0001
FLAG_TRIAL = 0b0000_0010


def b32nopad(b: bytes) -> str:
    return base64.b32encode(b).decode("ascii").rstrip("=")


def make_payload_v1(
    flags: int,
    product_id: bytes, license_id: bytes,
    issued_at: int, fp_hash: bytes,
) -> bytes:
    assert len(product_id) == 16
    assert len(license_id) == 16
    assert len(fp_hash) == 32
    payload = (
        bytes([KEY_VERSION_V1, flags])
        + product_id
        + license_id
        + issued_at.to_bytes(8, "big")
        + fp_hash
    )
    assert len(payload) == 74, f"v1 payload is {len(payload)} bytes, expected 74"
    return payload


def make_payload_v2(
    flags: int,
    product_id: bytes, license_id: bytes,
    issued_at: int, expires_at: int,
    fp_hash: bytes, entitlements: list[str],
) -> bytes:
    assert len(product_id) == 16
    assert len(license_id) == 16
    assert len(fp_hash) == 32
    assert 0 <= len(entitlements) <= 255
    tail = bytearray()
    for slug in entitlements:
        encoded = slug.encode("utf-8")
        assert len(encoded) <= 255, f"entitlement '{slug}' too long"
        tail.append(len(encoded))
        tail.extend(encoded)
    head = (
        bytes([KEY_VERSION_V2, flags])
        + product_id
        + license_id
        + issued_at.to_bytes(8, "big")
        + expires_at.to_bytes(8, "big")
        + fp_hash
        + bytes([len(entitlements)])
    )
    assert len(head) == 83
    return head + bytes(tail)


def sign_and_encode(sk: Ed25519PrivateKey, payload: bytes) -> str:
    sig = sk.sign(payload)
    assert len(sig) == 64
    return f"LIC1-{b32nopad(payload)}-{b32nopad(sig)}"


def main():
    # Deterministic test vector — fixed seeds so the output is stable.
    sk = Ed25519PrivateKey.from_private_bytes(bytes(range(32)))
    pk = sk.public_key()
    pub_pem = pk.public_bytes(
        Encoding.PEM, PublicFormat.SubjectPublicKeyInfo
    ).decode()

    product_id = uuid.UUID("6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0").bytes
    license_id_v1 = uuid.UUID("11111111-2222-3333-4444-555555555555").bytes
    license_id_v2 = uuid.UUID("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee").bytes
    issued_at = 1_700_000_000
    expires_at_v2 = 1_900_000_000  # ~2030
    fingerprint_raw = "test-machine-fingerprint"
    fp_hash = hashlib.sha256(fingerprint_raw.encode()).digest()
    entitlements_v2 = ["pro", "multi-device"]

    # v1: legacy fingerprint-bound key.
    v1_payload = make_payload_v1(
        FLAG_FINGERPRINT_BOUND,
        product_id, license_id_v1, issued_at, fp_hash,
    )
    v1_key = sign_and_encode(sk, v1_payload)

    # v2: trial + fingerprint-bound, with entitlements and expiry.
    v2_flags = FLAG_FINGERPRINT_BOUND | FLAG_TRIAL
    v2_payload = make_payload_v2(
        v2_flags,
        product_id, license_id_v2, issued_at, expires_at_v2,
        fp_hash, entitlements_v2,
    )
    v2_key = sign_and_encode(sk, v2_payload)

    # v2 perpetual, unbound, no entitlements — the "happy path" for a normal
    # permanent license purchase.
    v2_plain_payload = make_payload_v2(
        0,
        product_id, license_id_v2, issued_at, 0,
        bytes(32), [],
    )
    v2_plain_key = sign_and_encode(sk, v2_plain_payload)

    out = {
        "publicKeyPem": pub_pem,
        "v1": {
            "licenseKey": v1_key,
            "expected": {
                "version": 1,
                "productUuid": "6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0",
                "licenseUuid": "11111111-2222-3333-4444-555555555555",
                "issuedAt": issued_at,
                "expiresAt": 0,
                "flags": FLAG_FINGERPRINT_BOUND,
                "isFingerprintBound": True,
                "isTrial": False,
                "entitlements": [],
                "fingerprintRaw": fingerprint_raw,
                "fingerprintHashHex": fp_hash.hex(),
            },
        },
        "v2": {
            "licenseKey": v2_key,
            "expected": {
                "version": 2,
                "productUuid": "6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0",
                "licenseUuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
                "issuedAt": issued_at,
                "expiresAt": expires_at_v2,
                "flags": v2_flags,
                "isFingerprintBound": True,
                "isTrial": True,
                "entitlements": entitlements_v2,
                "fingerprintRaw": fingerprint_raw,
                "fingerprintHashHex": fp_hash.hex(),
            },
        },
        "v2_perpetual_unbound": {
            "licenseKey": v2_plain_key,
            "expected": {
                "version": 2,
                "productUuid": "6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0",
                "licenseUuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
                "issuedAt": issued_at,
                "expiresAt": 0,
                "flags": 0,
                "isFingerprintBound": False,
                "isTrial": False,
                "entitlements": [],
                "fingerprintRaw": None,
                "fingerprintHashHex": "00" * 32,
            },
        },
    }
    json.dump(out, sys.stdout, indent=2)
    print()


if __name__ == "__main__":
    main()
