import unittest
from unittest import TestCase
from unittest.mock import Mock
from analogai.foundation.modules.user.user import User
from analogai.foundation.infrastructure.repositories.in_memory.in_memory_user_repository_impl import InMemoryUserRepositoryImpl
from analogai.foundation.infrastructure.storage.storage_adapter import StorageAdapter
from analogai.foundation.infrastructure.mappers import UserStorageMapper

class TestUserRepositoryImpl(TestCase):
    def setUp(self):
        self.storage_adapter = Mock(spec=StorageAdapter)
        self.repository = InMemoryUserRepositoryImpl(storage_adapter=self.storage_adapter)
        self.test_user = User(
            id="user_id",
            name="Test User",
            email="test@example.com",
            nationality="USA",
            location="NY"
        )
        self.collection = "users"

    def test_create_calls_store_and_returns_user(self):
        result = self.repository.create(self.test_user)
        
        expected_data = UserStorageMapper.to_dict(self.test_user)
        self.storage_adapter.store.assert_called_once_with(self.collection, expected_data)
        self.assertEqual(result, self.test_user)
        self.assertEqual(result.id, "user_id")
        self.assertEqual(result.email, "test@example.com")
        self.assertEqual(result.name, "Test User")
        self.assertEqual(result.nationality, "USA")
        self.assertEqual(result.location, "NY")

    def test_create_without_id(self):
        user_no_id = User(id="generated_id", name="No ID User", email="no_id@example.com")
        
        result = self.repository.create(user_no_id)
        
        expected_data = UserStorageMapper.to_dict(user_no_id)
        self.storage_adapter.store.assert_called_once_with(self.collection, expected_data)
        self.assertIsNotNone(result.id)
        self.assertEqual(result.email, "no_id@example.com")

    def test_find_by_id_existing(self):
        user_data = UserStorageMapper.to_dict(self.test_user)
        self.storage_adapter.retrieve_by_id.return_value = user_data
        
        result = self.repository.find_by_id("user_id")
        
        self.storage_adapter.retrieve_by_id.assert_called_once_with(self.collection, "user_id")
        self.assertEqual(result.id, "user_id")
        self.assertEqual(result.email, "test@example.com")

    def test_find_by_id_nonexistent(self):
        self.storage_adapter.retrieve_by_id.return_value = None
        
        result = self.repository.find_by_id("nonexistent_id")
        
        self.storage_adapter.retrieve_by_id.assert_called_once_with(self.collection, "nonexistent_id")
        self.assertIsNone(result)

    def test_create_with_optional_fields_unset(self):
        minimal_user = User(id="minimal_id", name="Minimal User", email="minimal@example.com")
        
        result = self.repository.create(minimal_user)
        
        expected_data = UserStorageMapper.to_dict(minimal_user)
        self.storage_adapter.store.assert_called_once_with(self.collection, expected_data)
        self.assertEqual(result.id, "minimal_id")
        self.assertEqual(result.email, "minimal@example.com")
        self.assertEqual(result.name, "Minimal User")
        # self.assertIsNone(result.phone)

    def test_update_user(self):
        updated_user = User(
            id="user_id",
            name="Updated Name",
            email="updated@example.com",
            nationality="Canada"
        )
        
        result = self.repository.update(updated_user)
        
        expected_data = UserStorageMapper.to_dict(updated_user)
        self.storage_adapter.store.assert_called_once_with(self.collection, expected_data)
        self.assertEqual(result, updated_user)
        self.assertEqual(result.name, "Updated Name")
        self.assertEqual(result.email, "updated@example.com")
        self.assertEqual(result.nationality, "Canada")
    
    def test_user_with_timezone(self):
        timezone = "America/New_York"
        user = User(
            id="tz_user_id",
            name="Timezone User",
            email="tz@example.com",
            timezone=timezone
        )
        
        result = self.repository.create(user)
        
        expected_data = UserStorageMapper.to_dict(user)
        self.storage_adapter.store.assert_called_once_with(self.collection, expected_data)
        self.assertEqual(result.timezone, timezone)
        
        user_data = UserStorageMapper.to_dict(user)
        self.storage_adapter.retrieve_by_id.return_value = user_data
        retrieved = self.repository.find_by_id("tz_user_id")
        self.assertEqual(retrieved.timezone, timezone)
    
    def test_user_default_timezone(self):
        user = User(id="default_tz_id", name="Default TZ User", email="default_tz@example.com")
        
        self.assertIsNotNone(user.timezone)
        
        result = self.repository.create(user)
        self.assertIsNotNone(result.timezone)

    def test_find_by_email_existing(self):
        user_data = UserStorageMapper.to_dict(self.test_user)
        self.storage_adapter.retrieve_by_attributes.return_value = [user_data]
        
        result = self.repository.find_by_email("test@example.com")
        
        self.storage_adapter.retrieve_by_attributes.assert_called_once_with(self.collection, {"email": "test@example.com"})
        self.assertEqual(result.id, "user_id")
        self.assertEqual(result.email, "test@example.com")

    def test_find_by_email_nonexistent(self):
        self.storage_adapter.retrieve_by_attributes.return_value = []
        
        result = self.repository.find_by_email("nonexistent@example.com")
        
        self.storage_adapter.retrieve_by_attributes.assert_called_once_with(self.collection, {"email": "nonexistent@example.com"})
        self.assertIsNone(result)

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