import os
import base64
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC


class KeyEncryption:
    def __init__(self, encryption_key: str | None = None):
        self._fernet = self._create_fernet(encryption_key)

    def _create_fernet(self, key: str | None) -> Fernet:
        if not key:
            key = os.getenv("API_KEY_ENCRYPTION_KEY", "")

        if not key:
            return Fernet(Fernet.generate_key())

        try:
            return Fernet(key.encode())
        except Exception:
            kdf = PBKDF2HMAC(
                algorithm=hashes.SHA256(),
                length=32,
                salt=b"geo-platform-salt",
                iterations=100000,
            )
            derived_key = base64.urlsafe_b64encode(kdf.derive(key.encode()))
            return Fernet(derived_key)

    def encrypt(self, plaintext: str) -> str:
        if not plaintext:
            raise ValueError("Cannot encrypt empty string")
        return self._fernet.encrypt(plaintext.encode()).decode()

    def decrypt(self, ciphertext: str) -> str:
        if not ciphertext:
            raise ValueError("Cannot decrypt empty string")
        try:
            return self._fernet.decrypt(ciphertext.encode()).decode()
        except InvalidToken:
            raise ValueError("Invalid ciphertext or key")


_key_encryption: KeyEncryption | None = None


def get_key_encryption() -> KeyEncryption:
    global _key_encryption
    if _key_encryption is None:
        _key_encryption = KeyEncryption()
    return _key_encryption


def reset_key_encryption() -> None:
    global _key_encryption
    _key_encryption = None
