"""
Tests for Themis Fernet encryption utilities.
"""
from django.test import TestCase, override_settings

from themis.encryption import decrypt_value, encrypt_value, _get_fernet_key


class EncryptionTest(TestCase):
    """Tests for encrypt_value and decrypt_value."""

    def test_round_trip(self):
        """Encrypting then decrypting returns the original value."""
        original = "sk-abc123456789"
        encrypted = encrypt_value(original)
        decrypted = decrypt_value(encrypted)
        self.assertEqual(decrypted, original)

    def test_encrypted_differs_from_plaintext(self):
        """Encrypted value is not the same as the plaintext."""
        original = "my-secret-key"
        encrypted = encrypt_value(original)
        self.assertNotEqual(encrypted, original)

    def test_encrypted_is_string(self):
        """Encrypted value is returned as a string."""
        encrypted = encrypt_value("test")
        self.assertIsInstance(encrypted, str)

    def test_decrypted_is_string(self):
        """Decrypted value is returned as a string."""
        encrypted = encrypt_value("test")
        decrypted = decrypt_value(encrypted)
        self.assertIsInstance(decrypted, str)

    def test_empty_string(self):
        """Empty strings can be encrypted and decrypted."""
        encrypted = encrypt_value("")
        decrypted = decrypt_value(encrypted)
        self.assertEqual(decrypted, "")

    def test_unicode(self):
        """Unicode characters survive round-trip encryption."""
        original = "clé-secrète-日本語-🔑"
        encrypted = encrypt_value(original)
        decrypted = decrypt_value(encrypted)
        self.assertEqual(decrypted, original)

    def test_long_value(self):
        """Long strings can be encrypted and decrypted."""
        original = "x" * 10000
        encrypted = encrypt_value(original)
        decrypted = decrypt_value(encrypted)
        self.assertEqual(decrypted, original)

    def test_different_encryptions_differ(self):
        """Two encryptions of the same value produce different ciphertexts (Fernet uses timestamps/IV)."""
        original = "same-value"
        encrypted1 = encrypt_value(original)
        encrypted2 = encrypt_value(original)
        self.assertNotEqual(encrypted1, encrypted2)

    def test_decrypt_invalid_value_raises(self):
        """Decrypting an invalid value raises an exception."""
        with self.assertRaises(Exception):
            decrypt_value("not-a-valid-encrypted-string")

    @override_settings(SECRET_KEY="different-secret-key-for-testing")
    def test_different_secret_key_cannot_decrypt(self):
        """Values encrypted with one SECRET_KEY cannot be decrypted with another."""
        # This encrypted value was created with the test settings SECRET_KEY
        # Trying to decrypt with a different key should fail
        from themis.encryption import _get_fernet_key as get_key

        # The override_settings changes the key derivation
        with self.assertRaises(Exception):
            decrypt_value("gAAAAABk_invalid_but_looks_like_fernet")

    def test_fernet_key_is_consistent(self):
        """Same SECRET_KEY always produces the same Fernet key."""
        key1 = _get_fernet_key()
        key2 = _get_fernet_key()
        # Both should be Fernet instances with the same underlying key
        self.assertEqual(key1._signing_key, key2._signing_key)
        self.assertEqual(key1._encryption_key, key2._encryption_key)
