"""
crypto_utils.py — Enkripsi/dekripsi hasil transkripsi menggunakan Fernet (AES-128-CBC).

Cara generate key baru (jalankan sekali, simpan hasilnya di .env):
    python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

Tambahkan ke .env:
    ENCRYPTION_KEY=<hasil>

PENTING:
- Jangan ganti key setelah data tersimpan — data lama tidak bisa didekripsi.
- Simpan key di tempat aman (secrets manager, vault, bukan di repo).
- Jika key hilang, semua hasil transkripsi menjadi tidak terbaca.
"""

import os
import logging
from cryptography.fernet import Fernet, InvalidToken

logger = logging.getLogger(__name__)

# Cache instance agar tidak re-init setiap panggilan
_fernet: Fernet | None = None


def _get_fernet() -> Fernet:
    global _fernet
    if _fernet is None:
        key = os.getenv("ENCRYPTION_KEY", "")
        if not key:
            raise RuntimeError(
                "[Crypto] ENCRYPTION_KEY belum diset di environment variable!\n"
                "Generate key:\n"
                "  python -c \"from cryptography.fernet import Fernet; "
                "print(Fernet.generate_key().decode())\"\n"
                "Lalu tambahkan ke .env: ENCRYPTION_KEY=<hasil>"
            )
        try:
            _fernet = Fernet(key.encode("utf-8"))
        except Exception as exc:
            raise RuntimeError(
                f"[Crypto] ENCRYPTION_KEY tidak valid: {exc}\n"
                "Pastikan key di-generate dengan Fernet.generate_key()."
            ) from exc
    return _fernet


def encrypt_text(text: str) -> str:
    """
    Enkripsi plaintext → Fernet token (base64url-safe string).
    Mengembalikan string kosong jika input kosong/None.
    """
    if not text:
        return text
    return _get_fernet().encrypt(text.encode("utf-8")).decode("utf-8")


def decrypt_text(token: str) -> str:
    """
    Dekripsi Fernet token → plaintext.

    Backward-compatible: jika token bukan Fernet yang valid
    (data lama sebelum enkripsi diterapkan), kembalikan token
    apa adanya daripada crash — sehingga migrasi bisa bertahap.
    """
    if not token:
        return token
    try:
        return _get_fernet().decrypt(token.encode("utf-8")).decode("utf-8")
    except (InvalidToken, Exception):
        # Data lama (plaintext) atau key berbeda — biarkan as-is
        logger.debug("[Crypto] Dekripsi gagal — kemungkinan data plaintext lama.")
        return token


def is_encrypted(token: str) -> bool:
    """
    Cek apakah string sudah terenkripsi (berguna untuk migrasi data lama).
    Heuristik: Fernet token selalu diawali 'gAAA' dan panjangnya > 60.
    """
    if not token:
        return False
    return token.startswith("gAAA") and len(token) > 60