# -*- coding: utf-8 -*-
"""
加密模块单元测试
"""
import pytest
import os

from v123pan.crypto.chacha20_encryptor import ChaCha20Encryptor


class TestChaCha20Encryptor:
    """ChaCha20 加密器测试"""

    def test_init_with_password(self):
        """测试使用密码初始化"""
        encryptor = ChaCha20Encryptor("test_password")
        assert encryptor.password == "test_password"
        assert encryptor.salt is not None
        assert len(encryptor.salt) == 16

    def test_init_with_custom_salt(self):
        """测试使用自定义 salt 初始化"""
        custom_salt = b"0123456789abcdef"
        encryptor = ChaCha20Encryptor("test_password", custom_salt)
        assert encryptor.salt == custom_salt

    def test_init_with_invalid_salt(self):
        """测试使用无效 salt 初始化"""
        with pytest.raises(ValueError):
            ChaCha20Encryptor("test_password", b"invalid")

    def test_init_with_none_salt(self):
        """测试使用 None salt 初始化（应随机生成）"""
        encryptor = ChaCha20Encryptor("test_password", None)
        assert encryptor.salt is not None
        assert len(encryptor.salt) == 16

    def test_derive_key(self):
        """测试密钥派生"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()
        assert encryptor.key is not None
        assert len(encryptor.key) == 32

    def test_encrypt_decrypt_round_trip(self):
        """测试加密/解密往返"""
        password = "test_password"
        data = b"Hello, World!"
        nonce = os.urandom(24)

        encryptor = ChaCha20Encryptor(password)
        encryptor.derive_key()

        # 加密
        encrypted = encryptor.encrypt(data, nonce)

        # 解密
        decrypted = encryptor.decrypt(encrypted, nonce)

        assert decrypted == data
        assert len(encrypted) == len(data) + 16  # 密文 + 16 字节 tag

    def test_encrypt_empty_data(self):
        """测试加密空数据"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()
        nonce = os.urandom(24)

        data = b""
        encrypted = encryptor.encrypt(data, nonce)
        decrypted = encryptor.decrypt(encrypted, nonce)

        assert decrypted == data

    def test_encrypt_large_data(self):
        """测试加密大数据"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()
        nonce = os.urandom(24)

        data = os.urandom(1024 * 1024)  # 1MB
        encrypted = encryptor.encrypt(data, nonce)
        decrypted = encryptor.decrypt(encrypted, nonce)

        assert decrypted == data

    def test_decrypt_wrong_nonce(self):
        """测试使用错误的 nonce 解密"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()

        data = b"Hello, World!"
        nonce1 = os.urandom(24)
        nonce2 = os.urandom(24)

        encrypted = encryptor.encrypt(data, nonce1)

        with pytest.raises(ValueError):
            encryptor.decrypt(encrypted, nonce2)

    def test_decrypt_wrong_password(self):
        """测试使用错误的密码解密"""
        data = b"Hello, World!"
        nonce = os.urandom(24)
        salt = os.urandom(16)

        # 用正确的密码加密
        encryptor1 = ChaCha20Encryptor("correct_password", salt)
        encryptor1.derive_key()
        encrypted = encryptor1.encrypt(data, nonce)

        # 用错误的密码解密
        encryptor2 = ChaCha20Encryptor("wrong_password", salt)
        encryptor2.derive_key()

        with pytest.raises(ValueError):
            encryptor2.decrypt(encrypted, nonce)

    def test_decrypt_tampered_data(self):
        """测试解密被篡改的数据"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()

        data = b"Hello, World!"
        nonce = os.urandom(24)

        encrypted = encryptor.encrypt(data, nonce)
        tampered = encrypted[:-1] + bytes([(encrypted[-1] + 1) % 256])

        with pytest.raises(ValueError):
            encryptor.decrypt(tampered, nonce)

    def test_nonce_length_validation(self):
        """测试 nonce 长度验证"""
        encryptor = ChaCha20Encryptor("test_password")
        encryptor.derive_key()

        data = b"Hello, World!"

        # 测试过短的 nonce
        with pytest.raises(ValueError):
            encryptor.encrypt(data, os.urandom(12))

        # 测试过长的 nonce
        with pytest.raises(ValueError):
            encryptor.encrypt(data, os.urandom(32))

    def test_key_property_without_derive(self):
        """测试未派生密钥时访问 key 属性"""
        encryptor = ChaCha20Encryptor("test_password")

        with pytest.raises(ValueError):
            _ = encryptor.key

    def test_same_password_same_salt_same_result(self):
        """测试相同密码和 salt 产生相同密钥"""
        salt = b"0123456789abcdef"

        encryptor1 = ChaCha20Encryptor("password", salt)
        encryptor1.derive_key()

        encryptor2 = ChaCha20Encryptor("password", salt)
        encryptor2.derive_key()

        assert encryptor1.key == encryptor2.key

    def test_same_password_different_salt_different_result(self):
        """测试相同密码不同 salt 产生不同密钥"""
        salt1 = b"0123456789abcdef"
        salt2 = b"fedcba9876543210"

        encryptor1 = ChaCha20Encryptor("password", salt1)
        encryptor1.derive_key()

        encryptor2 = ChaCha20Encryptor("password", salt2)
        encryptor2.derive_key()

        assert encryptor1.key != encryptor2.key
