"""
spidercrypt.crypto
~~~~~~~~~~~~~~~~~~
AES-256-GCM encryption and decryption utilities.
"""

import os
import base64
from pathlib import Path
from cryptography.hazmat.primitives.ciphers.aead import AESGCM


def gen_key() -> str:
    """Generate a base64-encoded AES-256 key."""
    return base64.b64encode(AESGCM.generate_key(bit_length=256)).decode()


def encrypt(key_b64: str, data: bytes) -> bytes:
    """
    Encrypt *data* with AES-256-GCM.

    Returns:
        bytes: ``nonce (12 bytes) + ciphertext + auth_tag (16 bytes)``
    """
    key = base64.b64decode(key_b64)
    aes = AESGCM(key)
    nonce = os.urandom(12)
    return nonce + aes.encrypt(nonce, data, None)


def decrypt(key_b64: str, payload: bytes) -> bytes:
    """
    Decrypt an AES-256-GCM *payload* produced by :func:`encrypt`.

    Raises:
        cryptography.exceptions.InvalidTag: if the key is wrong or
        the payload has been tampered with.
    """
    key = base64.b64decode(key_b64)
    aes = AESGCM(key)
    return aes.decrypt(payload[:12], payload[12:], None)


def encrypt_file(key_b64: str, infile: str, outfile: str) -> None:
    """Encrypt *infile* and write the result to *outfile*."""
    data = Path(infile).read_bytes()
    Path(outfile).write_bytes(encrypt(key_b64, data))


def decrypt_file(key_b64: str, infile: str, outfile: str) -> None:
    """Decrypt *infile* and write the result to *outfile*."""
    payload = Path(infile).read_bytes()
    Path(outfile).write_bytes(decrypt(key_b64, payload))