import unittest
from unittest.mock import MagicMock
from datetime import datetime
import os
from security.memory.core import MemoryCore, EncryptionError, DecryptionError, AccessDenied, NotFound
from security.rbac_engine import RBACEngine, ClientCertInfo

class TestMemoryCore(unittest.TestCase):
    def setUp(self):
        # Setup mock RBAC engine
        self.mock_rbac = MagicMock(spec=RBACEngine)
        self.mock_rbac.validate_permission.return_value = True
        
        # Test encryption key
        self.test_key = os.urandom(32)
        
        # Initialize core
        self.core = MemoryCore(self.test_key, self.mock_rbac)
        
        # Test data
        self.test_key = "test_key"
        self.test_value = b"test_value"
        self.test_user = "test_user"
        self.test_cert = ClientCertInfo(
            subject={"CN": "test_cert"},
            issuer={"CN": "test_issuer"},
            not_before=datetime.now(),
            not_after=datetime(2030, 1, 1)
        )

    def test_create_success(self):
        result = self.core.create(self.test_key, self.test_value, self.test_user)
        self.assertTrue(result)
        self.assertIn(self.test_key, self.core.data)
        
    def test_create_rbac_failure(self):
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.create(self.test_key, self.test_value, self.test_user)
            
    def test_read_success(self):
        self.core.create(self.test_key, self.test_value, self.test_user)
        result = self.core.read(self.test_key, self.test_user)
        self.assertEqual(result, self.test_value)
        
    def test_read_not_found(self):
        with self.assertRaises(NotFound):
            self.core.read("nonexistent_key", self.test_user)
            
    def test_read_rbac_failure(self):
        self.core.create(self.test_key, self.test_value, self.test_user)
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.read(self.test_key, self.test_user)
            
    def test_update_success(self):
        self.core.create(self.test_key, self.test_value, self.test_user)
        new_value = b"new_value"
        result = self.core.update(self.test_key, new_value, self.test_user)
        self.assertTrue(result)
        self.assertEqual(self.core.read(self.test_key, self.test_user), new_value)
        
    def test_update_not_found(self):
        with self.assertRaises(NotFound):
            self.core.update("nonexistent_key", self.test_value, self.test_user)
            
    def test_delete_success(self):
        self.core.create(self.test_key, self.test_value, self.test_user)
        result = self.core.delete(self.test_key, self.test_user)
        self.assertTrue(result)
        self.assertNotIn(self.test_key, self.core.data)
        
    def test_encryption_error(self):
        with self.assertRaises(EncryptionError):
            # Pass invalid key to force encryption error
            bad_core = MemoryCore(b"invalid_key", self.mock_rbac)
            bad_core.create(self.test_key, self.test_value, self.test_user)
            
    def test_decryption_error(self):
        self.core.create(self.test_key, self.test_value, self.test_user)
        # Corrupt the encrypted data
        self.core.data[self.test_key] = b"corrupted_data"
        with self.assertRaises(DecryptionError):
            self.core.read(self.test_key, self.test_user)
            
    def test_audit_logging(self):
        initial_log_count = len(self.core.audit_log)
        self.core.create(self.test_key, self.test_value, self.test_user)
        self.assertEqual(len(self.core.audit_log), initial_log_count + 1)
        
        self.core.read(self.test_key, self.test_user)
        self.assertEqual(len(self.core.audit_log), initial_log_count + 2)
        
    def test_cert_based_auth(self):
        result = self.core.create(self.test_key, self.test_value, cert_info=self.test_cert)
        self.assertTrue(result)
        self.assertIn(self.test_key, self.core.data)

    def test_memory_operations_rbac_integration(self):
        """Test RBAC integration with memory operations"""
        # Test create with valid permission
        self.mock_rbac.validate_permission.return_value = True
        result = self.core.create("key1", b"value1", self.test_user)
        self.assertTrue(result)
        
        # Test create with invalid permission
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.create("key2", b"value2", self.test_user)
            
        # Test read with valid permission
        self.mock_rbac.validate_permission.return_value = True
        value = self.core.read("key1", self.test_user)
        self.assertEqual(value, b"value1")
        
        # Test read with invalid permission
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.read("key1", self.test_user)
            
        # Test update with valid permission
        self.mock_rbac.validate_permission.return_value = True
        result = self.core.update("key1", b"new_value", self.test_user)
        self.assertTrue(result)
        
        # Test update with invalid permission
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.update("key1", b"new_value", self.test_user)
            
        # Test delete with valid permission
        self.mock_rbac.validate_permission.return_value = True
        result = self.core.delete("key1", self.test_user)
        self.assertTrue(result)
        
        # Test delete with invalid permission
        self.core.create("key1", b"value1", self.test_user)
        self.mock_rbac.validate_permission.return_value = False
        with self.assertRaises(AccessDenied):
            self.core.delete("key1", self.test_user)
            
    def test_memory_operations_cert_auth(self):
        """Test certificate-based authentication for memory operations"""
        # Test create with valid cert
        self.mock_rbac.validate_permission.return_value = True
        result = self.core.create("key1", b"value1", cert_info=self.test_cert)
        self.assertTrue(result)
        
        # Test read with valid cert
        value = self.core.read("key1", cert_info=self.test_cert)
        self.assertEqual(value, b"value1")
        
        # Test update with valid cert
        result = self.core.update("key1", b"new_value", cert_info=self.test_cert)
        self.assertTrue(result)
        
        # Test delete with valid cert
        result = self.core.delete("key1", cert_info=self.test_cert)
        self.assertTrue(result)

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