import base64
import hashlib

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


def _get_fernet() -> Fernet:
    key = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
    return Fernet(base64.urlsafe_b64encode(key))


def encrypt_value(plaintext: str) -> str:
    if not plaintext:
        return ""
    f = _get_fernet()
    return f.encrypt(plaintext.encode()).decode()


def decrypt_value(ciphertext: str) -> str:
    if not ciphertext:
        return ""
    f = _get_fernet()
    return f.decrypt(ciphertext.encode()).decode()


def compute_national_id_hash(value: str) -> str:
    if not value:
        return ""
    salt = settings.SECRET_KEY.encode()
    return hashlib.sha256(salt + value.strip().encode()).hexdigest()


def mask_national_id(value: str) -> str:
    if not value:
        return ""
    value = value.strip()
    if len(value) <= 4:
        return "*" * len(value)
    return "*" * (len(value) - 4) + value[-4:]


class EncryptedCharField(models.CharField):
    def get_prep_value(self, value):
        if not value:
            return value
        return encrypt_value(str(value))

    def from_db_value(self, value, expression, connection):
        if not value:
            return value
        try:
            return decrypt_value(value)
        except Exception:
            return value

    def to_python(self, value):
        if not value:
            return value
        if isinstance(value, str):
            try:
                return decrypt_value(value)
            except Exception:
                return value
        return value

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        path = "apps.core.encryption.EncryptedCharField"
        return name, path, args, kwargs
