"""
Encryption utilities for sensitive data like API keys.
Uses Fernet (symmetric encryption) from cryptography library.
"""

import os
import base64
from typing import Optional
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC


class KeyEncryption:
    """Handles encryption/decryption of API keys."""

    def __init__(self, master_key: Optional[str] = None):
        """
        Initialize with a master key.
        If not provided, uses environment variable or generates one.
        """
        if master_key:
            self.master_key = master_key.encode()
        else:
            # Use ENCRYPTION_KEY as the standard environment variable
            env_key = os.getenv("ENCRYPTION_KEY")
            if env_key:
                self.master_key = env_key.encode()
            else:
                # Fail fast - encryption key is required
                raise ValueError(
                    "ENCRYPTION_KEY environment variable is not set. "
                    "This is required for secure API key storage. "
                    'Generate one with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"'
                )

        # Derive a key from the master key using PBKDF2
        salt = (
            b"foundrymatch_salt_v1"  # In production, use a random salt per deployment
        )
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(self.master_key))
        self.cipher = Fernet(key)

    def encrypt(self, plaintext: str) -> str:
        """Encrypt a plaintext string."""
        encrypted = self.cipher.encrypt(plaintext.encode())
        return base64.urlsafe_b64encode(encrypted).decode()

    def decrypt(self, ciphertext: str) -> str:
        """Decrypt a ciphertext string."""
        try:
            encrypted = base64.urlsafe_b64decode(ciphertext.encode())
            decrypted = self.cipher.decrypt(encrypted)
            return decrypted.decode()
        except Exception as e:
            raise ValueError(f"Failed to decrypt: {e}")

    @staticmethod
    def generate_master_key() -> str:
        """Generate a new master key for encryption."""
        return Fernet.generate_key().decode()


# Global instance (initialized once)
_encryptor = None


def get_encryptor() -> KeyEncryption:
    """Get or create the global encryptor instance."""
    global _encryptor
    if _encryptor is None:
        _encryptor = KeyEncryption()
    return _encryptor


def encrypt_api_key(key: str) -> str:
    """Encrypt an API key for storage."""
    return get_encryptor().encrypt(key)


def decrypt_api_key(encrypted_key: str) -> str:
    """Decrypt an API key from storage."""
    return get_encryptor().decrypt(encrypted_key)
