"""
Encryption utility module for BookBeach application
Provides encryption and decryption functionality using Fernet symmetric encryption
"""

from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import os


class PasswordEncryption:
    """Handle password encryption and decryption using a key"""
    
    def __init__(self, key_phrase: str):
        """
        Initialize the encryption handler with a key phrase
        
        Args:
            key_phrase (str): The key phrase to use for encryption/decryption
        """
        self.key_phrase = key_phrase
        self._fernet = self._create_fernet_key()
    
    def _create_fernet_key(self) -> Fernet:
        """Create a Fernet key from the key phrase"""
        # Use a fixed salt for consistent key generation
        salt = b'bookbeach_salt_123456789012345'  # 32 bytes
        
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(self.key_phrase.encode()))
        return Fernet(key)
    
    def encrypt(self, plaintext: str) -> str:
        """
        Encrypt a plaintext string
        
        Args:
            plaintext (str): The string to encrypt
            
        Returns:
            str: The encrypted string (base64 encoded)
        """
        if not plaintext:
            return ""
        
        encrypted_bytes = self._fernet.encrypt(plaintext.encode())
        return base64.urlsafe_b64encode(encrypted_bytes).decode()
    
    def decrypt(self, encrypted_text: str) -> str:
        """
        Decrypt an encrypted string
        
        Args:
            encrypted_text (str): The encrypted string (base64 encoded)
            
        Returns:
            str: The decrypted plaintext string
        """
        if not encrypted_text:
            return ""
        
        try:
            encrypted_bytes = base64.urlsafe_b64decode(encrypted_text.encode())
            decrypted_bytes = self._fernet.decrypt(encrypted_bytes)
            return decrypted_bytes.decode()
        except Exception as e:
            raise ValueError(f"Failed to decrypt text: {str(e)}")
    
    def is_encrypted(self, text: str) -> bool:
        """
        Check if a string appears to be encrypted
        
        Args:
            text (str): The string to check
            
        Returns:
            bool: True if the string appears to be encrypted
        """
        if not text:
            return False
        
        try:
            # Try to decrypt it - if successful, it was encrypted
            self.decrypt(text)
            return True
        except:
            return False


# Global encryption instance using the default key
DEFAULT_ENCRYPTION = PasswordEncryption("babagamma")


def encrypt_password(password: str, key_phrase: str = "babagamma") -> str:
    """
    Encrypt a password using the specified key phrase
    
    Args:
        password (str): The password to encrypt
        key_phrase (str): The key phrase to use for encryption
        
    Returns:
        str: The encrypted password
    """
    encryption = PasswordEncryption(key_phrase)
    return encryption.encrypt(password)


def decrypt_password(encrypted_password: str, key_phrase: str = "babagamma") -> str:
    """
    Decrypt a password using the specified key phrase
    
    Args:
        encrypted_password (str): The encrypted password
        key_phrase (str): The key phrase to use for decryption
        
    Returns:
        str: The decrypted password
    """
    encryption = PasswordEncryption(key_phrase)
    return encryption.decrypt(encrypted_password)


def is_encrypted(text: str, key_phrase: str = "babagamma") -> bool:
    """
    Check if a string is encrypted
    
    Args:
        text (str): The string to check
        key_phrase (str): The key phrase to use for testing decryption
        
    Returns:
        bool: True if the string appears to be encrypted
    """
    encryption = PasswordEncryption(key_phrase)
    return encryption.is_encrypted(text)