import unittest
from unittest.mock import Mock
from analogai.foundation.core.observables.notion_observable_service import NotionObservableService, NotionObserver
from analogai.foundation.modules.notion.notion import Notion


class TestNotionObserver(NotionObserver):
    def __init__(self):
        self.created_notions = []
    
    def on_notion_created(self, notion):
        self.created_notions.append(notion)


class TestNotionObservableService(unittest.TestCase):
    def setUp(self):
        self.service = NotionObservableService()
        self.notion = Notion(user_id="user1", agent_id="agent1", caption="test", id="notion1")
    
    def test_add_observer(self):
        observer = Mock(spec=NotionObserver)
        self.service.add_observer(observer)
        
        self.assertIn(observer, self.service._observers)
    
    def test_remove_observer(self):
        observer = Mock(spec=NotionObserver)
        self.service.add_observer(observer)
        self.service.remove_observer(observer)
        
        self.assertNotIn(observer, self.service._observers)
    
    def test_notify_notion_created_calls_observer(self):
        observer = Mock(spec=NotionObserver)
        observer.on_notion_created = Mock()
        self.service.add_observer(observer)
        
        self.service.notify_notion_created(self.notion)
        
        observer.on_notion_created.assert_called_once_with(self.notion)
    
    def test_notify_notion_created_calls_all_observers(self):
        observer1 = Mock(spec=NotionObserver)
        observer1.on_notion_created = Mock()
        observer2 = Mock(spec=NotionObserver)
        observer2.on_notion_created = Mock()
        
        self.service.add_observer(observer1)
        self.service.add_observer(observer2)
        
        self.service.notify_notion_created(self.notion)
        
        observer1.on_notion_created.assert_called_once_with(self.notion)
        observer2.on_notion_created.assert_called_once_with(self.notion)
    
    def test_notify_notion_created_handles_missing_method_gracefully(self):
        observer = Mock()
        del observer.on_notion_created
        
        self.service.add_observer(observer)
        
        self.service.notify_notion_created(self.notion)
    
    def test_notify_notion_created_handles_missing_attribute_gracefully(self):
        observer = Mock()
        del observer.on_notion_created
        
        observer2 = Mock(spec=NotionObserver)
        observer2.on_notion_created = Mock()
        
        self.service.add_observer(observer)
        self.service.add_observer(observer2)
        
        self.service.notify_notion_created(self.notion)
        
        observer2.on_notion_created.assert_called_once_with(self.notion)
    
    def test_notify_notion_created_with_concrete_observer(self):
        observer = TestNotionObserver()
        self.service.add_observer(observer)
        
        self.service.notify_notion_created(self.notion)
        
        self.assertEqual(len(observer.created_notions), 1)
        self.assertEqual(observer.created_notions[0], self.notion)
    
    def test_notify_notion_created_with_multiple_notions(self):
        observer = TestNotionObserver()
        self.service.add_observer(observer)
        
        notion1 = Notion(user_id="user1", agent_id="agent1", caption="test1", id="notion1")
        notion2 = Notion(user_id="user2", agent_id="agent2", caption="test2", id="notion2")
        
        self.service.notify_notion_created(notion1)
        self.service.notify_notion_created(notion2)
        
        self.assertEqual(len(observer.created_notions), 2)
        self.assertEqual(observer.created_notions[0], notion1)
        self.assertEqual(observer.created_notions[1], notion2)


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