"""
Zentrale Krypto-Hilfsfunktionen für TimeMaster.

Verwendet Fernet-Verschlüsselung (AES-128-CBC + HMAC-SHA256).
Der Schlüssel wird per SHA-256 abgeleitet aus:
  - SECRET_KEY_DATA  (empfohlen, separater Key für Datenverschlüsselung)
  - SECRET_KEY       (Fallback wenn SECRET_KEY_DATA nicht gesetzt – Warnung beim Start)

Verwendung:
    from app.core.crypto import encrypt_value, decrypt_value

    stored = encrypt_value("geheimes-passwort")
    plain  = decrypt_value(stored)
"""
from __future__ import annotations

import base64
import hashlib
import logging

from cryptography.fernet import Fernet, InvalidToken

from app.core.config import settings

logger = logging.getLogger(__name__)


def get_fernet_key() -> bytes:
    """Gibt den Fernet-Key zurück.

    Bevorzugt SECRET_KEY_DATA (separater Datenschlüssel).
    Fällt auf SECRET_KEY zurück wenn SECRET_KEY_DATA nicht gesetzt ist,
    und gibt dabei eine Warnung aus (JWT- und Datenschlüssel identisch).

    Der Key wird per SHA-256 auf 32 Bytes normiert und dann base64url-kodiert.
    """
    if settings.secret_key_data:
        key_material = settings.secret_key_data
    else:
        logger.warning(
            "SECRET_KEY_DATA nicht gesetzt — JWT-Key wird auch für Datenverschlüsselung "
            "verwendet. Bitte SECRET_KEY_DATA in .env setzen für verbesserte Sicherheit."
        )
        key_material = settings.secret_key

    key_bytes = hashlib.sha256(key_material.encode()).digest()
    return base64.urlsafe_b64encode(key_bytes)


def _fernet() -> Fernet:
    """Erstellt eine Fernet-Instanz aus dem konfigurierten Datenschlüssel."""
    return Fernet(get_fernet_key())


def encrypt_value(plain: str) -> str:
    """Verschlüsselt einen Klartext-String per Fernet. Gibt den chiffrierten String zurück."""
    return _fernet().encrypt(plain.encode()).decode()


def decrypt_value(encrypted: str) -> str:
    """
    Entschlüsselt einen Fernet-verschlüsselten String.
    Wirft ValueError bei ungültigem Token oder falschem Schlüssel.
    """
    try:
        return _fernet().decrypt(encrypted.encode()).decode()
    except InvalidToken as exc:
        raise ValueError("Entschlüsselung fehlgeschlagen – ungültiger Token oder falscher Schlüssel.") from exc
