# -*- coding: utf-8; -*-
#
# This file is part of Superdesk.
#
# Copyright 2013, 2014 Sourcefabric z.u. and contributors.
#
# For the full copyright and license information, please see the
# AUTHORS and LICENSE files distributed with this source code, or
# at https://www.sourcefabric.org/superdesk/license

import logging
import superdesk

from flask import current_app as app
from superdesk.activity import add_activity, ACTIVITY_UPDATE
from superdesk.services import BaseService
from superdesk import get_resource_service
from superdesk.errors import SuperdeskApiError
from superdesk.notification import push_notification
from superdesk.utils import compare_preferences
from superdesk.resource import Resource


logger = logging.getLogger(__name__)


class RolesResource(Resource):
    schema = {
        "name": {"type": "string", "required": True, "nullable": False, "empty": False, "iunique": True},
        "description": {"type": "string"},
        "privileges": {
            "type": "dict",
            "schema": {},
            "allow_unknown": True,
        },
        "is_default": {"type": "boolean"},
        #: author role to be automatically set when user creates an item
        #: .. versionadded:: 1.29
        "author_role": {
            "type": "string",
            "nullable": True,
        },
        #: author role to be automatically set when user edits an item
        #: .. versionadded:: 1.29
        "editor_role": {
            "type": "string",
            "nullable": True,
        },
    }

    privileges = {"POST": "roles", "DELETE": "roles", "PATCH": "roles"}

    mongo_indexes = {
        "name_1": ([("name", 1)], {"unique": True}),
    }


class RolesService(BaseService):
    def on_update(self, updates, original):
        if updates.get("is_default"):
            # if we are updating the role that is already default that is OK
            if original.get("is_default"):
                return
            self.remove_old_default()

    def on_create(self, docs):
        for doc in docs:
            # if this new one is default need to remove the old default
            if doc.get("is_default"):
                self.remove_old_default()

    def on_delete(self, docs):
        if docs.get("is_default"):
            raise SuperdeskApiError.forbiddenError("Cannot delete the default role")
        # check if there are any users in the role
        user = get_resource_service("users").find_one(req=None, role=docs.get("_id"))
        if user:
            raise SuperdeskApiError.forbiddenError("Cannot delete the role, it still has users in it!")

    def remove_old_default(self):
        # see if there is already a default role and set it to no longer default
        role_id = self.get_default_role_id()
        # make it no longer default
        if role_id:
            role = self.find_one(req=None, is_default=True)
            get_resource_service("roles").update(role_id, {"is_default": False}, role)

    def get_default_role_id(self):
        role = self.find_one(req=None, is_default=True)
        return role.get("_id") if role is not None else None

    def on_updated(self, updates, role):
        self.__send_notification(updates, role)

    def __send_notification(self, updates, role):
        role_id = role["_id"]

        role_users = superdesk.get_resource_service("users").get_users_by_role(role_id)
        notified_users = [user["_id"] for user in role_users]

        if "privileges" in updates:
            privileges_updated = False
            added, removed, modified = compare_preferences(role.get("privileges", {}), updates["privileges"])
            if len(removed) > 0 or (1, 0) in modified.values():
                push_notification("role_privileges_revoked", updated=1, role_id=str(role_id))
                privileges_updated = True
            if len(added) > 0 or (0, 1) in modified.values():
                activity = add_activity(
                    ACTIVITY_UPDATE,
                    "role {{role}} has been granted new privileges: Please re-login.",
                    self.datasource,
                    notify=notified_users,
                    can_push_notification=False,
                    role=role.get("name"),
                )
                push_notification("activity", _dest=activity["recipients"])
                privileges_updated = True
            if privileges_updated:
                app.on_role_privileges_updated(role, role_users)

        else:
            push_notification("role", updated=1, user_id=str(role_id))
