import base64
import hashlib

from cryptography.fernet import Fernet
from django.conf import settings
from django.db import models


def _get_fernet():
    """Derive a Fernet key from Django's SECRET_KEY."""
    raw_key = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
    return Fernet(base64.urlsafe_b64encode(raw_key))


class EncryptedCharField(models.TextField):
    """
    Stores values encrypted at rest using Fernet symmetric encryption.
    The encryption key is derived from Django's SECRET_KEY so no extra
    secrets management is required — if the SECRET_KEY is set, values
    are protected.

    From the application's perspective this behaves like a plain text field:
    you read/write plaintext; encryption/decryption happens transparently.
    """

    def from_db_value(self, value, expression, connection):
        if not value:
            return value
        try:
            return _get_fernet().decrypt(value.encode()).decode()
        except Exception:
            # Gracefully return raw value if decryption fails
            # (e.g. migrating plaintext rows that were saved before encryption)
            return value

    def get_prep_value(self, value):
        if not value:
            return value
        return _get_fernet().encrypt(value.encode()).decode()
