"""
Unit tests for FreeExile Security Fortress:
- Apple App Attest & DeviceCheck Verification
- ChaCha20-Poly1305 / AEAD Packet Encryption & Integrity Verification
- Anti-Replay Sliding Window Guard
"""

import unittest
import time
import sys
import os

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../server")))

from security.app_attest import AppleAppAttestValidator, AttestationToken
from security.packet_cipher import PacketCipherEngine, AntiReplayWindow


class TestSecurityFortress(unittest.TestCase):
    def setUp(self):
        self.attest_validator = AppleAppAttestValidator(expected_bundle_id="com.freeexile.game.ios")
        self.cipher_engine = PacketCipherEngine(shared_key=b"FREEEXILE_32BYTE_MASTER_KEY_001")
        self.replay_guard = AntiReplayWindow(window_size=64)

    def test_app_attest_valid_genuine_device(self):
        """Genuine iPhone with valid Secure Enclave key and valid challenge passes attestation."""
        token = self.attest_validator.generate_mock_attestation(
            device_id="iphone_15_pro_secure_enclave_01",
            bundle_id="com.freeexile.game.ios"
        )
        is_valid, msg = self.attest_validator.verify_attestation(token)
        self.assertTrue(is_valid)
        self.assertIn("verified", msg.lower())

    def test_app_attest_reject_bundle_tampering(self):
        """Attestation with modified/cracked IPA bundle ID is immediately rejected."""
        tampered_token = self.attest_validator.generate_mock_attestation(
            device_id="jailbroken_device_02",
            bundle_id="com.cracked.freeexile" # Tampered bundle ID
        )
        is_valid, msg = self.attest_validator.verify_attestation(tampered_token)
        self.assertFalse(is_valid)
        self.assertIn("bundle", msg.lower())

    def test_packet_encryption_and_tamper_detection(self):
        """Payload is encrypted; tampering with any byte causes MAC authentication failure."""
        plaintext = b"PLAYER_MOVE_DIR_X_1.0_DIR_Y_0.0"
        seq_num = 1001

        ciphertext, tag, nonce = self.cipher_engine.encrypt(plaintext, seq_num)
        self.assertNotEqual(ciphertext, plaintext)

        # Successful decryption
        decrypted = self.cipher_engine.decrypt(ciphertext, tag, nonce, seq_num)
        self.assertEqual(decrypted, plaintext)

        # Tampered ciphertext (1 byte changed)
        tampered_ciphertext = bytearray(ciphertext)
        tampered_ciphertext[0] ^= 0xFF
        with self.assertRaises(ValueError):
            self.cipher_engine.decrypt(bytes(tampered_ciphertext), tag, nonce, seq_num)

    def test_anti_replay_sliding_window(self):
        """Replayed packets or duplicate sequence numbers are rejected."""
        # Packet 1 arrives
        self.assertTrue(self.replay_guard.check_and_update(1))
        # Packet 2 arrives
        self.assertTrue(self.replay_guard.check_and_update(2))
        # Packet 2 replayed -> rejected!
        self.assertFalse(self.replay_guard.check_and_update(2))
        # Packet 1 replayed -> rejected!
        self.assertFalse(self.replay_guard.check_and_update(1))
        # Packet 10 arrives (in order)
        self.assertTrue(self.replay_guard.check_and_update(10))
        # Packet 5 arrives (within sliding window) -> accepted first time
        self.assertTrue(self.replay_guard.check_and_update(5))
        # Packet 5 replayed -> rejected
        self.assertFalse(self.replay_guard.check_and_update(5))


if __name__ == "__main__":
    unittest.main()
