from plone import api
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from ploneintranet import api as pi_api
from ploneintranet.microblog.interfaces import IMicroblogContext
from ploneintranet.microblog.statusupdate import StatusUpdate
from ploneintranet.microblog.testing import (
    PLONEINTRANET_MICROBLOG_CONTENTUPDATES_TESTING,
)
from unittest.mock import Mock
from zope.event import notify
from zope.interface import alsoProvides
from zope.lifecycleevent import ObjectModifiedEvent

import datetime
import unittest


class BaseContentContextTestCase(unittest.TestCase):

    layer = PLONEINTRANET_MICROBLOG_CONTENTUPDATES_TESTING

    def setUp(self):
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        self.enterContext(pi_api.events.notifications_disabled)
        pi_api.events.disable_previews()
        setRoles(self.portal, TEST_USER_ID, ["Manager"])
        self.container = api.portal.get_tool("ploneintranet_microblog")
        self.ws_id = self.portal.invokeFactory("Folder", "workspace")
        self.microblog_context = self.portal[self.ws_id]
        alsoProvides(self.microblog_context, IMicroblogContext)
        self.microblog_context.reindexObject()


class TestContentCreatedSubscriber(BaseContentContextTestCase):
    def test_content_created(self):
        doc_id = self.microblog_context.invokeFactory("Document", "mydoc")
        document = self.microblog_context[doc_id]
        updates = list(self.container.values())
        self.assertEqual(1, len(updates))
        self.assertEqual(document, updates[0].content_context)
        self.assertEqual("created", updates[0].action_verb)


class TestNewsitemSubscribers(BaseContentContextTestCase):
    @pi_api.env.system_timezone_CEST()
    def test_content_statechanged_newsitem_modified(self):
        # create so we have a news item to work with
        news_id = self.portal.invokeFactory("News Item", "mynews")
        news_item = self.portal[news_id]
        news_item.setEffectiveDate(
            datetime.datetime(2099, 1, 1, 1).astimezone(datetime.UTC)
        )
        updates = list(self.container.values())
        self.assertEqual(1, len(updates))
        self.assertEqual(news_item, updates[0].content_context)
        self.assertEqual("created", updates[0].action_verb)

        # publish initially
        api.content.transition(news_item, "publish")
        updates = list(self.container.values())
        self.assertEqual(2, len(updates))
        self.assertEqual(news_item, updates[0].content_context)
        self.assertEqual("published", updates[0].action_verb)
        self.assertEqual("DateTime('2099/01/01 00:00:00 GMT+0')", repr(updates[0].date))
        published_update_1 = updates[0]

        # modifying the effective date removes the previous "published"
        # update and issues a new one
        news_item.setEffectiveDate(
            datetime.datetime(2099, 2, 2, 1).astimezone(datetime.UTC)
        )
        modified = ObjectModifiedEvent(news_item)
        modified.descriptions = [Mock(attributes={"effective"})]
        notify(modified)
        updates = list(self.container.values())
        self.assertEqual(2, len(updates))
        self.assertEqual(news_item, updates[0].content_context)
        self.assertEqual("published", updates[0].action_verb)
        self.assertEqual("DateTime('2099/02/02 00:00:00 GMT+0')", repr(updates[0].date))
        published_update_2 = updates[0]
        self.assertNotEqual(published_update_1.id, published_update_2.id)


class TestDeleteSubscriber(BaseContentContextTestCase):
    def setUp(self):
        super().setUp()
        self.doc_id = self.microblog_context.invokeFactory("Document", "mydoc")
        self.document = self.microblog_context[self.doc_id]
        self.document.reindexObject()

    def test_delete_content_context(self):
        su1 = StatusUpdate("test")
        self.container.add(su1)
        su2 = StatusUpdate("foobar", content_context=self.document)
        self.container.add(su2)
        self.microblog_context.manage_delObjects([self.doc_id])
        self.assertEqual([su1], (list(self.container.values())))

    def test_delete_microblog_context(self):
        su1 = StatusUpdate("test")
        self.container.add(su1)
        su2 = StatusUpdate("foobar", microblog_context=self.microblog_context)
        self.container.add(su2)
        self.portal.manage_delObjects([self.ws_id])
        self.assertEqual([su1], (list(self.container.values())))

    def test_delete_microblog_context_and_content(self):
        su1 = StatusUpdate("test", content_context=self.document)
        self.container.add(su1)
        su2 = StatusUpdate("foobar", microblog_context=self.microblog_context)
        self.container.add(su2)
        self.portal.manage_delObjects([self.ws_id])
        self.assertEqual([], (list(self.container.values())))

    def test_delete_content_replies(self):
        su1 = StatusUpdate("test", content_context=self.document)
        self.container.add(su1)
        su2 = StatusUpdate("foobar", thread_id=su1.id)
        self.container.add(su2)
        self.microblog_context.manage_delObjects([self.doc_id])
        self.assertEqual([], (list(self.container.values())))
