"""
Python test suite for irene_cipher

Run with: python test_irene_cipher.py
"""

import irene_cipher
import os
import tempfile
from pathlib import Path


def test_text_encryption():
    """Test basic text encryption and decryption"""
    print("Testing text encryption...", end=" ")
    
    password = "test_password_123"
    plaintext = "Hello, World! This is a test message."
    
    ciphertext = irene_cipher.encrypt_text(plaintext, password)
    decrypted = irene_cipher.decrypt_text(ciphertext, password)
    
    assert decrypted == plaintext
    assert len(ciphertext) > len(plaintext)
    print("✓")


def test_binary_encryption():
    """Test binary data encryption"""
    print("Testing binary encryption...", end=" ")
    
    password = "binary_pass"
    data = bytes(range(256))
    
    encrypted = irene_cipher.encrypt_bytes(data, password)
    decrypted = irene_cipher.decrypt_bytes(encrypted, password)
    
    assert decrypted == data
    print("✓")


def test_file_encryption():
    """Test file encryption and decryption"""
    print("Testing file encryption...", end=" ")
    
    with tempfile.TemporaryDirectory() as tmpdir:
        input_file = Path(tmpdir) / "input.txt"
        encrypted_file = Path(tmpdir) / "encrypted.bin"
        output_file = Path(tmpdir) / "output.txt"
        
        # Write test data
        test_data = b"File content\n" * 1000
        input_file.write_bytes(test_data)
        
        # Encrypt and decrypt
        password = "file_password"
        irene_cipher.encrypt_file(str(input_file), str(encrypted_file), password)
        irene_cipher.decrypt_file(str(encrypted_file), str(output_file), password)
        
        # Verify
        result = output_file.read_bytes()
        assert result == test_data
    
    print("✓")


def test_wrong_password():
    """Test that wrong password fails"""
    print("Testing wrong password detection...", end=" ")
    
    password = "correct"
    ciphertext = irene_cipher.encrypt_text("secret", password)
    
    try:
        irene_cipher.decrypt_text(ciphertext, "wrong")
        assert False, "Should have raised ValueError"
    except ValueError:
        pass  # Expected
    
    print("✓")


def test_tampered_data():
    """Test that tampered data fails"""
    print("Testing tampered data detection...", end=" ")
    
    password = "password"
    ciphertext = irene_cipher.encrypt_text("message", password)
    
    # Tamper with ciphertext
    tampered = bytearray(ciphertext)
    tampered[-1] ^= 0xFF
    
    try:
        irene_cipher.decrypt_text(bytes(tampered), password)
        assert False, "Should have raised ValueError"
    except ValueError:
        pass  # Expected
    
    print("✓")


def test_empty_data():
    """Test encryption of empty data"""
    print("Testing empty data...", end=" ")
    
    password = "pass"
    
    # Empty text
    ct = irene_cipher.encrypt_text("", password)
    pt = irene_cipher.decrypt_text(ct, password)
    assert pt == ""
    
    # Empty bytes
    ct = irene_cipher.encrypt_bytes(b"", password)
    pt = irene_cipher.decrypt_bytes(ct, password)
    assert pt == b""
    
    print("✓")


def test_large_data():
    """Test encryption of large data"""
    print("Testing large data (1 MB)...", end=" ")
    
    password = "large_data_pass"
    data = b"X" * (1024 * 1024)  # 1 MB
    
    encrypted = irene_cipher.encrypt_bytes(data, password)
    decrypted = irene_cipher.decrypt_bytes(encrypted, password)
    
    assert decrypted == data
    print("✓")


def test_unicode_text():
    """Test encryption of unicode text"""
    print("Testing unicode text...", end=" ")
    
    password = "unicode_pass"
    text = "Hello 世界 🌍 مرحبا Привет"
    
    ciphertext = irene_cipher.encrypt_text(text, password)
    plaintext = irene_cipher.decrypt_text(ciphertext, password)
    
    assert plaintext == text
    print("✓")


def test_key_generation():
    """Test random key generation"""
    print("Testing key generation...", end=" ")
    
    key1 = irene_cipher.generate_key()
    key2 = irene_cipher.generate_key()
    
    assert len(key1) == 32
    assert len(key2) == 32
    assert key1 != key2
    
    print("✓")


def test_nonce_uniqueness():
    """Test that same plaintext produces different ciphertext"""
    print("Testing nonce uniqueness...", end=" ")
    
    password = "same_pass"
    plaintext = "same message"
    
    ct1 = irene_cipher.encrypt_text(plaintext, password)
    ct2 = irene_cipher.encrypt_text(plaintext, password)
    ct3 = irene_cipher.encrypt_text(plaintext, password)
    
    # All should be different
    assert ct1 != ct2
    assert ct2 != ct3
    assert ct1 != ct3
    
    # But all should decrypt to same plaintext
    assert irene_cipher.decrypt_text(ct1, password) == plaintext
    assert irene_cipher.decrypt_text(ct2, password) == plaintext
    assert irene_cipher.decrypt_text(ct3, password) == plaintext
    
    print("✓")


def test_different_passwords():
    """Test that different passwords produce different ciphertext"""
    print("Testing password independence...", end=" ")
    
    plaintext = "message"
    
    ct1 = irene_cipher.encrypt_text(plaintext, "pass1")
    ct2 = irene_cipher.encrypt_text(plaintext, "pass2")
    ct3 = irene_cipher.encrypt_text(plaintext, "pass3")
    
    assert ct1 != ct2
    assert ct2 != ct3
    assert ct1 != ct3
    
    print("✓")


def test_large_file():
    """Test encryption of larger file"""
    print("Testing large file (5 MB)...", end=" ")
    
    with tempfile.TemporaryDirectory() as tmpdir:
        input_file = Path(tmpdir) / "large.bin"
        encrypted_file = Path(tmpdir) / "large.enc"
        output_file = Path(tmpdir) / "large.dec"
        
        # Create 5 MB file
        data = b"A" * (5 * 1024 * 1024)
        input_file.write_bytes(data)
        
        password = "large_file_pass"
        irene_cipher.encrypt_file(str(input_file), str(encrypted_file), password)
        irene_cipher.decrypt_file(str(encrypted_file), str(output_file), password)
        
        result = output_file.read_bytes()
        assert len(result) == len(data)
        assert result == data
    
    print("✓")


def run_all_tests():
    """Run all tests"""
    print()
    print("=" * 60)
    print("Running Irene Cipher Test Suite")
    print("=" * 60)
    print()
    
    tests = [
        test_text_encryption,
        test_binary_encryption,
        test_file_encryption,
        test_wrong_password,
        test_tampered_data,
        test_empty_data,
        test_large_data,
        test_unicode_text,
        test_key_generation,
        test_nonce_uniqueness,
        test_different_passwords,
        test_large_file,
    ]
    
    failed = 0
    for test in tests:
        try:
            test()
        except Exception as e:
            print(f"✗ FAILED: {e}")
            import traceback
            traceback.print_exc()
            failed += 1
    
    print()
    print("=" * 60)
    if failed == 0:
        print(f"✓ ALL {len(tests)} TESTS PASSED")
    else:
        print(f"✗ {failed}/{len(tests)} TESTS FAILED")
    print("=" * 60)
    print()
    
    return failed == 0


if __name__ == "__main__":
    import sys
    success = run_all_tests()
    sys.exit(0 if success else 1)
