from datetime import datetime
from DateTime import DateTime
from persistent import Persistent
from plone import api
from plone.protect.interfaces import IDisableCSRFProtection
from ploneintranet import api as pi_api
from ploneintranet.notifications.interfaces import IMessage
from zope.globalrequest import getRequest
from zope.i18n import translate
from zope.interface import alsoProvides
from zope.interface import implementer

import pickle


@implementer(IMessage)
class Message(Persistent):
    actors = None
    predicate = ""
    obj = {}
    recipient = None

    def __init__(self, actors, predicate, obj):
        self.actors = actors

        # make sure actors is a list
        if not isinstance(self.actors, list):
            self.actors = [self.actors]

        self.predicate = predicate

        self.obj = obj.copy()

        if "url" not in obj:
            self.obj["url"] = ""
        if "message_last_modification_date" not in obj:
            self.obj["message_last_modification_date"] = datetime.utcnow()
        if "read" not in obj:
            self.obj["read"] = False

    def mark_as_read(self, now=None):
        if self.obj["read"]:
            # already read
            return
        if now is None:
            now = datetime.utcnow()
        self.obj["read"] = now
        self._p_changed = 1
        request = getRequest()
        if request is not None:
            alsoProvides(request, IDisableCSRFProtection)
        if self.recipient:
            pi_api.push.notification_counter_changed_for(self.recipient)

    def marked_read_at(self):
        return self.obj["read"]

    @property
    def date(self):
        modified = self.obj.get("message_last_modification_date", None)
        if hasattr(modified, "isoformat"):
            modified = DateTime(modified.isoformat())
        if modified:
            to_local = api.portal.get_tool("translation_service").toLocalizedTime
            return to_local(modified, long_format=True)

    def is_unread(self):
        return self.marked_read_at() is False

    def update_object(self, obj):
        self.obj = obj
        self.obj["message_last_modification_date"] = datetime.utcnow()
        self._p_changed = 1

    def update_actors(self, added=[], removed=[]):
        for add in added:
            if add not in self.actors:
                self.actors.append(add)
                self._p_changed = 1
        for remove in removed:
            if remove in self.actors:
                self.actors.remove(remove)
                self._p_changed = 1

    def clone(self):
        return self.__class__(
            actors=pickle.loads(pickle.dumps(self.actors)),
            predicate=self.predicate,
            obj=pickle.loads(pickle.dumps(self.obj)),
        )

    @property
    def verb(self):
        lang = api.portal.get_current_language()
        label = translate(
            f"label_verb_{self.predicate}",
            "ploneintranet",
            target_language=lang,
        )
        return label

    def absolute_url(self):
        """The URL should be stored as relative one (even this is not always the case)
        this method will try to make it absolute
        """
        if self.is_unread():
            return f"{api.portal.get().absolute_url()}/@@notification/{self.id}"

        url = self.obj.get("url", "")
        if ":/" in url:
            # URL already has a scheme, do nothing
            return url
        portal = api.portal.get()
        plone_relative_url = portal.absolute_url(1)
        if url.startswith(plone_relative_url + "/"):
            url = url[len(plone_relative_url) :]
        url = url.lstrip("/")
        url = f"{portal.absolute_url()}/{url}"
        return url
