#       Licensed to the Apache Software Foundation (ASF) under one
#       or more contributor license agreements.  See the NOTICE file
#       distributed with this work for additional information
#       regarding copyright ownership.  The ASF licenses this file
#       to you under the Apache License, Version 2.0 (the
#       "License"); you may not use this file except in compliance
#       with the License.  You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#       Unless required by applicable law or agreed to in writing,
#       software distributed under the License is distributed on an
#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#       KIND, either express or implied.  See the License for the
#       specific language governing permissions and limitations
#       under the License.
from __future__ import annotations
import bson
import logging
import typing

from ming.odm import Mapper
from tg import tmpl_context as c

from activitystream import ActivityDirector
from activitystream.base import NodeBase, ActivityObjectBase
from activitystream.managers import Aggregator as BaseAggregator

from allura.lib import security
from allura.tasks.activity_tasks import create_timelines

if typing.TYPE_CHECKING:
    import allura.model as M
    from activitystream.storage.mingstorage import Activity

log = logging.getLogger(__name__)


class Director(ActivityDirector):

    """Overrides the default ActivityDirector to kick off background
    timeline aggregations after an activity is created.

    """

    def create_activity(self, actor: ActivityNode, verb: str, obj: ActivityObject, target=None,
                        related_nodes=None, tags=None):
        if c.project and c.project.notifications_disabled:
            return

        from allura.model.project import Project
        super().create_activity(actor, verb, obj,
                                target=target,
                                related_nodes=related_nodes,
                                tags=tags)
        # aggregate actor and follower's timelines
        if actor.node_id:
            create_timelines.post(actor.node_id)
        # aggregate project and follower's timelines
        for node in [obj, target] + (related_nodes or []):
            if isinstance(node, Project):
                create_timelines.post(node.node_id)


class Aggregator(BaseAggregator):
    pass


class ActivityNode(NodeBase):

    @property
    def node_id(self):
        return f"{self.__class__.__name__}:{self._id}"


class ActivityObject(ActivityObjectBase):
    '''
    Allura's base activity class.
    '''

    @property
    def activity_name(self):
        """Override this for each Artifact type."""
        return f"{self.__mongometa__.name.capitalize()} {self._id}"

    @property
    def activity_url(self):
        return self.url()

    @property
    def activity_extras(self):
        """Return a BSON-serializable dict of extra stuff to store on the
        activity.
        """
        return {"allura_id": self.allura_id}

    @property
    def allura_id(self):
        """Return a string which uniquely identifies this object and which can
        be used to retrieve the object from mongo.
        """
        return f"{self.__class__.__name__}:{self._id}"

    def has_activity_access(self, perm, user, activity):
        """Return True if user has perm access to this object, otherwise
        return False.
        """
        if self.project is None or getattr(self, 'deleted', False):
            return False
        return security.has_access(self, perm, user, self.project)


class TransientActor(NodeBase, ActivityObjectBase):
    """An activity actor which is not a persistent Node in the network.

    """
    def __init__(self, activity_name):
        NodeBase.__init__(self)
        ActivityObjectBase.__init__(self)
        self.activity_name = activity_name


def get_allura_id(activity_object_dict):
    extras_dict = activity_object_dict.activity_extras
    if not extras_dict:
        return None
    allura_id = extras_dict.get('allura_id')
    if not allura_id:
        return None
    return allura_id


def get_activity_object(activity_object_dict):
    """Given a BSON-serialized activity object (e.g. activity.obj dict in a
    timeline), return the corresponding :class:`ActivityObject`.

    """
    allura_id = get_allura_id(activity_object_dict)
    if not allura_id:
        return None
    return get_object_from_id(allura_id)


def get_object_from_id(node_id):
    classname, _id = node_id.split(':', 1)
    cls = Mapper.by_classname(classname).mapped_class
    try:
        _id = bson.ObjectId(_id)
    except bson.errors.InvalidId:
        pass
    obj = cls.query.get(_id=_id)
    return obj


def perm_check(user: M.User):
    """
    Return a function that returns True if ``user`` has 'read' access to a given activity,
    otherwise returns False.
    """
    def _perm_check(activity: Activity):
        if not get_allura_id(activity.obj):
            # include activity records that do not have an allura object
            return True
        obj = get_activity_object(activity.obj)
        if obj is None:
            # Do not include if there's supposed to be an allura object, but it's missing
            return False
        # Finally, if there's an allura object, perform a permission check
        return obj.has_activity_access('read', user, activity)
    return _perm_check
