"""Symmetric encryption for secrets (e.g. env vars)."""
import base64
import hashlib
import secrets
from typing import Any

from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

from src.config import get_settings

settings = get_settings()


def _get_fernet() -> Fernet:
    """Create Fernet instance from encryption key."""
    key_bytes = settings.encryption_key.encode()
    if len(key_bytes) < 32:
        # Pad or derive key if too short
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=b"p2hs_env_encryption",
            iterations=100000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(key_bytes))
    else:
        key = base64.urlsafe_b64encode(hashlib.sha256(key_bytes).digest())
    return Fernet(key)


def encrypt_value(plain_value: str) -> str:
    """Encrypt a string value for storage."""
    fernet = _get_fernet()
    return fernet.encrypt(plain_value.encode()).decode()


def decrypt_value(encrypted_value: str) -> str:
    """Decrypt a stored value."""
    fernet = _get_fernet()
    try:
        return fernet.decrypt(encrypted_value.encode()).decode()
    except InvalidToken:
        raise ValueError("Invalid or corrupted encrypted value")


def encrypt_dict(data: dict[str, str]) -> dict[str, str]:
    """Encrypt each value in a dict individually."""
    return {k: encrypt_value(v) for k, v in data.items()}


def decrypt_dict(encrypted: dict[str, str]) -> dict[str, str]:
    """Decrypt each value in a dict individually."""
    return {k: decrypt_value(v) for k, v in encrypted.items()}
