import unittest
from unittest.mock import MagicMock
from analogai.foundation.modules.user.user_service import UserService
from analogai.foundation.modules.user.user_repository import UserRepository
from analogai.foundation.modules.user.user import User


test_user_id = "test_user_id"
test_authority = 1.0


class TestUserService(unittest.TestCase):
    def setUp(self):
        self.mock_user_repository = MagicMock(spec=UserRepository)
        self.test_user = User(id=test_user_id, name="Test User", email="test@example.com")
        self.user_service = UserService(self.mock_user_repository)

    def test_find_user_success(self):
        self.mock_user_repository.find_by_id.return_value = self.test_user
        result = self.user_service.find(test_user_id)
        self.mock_user_repository.find_by_id.assert_called_once_with(test_user_id)
        self.assertEqual(result, self.test_user)

    def test_find_user_not_found(self):
        self.mock_user_repository.find_by_id.return_value = None
        user = self.user_service.find(test_user_id)
        self.assertIsNone(user)
        self.mock_user_repository.find_by_id.assert_called_once_with(test_user_id)

    def test_find_by_email_success(self):
        test_email = "test@example.com"
        self.mock_user_repository.find_by_email.return_value = self.test_user
        result = self.user_service.find_by_email(test_email)
        self.mock_user_repository.find_by_email.assert_called_once_with(test_email)
        self.assertEqual(result, self.test_user)

    def test_find_by_email_not_found(self):
        test_email = "nonexistent@example.com"
        self.mock_user_repository.find_by_email.return_value = None
        user = self.user_service.find_by_email(test_email)
        self.assertIsNone(user)
        self.mock_user_repository.find_by_email.assert_called_once_with(test_email)

    def test_update_user_success(self):
        updated_user = User(id=test_user_id, name="Updated User", email="updated@example.com")
        self.mock_user_repository.find_by_id.return_value = self.test_user
        self.mock_user_repository.update.return_value = updated_user

        result = self.user_service.update(updated_user)

        self.mock_user_repository.find_by_id.assert_called_once_with(test_user_id)
        self.mock_user_repository.update.assert_called_once_with(updated_user)
        self.assertEqual(result, updated_user)

    def test_update_user_not_found(self):
        updated_user = User(id="nonexistent_id", name="Updated User", email="updated@example.com")
        self.mock_user_repository.find_by_id.return_value = None

        with self.assertRaises(ValueError) as context:
            self.user_service.update(updated_user)

        self.assertEqual(str(context.exception), f"User with ID {updated_user.id} not found")
        self.mock_user_repository.find_by_id.assert_called_once_with(updated_user.id)
        self.mock_user_repository.update.assert_not_called()

    def test_create_user_success(self):
        new_user = User(id=test_user_id, name="New User", email="new@example.com")
        self.mock_user_repository.find_by_email.return_value = None
        self.mock_user_repository.create.return_value = new_user

        result = self.user_service.create(test_user_id, "New User", "new@example.com")

        self.mock_user_repository.find_by_email.assert_called_once_with("new@example.com")
        self.mock_user_repository.create.assert_called_once()
        self.assertEqual(result, new_user)

    def test_create_user_with_duplicate_email_raises_error(self):
        existing_user = User(id="existing_id", name="Existing User", email="duplicate@example.com")
        self.mock_user_repository.find_by_email.return_value = existing_user

        with self.assertRaises(ValueError) as context:
            self.user_service.create(test_user_id, "New User", "duplicate@example.com")

        self.assertIn("already exists", str(context.exception))
        self.assertIn("duplicate@example.com", str(context.exception))
        self.mock_user_repository.find_by_email.assert_called_once_with("duplicate@example.com")
        self.mock_user_repository.create.assert_not_called()

    def test_create_user_with_timezone(self):
        timezone = "America/New_York"
        new_user = User(id=test_user_id, name="New User", email="new@example.com", timezone=timezone)
        self.mock_user_repository.find_by_email.return_value = None
        self.mock_user_repository.create.return_value = new_user

        result = self.user_service.create(test_user_id, "New User", "new@example.com", timezone=timezone)

        self.mock_user_repository.find_by_email.assert_called_once_with("new@example.com")
        self.mock_user_repository.create.assert_called_once()
        self.assertEqual(result, new_user)
        self.assertEqual(result.timezone, timezone)

    def test_user_has_default_timezone(self):
        new_user = User(id=test_user_id, name="New User", email="new@example.com")
        self.assertIsNotNone(new_user.timezone)

    def test_user_with_nationality_and_location(self):
        user = User(
            id=test_user_id,
            name="Test User",
            email="test@example.com",
            nationality="US",
            location="New York"
        )
        self.assertEqual(user.nationality, "US")
        self.assertEqual(user.location, "New York")

    def test_delete_user_success(self):
        self.mock_user_repository.delete.return_value = True

        result = self.user_service.delete(test_user_id)

        self.mock_user_repository.delete.assert_called_once_with(test_user_id)
        self.assertTrue(result)


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