"""CLI tool to encrypt/decrypt asset files for CGT License system.

Usage:
    python -m cgt_license.encrypt_tool encrypt \\
        --input presets/render_profiles.json \\
        --output presets/render_profiles.json.enc \\
        --secret-hex <32-byte-hex-runtime-secret> \\
        --product-id sample-pyside

    python -m cgt_license.encrypt_tool decrypt \\
        --input presets/render_profiles.json.enc \\
        --output presets/render_profiles.json \\
        --secret-hex <32-byte-hex-runtime-secret> \\
        --product-id sample-pyside

The encryption uses:
    key = HKDF-SHA256(secret, salt=b"cgt-asset", info=product_id.encode())
    cipher = AES-256-GCM
    format = nonce(12 bytes) + ciphertext + tag(16 bytes)
"""

import argparse
import os
import sys

# Use cryptography library for encryption (same algo as Guard.dll)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes


def derive_key(secret: bytes, product_id: str) -> bytes:
    """Derive AES-256 key from runtime secret via HKDF-SHA256."""
    return HKDF(
        algorithm=hashes.SHA256(),
        length=32,
        salt=b"cgt-asset",
        info=product_id.encode("utf-8"),
    ).derive(secret)


def encrypt_file(
    input_path: str, output_path: str, secret: bytes, product_id: str
):
    """Encrypt a file with AES-256-GCM."""
    key = derive_key(secret, product_id)

    with open(input_path, "rb") as f:
        plaintext = f.read()

    nonce = os.urandom(12)
    aesgcm = AESGCM(key)
    ciphertext = aesgcm.encrypt(nonce, plaintext, None)

    with open(output_path, "wb") as f:
        f.write(nonce + ciphertext)  # nonce(12) + ciphertext + tag(16)

    print(f"Encrypted: {input_path} -> {output_path}")
    print(f"  Size: {len(plaintext)} -> {12 + len(ciphertext)} bytes")


def decrypt_file(
    input_path: str, output_path: str, secret: bytes, product_id: str
):
    """Decrypt a file with AES-256-GCM."""
    key = derive_key(secret, product_id)

    with open(input_path, "rb") as f:
        data = f.read()

    if len(data) < 12 + 16:
        print("Error: encrypted file too short", file=sys.stderr)
        sys.exit(1)

    nonce = data[:12]
    ciphertext = data[12:]

    aesgcm = AESGCM(key)
    try:
        plaintext = aesgcm.decrypt(nonce, ciphertext, None)
    except Exception as e:
        print(f"Decryption failed: {e}", file=sys.stderr)
        print(
            "Check that the secret and product-id are correct.",
            file=sys.stderr,
        )
        sys.exit(1)

    with open(output_path, "wb") as f:
        f.write(plaintext)

    print(f"Decrypted: {input_path} -> {output_path}")
    print(f"  Size: {len(data)} -> {len(plaintext)} bytes")


def generate_test_secret():
    """Generate a random 32-byte secret for testing."""
    secret = os.urandom(32)
    print(f"Test runtime secret (hex): {secret.hex()}")
    print("Use this with --secret-hex for testing.")
    print("In production, the server generates this automatically.")


def main():
    parser = argparse.ArgumentParser(
        description="CGT License — Asset encryption tool"
    )
    sub = parser.add_subparsers(dest="command", required=True)

    # encrypt
    enc = sub.add_parser("encrypt", help="Encrypt an asset file")
    enc.add_argument(
        "--input", "-i", required=True, help="Input plaintext file"
    )
    enc.add_argument(
        "--output", "-o", required=True, help="Output encrypted file"
    )
    enc.add_argument(
        "--secret-hex",
        required=True,
        help="Runtime secret as hex (64 chars)",
    )
    enc.add_argument(
        "--product-id",
        required=True,
        help="Product ID for key derivation",
    )

    # decrypt
    dec = sub.add_parser("decrypt", help="Decrypt an asset file")
    dec.add_argument(
        "--input", "-i", required=True, help="Input encrypted file"
    )
    dec.add_argument(
        "--output", "-o", required=True, help="Output plaintext file"
    )
    dec.add_argument(
        "--secret-hex",
        required=True,
        help="Runtime secret as hex (64 chars)",
    )
    dec.add_argument(
        "--product-id",
        required=True,
        help="Product ID for key derivation",
    )

    # generate-secret
    sub.add_parser("generate-secret", help="Generate a random test secret")

    args = parser.parse_args()

    if args.command == "generate-secret":
        generate_test_secret()
        return

    secret = bytes.fromhex(args.secret_hex)
    if len(secret) != 32:
        print(
            "Error: secret must be exactly 32 bytes (64 hex chars)",
            file=sys.stderr,
        )
        sys.exit(1)

    if args.command == "encrypt":
        encrypt_file(args.input, args.output, secret, args.product_id)
    elif args.command == "decrypt":
        decrypt_file(args.input, args.output, secret, args.product_id)


if __name__ == "__main__":
    main()
