"""Credential vault: envelope encryption, decryption, and key rotation."""

from __future__ import annotations

import base64

import pytest
from cryptography.fernet import Fernet
from legate.vault import Vault, VaultError
from legate.vault.crypto import _fernet_from_master


def _key(seed: bytes) -> Fernet:
    return Fernet(base64.urlsafe_b64encode(seed * 32))


def test_encrypt_decrypt_round_trip():
    vault = Vault.from_settings()
    secret = {"bot_token": "xoxb-super-secret", "extra": 1}
    enc = vault.encrypt(secret)

    assert "xoxb-super-secret" not in enc.ciphertext  # not stored in the clear
    assert enc.wrapped_dek and enc.key_version == "1"
    assert vault.decrypt(enc.ciphertext, enc.wrapped_dek, enc.key_version) == secret


def test_each_record_uses_a_fresh_data_key():
    vault = Vault.from_settings()
    a = vault.encrypt({"v": "same"})
    b = vault.encrypt({"v": "same"})
    assert a.wrapped_dek != b.wrapped_dek  # different DEKs
    assert a.ciphertext != b.ciphertext


def test_wrong_master_key_cannot_decrypt():
    k1 = _key(b"1")
    k2 = _key(b"2")
    enc = Vault({"1": k1}, "1").encrypt({"token": "abc"})
    other = Vault({"1": k2}, "1")
    with pytest.raises(VaultError):
        other.decrypt(enc.ciphertext, enc.wrapped_dek, enc.key_version)


def test_key_rotation_rewraps_without_losing_data():
    k1, k2 = _key(b"1"), _key(b"2")
    v1 = Vault({"1": k1}, "1")
    enc = v1.encrypt({"token": "abc"})

    # A vault that knows both keys, defaulting to version 2.
    v2 = Vault({"1": k1, "2": k2}, "2")
    rewrapped = v2.rewrap(enc.ciphertext, enc.wrapped_dek, enc.key_version)

    assert rewrapped.key_version == "2"
    assert rewrapped.ciphertext == enc.ciphertext  # payload untouched
    assert v2.decrypt(rewrapped.ciphertext, rewrapped.wrapped_dek, "2") == {"token": "abc"}
    # The original (version 1) record still decrypts too.
    assert v2.decrypt(enc.ciphertext, enc.wrapped_dek, "1") == {"token": "abc"}


def test_invalid_master_key_is_rejected():
    with pytest.raises(VaultError):
        _fernet_from_master("")
    with pytest.raises(VaultError):
        _fernet_from_master(base64.b64encode(b"too-short").decode())
