import unittest
from unittest.mock import Mock
from analogai.foundation.modules.user.user import User
from analogai.foundation.infrastructure.repositories.mongodb.mongodb_user_repository_impl import MongoDBUserRepositoryImpl
from analogai.foundation.infrastructure.tests.repositories.mongodb.test_config import MongoDBEnvironmentCheckMixin

class TestMongoDBUserRepositoryImpl(MongoDBEnvironmentCheckMixin, unittest.TestCase):
    def setUp(self):
        self.mock_storage_adapter = Mock()
        self.repository = MongoDBUserRepositoryImpl(self.mock_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)
        
        self.mock_storage_adapter.store.assert_called_once()
        call_args = self.mock_storage_adapter.store.call_args
        self.assertEqual(call_args[0][0], self.collection)
        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")

    def test_find_by_id_existing(self):
        mock_doc = {
            "id": "user_id",
            "name": "Test User",
            "email": "test@example.com",
            "nationality": "USA",
            "location": "NY",
            "timezone": "America/New_York"
        }
        self.mock_storage_adapter.retrieve_by_id.return_value = mock_doc
        
        result = self.repository.find_by_id("user_id")
        
        self.mock_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")
        self.assertEqual(result.name, "Test User")
        self.assertEqual(result.nationality, "USA")
        self.assertEqual(result.location, "NY")
        self.assertEqual(result.timezone, "America/New_York")

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

    def test_find_by_email_existing(self):
        mock_doc = {
            "id": "user_id",
            "name": "Test User",
            "email": "test@example.com",
            "nationality": "USA",
            "location": "NY",
            "timezone": "America/New_York"
        }
        self.mock_storage_adapter.retrieve_by_attributes.return_value = [mock_doc]
        
        result = self.repository.find_by_email("test@example.com")
        
        self.mock_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")
        self.assertEqual(result.name, "Test User")
        self.assertEqual(result.timezone, "America/New_York")

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

    def test_update_user(self):
        updated_user = User(
            id="user_id",
            name="Updated Name",
            email="updated@example.com",
            nationality="Canada",
            timezone="Europe/London"
        )
        
        result = self.repository.update(updated_user)
        
        self.mock_storage_adapter.store.assert_called_once()
        call_args = self.mock_storage_adapter.store.call_args
        self.assertEqual(call_args[0][0], self.collection)
        self.assertEqual(result, updated_user)
        self.assertEqual(result.name, "Updated Name")
        self.assertEqual(result.email, "updated@example.com")
        self.assertEqual(result.nationality, "Canada")
        self.assertEqual(result.timezone, "Europe/London")
    
    def test_user_with_timezone(self):
        timezone = "Asia/Tokyo"
        user = User(
            id="tz_user_id",
            name="Timezone User",
            email="tz@example.com",
            timezone=timezone
        )
        
        result = self.repository.create(user)
        self.assertEqual(result.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)

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