"""
Encryption Module - Chiffrement des exports d'audit.

Ce module implémente le chiffrement des données d'audit exportées pour
protéger les informations sensibles.

Exigences : 17.4
"""

import base64
import json
from typing import Any, Dict

from cryptography.fernet import Fernet
from pydantic import BaseModel, Field


class EncryptionKey(BaseModel):
    """Clé de chiffrement."""

    key: bytes = Field(..., description="Clé de chiffrement Fernet")

    @classmethod
    def generate(cls) -> "EncryptionKey":
        """
        Génère une nouvelle clé de chiffrement.

        Returns:
            EncryptionKey générée
        """
        return cls(key=Fernet.generate_key())

    @classmethod
    def from_string(cls, key_string: str) -> "EncryptionKey":
        """
        Crée une clé depuis une chaîne base64.

        Args:
            key_string: Clé en format base64

        Returns:
            EncryptionKey
        """
        return cls(key=key_string.encode())

    def to_string(self) -> str:
        """
        Convertit la clé en chaîne base64.

        Returns:
            Clé en format base64
        """
        return self.key.decode()


class AuditEncryptor:
    """
    Chiffreur pour les exports d'audit.

    Utilise Fernet (AES-128 en mode CBC avec HMAC) pour chiffrer
    les données d'audit exportées.

    Exigences : 17.4
    """

    def __init__(self, encryption_key: EncryptionKey):
        """
        Initialise l'AuditEncryptor.

        Args:
            encryption_key: Clé de chiffrement
        """
        self.encryption_key = encryption_key
        self.cipher = Fernet(encryption_key.key)

    def encrypt_audit_data(self, audit_data: Dict[str, Any]) -> bytes:
        """
        Chiffre les données d'audit.

        Args:
            audit_data: Données d'audit à chiffrer (dict)

        Returns:
            Données chiffrées (bytes)

        Exigences : 17.4
        """
        # Convertir en JSON
        json_data = json.dumps(audit_data, default=str, ensure_ascii=False)

        # Encoder en bytes
        data_bytes = json_data.encode("utf-8")

        # Chiffrer
        encrypted_data = self.cipher.encrypt(data_bytes)

        return encrypted_data

    def decrypt_audit_data(self, encrypted_data: bytes) -> Dict[str, Any]:
        """
        Déchiffre les données d'audit.

        Args:
            encrypted_data: Données chiffrées (bytes)

        Returns:
            Données d'audit déchiffrées (dict)

        Raises:
            cryptography.fernet.InvalidToken: Si le déchiffrement échoue
        """
        # Déchiffrer
        decrypted_bytes = self.cipher.decrypt(encrypted_data)

        # Décoder
        json_data = decrypted_bytes.decode("utf-8")

        # Parser JSON
        audit_data = json.loads(json_data)

        return audit_data

    def encrypt_to_base64(self, audit_data: Dict[str, Any]) -> str:
        """
        Chiffre les données d'audit et retourne en base64.

        Args:
            audit_data: Données d'audit à chiffrer

        Returns:
            Données chiffrées en base64 (str)
        """
        encrypted_data = self.encrypt_audit_data(audit_data)
        return base64.b64encode(encrypted_data).decode("ascii")

    def decrypt_from_base64(self, encrypted_base64: str) -> Dict[str, Any]:
        """
        Déchiffre les données d'audit depuis base64.

        Args:
            encrypted_base64: Données chiffrées en base64

        Returns:
            Données d'audit déchiffrées
        """
        encrypted_data = base64.b64decode(encrypted_base64.encode("ascii"))
        return self.decrypt_audit_data(encrypted_data)
