"""
Encryption and decryption utilities for UniCoreFW.

This module provides basic string encryption/decryption using the 'cryptography' library
(Fernet symmetric encryption). For production use, ensure that your key handling, secret
management, and error handling meet security best practices.

Copyright (C) 2024 Kenny Ngo / UniCoreFW.Org / IIPTech.info
"""

try:
    from cryptography.fernet import Fernet, InvalidToken

    CRYPTO_AVAILABLE = True
except ImportError:
    # If cryptography isn't installed, these functions won't work
    CRYPTO_AVAILABLE = False


def generate_key() -> bytes:
    """
    Generate a new Fernet (AES-based) key.

    Returns:
        A randomly generated 32-byte key suitable for Fernet encryption.

    Raises:
        RuntimeError: If 'cryptography' is not installed.
    """
    if not CRYPTO_AVAILABLE:
        raise RuntimeError("cryptography library is not installed.")
    return Fernet.generate_key()


def encrypt_string(plaintext: str, key: bytes) -> str:
    """
    Encrypt a plaintext string using a given Fernet key.

    Args:
        plaintext: The string to encrypt.
        key: The 32-byte key generated by 'generate_key' or shared by the user.

    Returns:
        A URL-safe base64-encoded ciphertext string.

    Raises:
        RuntimeError: If 'cryptography' is not installed.
    """
    if not CRYPTO_AVAILABLE:
        raise RuntimeError("cryptography library is not installed.")
    f = Fernet(key)
    token = f.encrypt(plaintext.encode("utf-8"))
    return token.decode("utf-8")


def decrypt_string(ciphertext: str, key: bytes) -> str:
    """
    Decrypt a ciphertext string (base64-encoded token) using a given Fernet key.

    Args:
        ciphertext: The base64-encoded token from 'encrypt_string'.
        key: The same 32-byte key used to encrypt.

    Returns:
        The original plaintext string.

    Raises:
        RuntimeError: If 'cryptography' is not installed.
        ValueError: If the token is invalid or cannot be decrypted.
    """
    if not CRYPTO_AVAILABLE:
        raise RuntimeError("cryptography library is not installed.")
    f = Fernet(key)
    try:
        decrypted = f.decrypt(ciphertext.encode("utf-8"))
        return decrypted.decode("utf-8")
    except InvalidToken:
        raise ValueError("Decryption failed: Invalid key or ciphertext.")
