"""Encryption utilities for Lettera entries.

Uses XSalsa20-Poly1305 (PyNaCl SecretBox) with PBKDF2-SHA256 key derivation.
Encrypted file format:
    LETTERA_ENC:v1:<base64(salt)>:<base64(nonce + ciphertext + mac)>
"""

import base64
import hashlib
import os

from nacl.secret import SecretBox

HEADER_PREFIX = "LETTERA_ENC:v1:"
_SALT_BYTES = 16
_KEY_BYTES = 32
_PBKDF2_ITERATIONS = 480_000


def _derive_key(passphrase: str, salt: bytes) -> bytes:
    return hashlib.pbkdf2_hmac(
        "sha256", passphrase.encode("utf-8"), salt, _PBKDF2_ITERATIONS, _KEY_BYTES
    )


def is_encrypted(content: str) -> bool:
    return content.startswith(HEADER_PREFIX)


def encrypt_content(passphrase: str, plaintext: str) -> str:
    salt = os.urandom(_SALT_BYTES)
    key = _derive_key(passphrase, salt)
    box = SecretBox(key)
    encrypted = box.encrypt(plaintext.encode("utf-8"))  # nonce prepended automatically
    salt_b64 = base64.b64encode(salt).decode("ascii")
    payload_b64 = base64.b64encode(bytes(encrypted)).decode("ascii")
    return f"{HEADER_PREFIX}{salt_b64}:{payload_b64}"


def decrypt_content(passphrase: str, encrypted: str) -> str:
    """Decrypt an encrypted entry string.

    Raises ValueError if the passphrase is wrong or the content is corrupt.
    """
    if not encrypted.startswith(HEADER_PREFIX):
        raise ValueError("Not an encrypted entry")
    rest = encrypted[len(HEADER_PREFIX):]
    parts = rest.split(":")
    if len(parts) != 2:
        raise ValueError("Malformed encrypted entry")
    salt = base64.b64decode(parts[0])
    payload = base64.b64decode(parts[1])
    key = _derive_key(passphrase, salt)
    box = SecretBox(key)
    try:
        plaintext_bytes = box.decrypt(payload)
    except Exception:
        raise ValueError("Decryption failed — wrong passphrase or corrupted entry")
    return plaintext_bytes.decode("utf-8")
