""" SlackAction

  This action posts the status change to a Slack channel
  It uses Slack Webhooks.
  Also compatible with Mattermost, which is an open source alternative to Slack.
  To create a webhook URL refer the following :

  * Slack : https://api.slack.com/incoming-webhooks
  * Mattermost : https://docs.mattermost.com/developer/webhooks-incoming.html

  Add the webhook URL to dirac.cfg at Operations/[]/ResourceStatus/Config/Slack

  example:

    Operations/
      Defaults/
        ResourceStatus/
          Config/
            Slack = https://hooks.slack.com/services/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
            Mattermost = https://mattermost.web.cern.ch/hooks/axy94k3m1pg5xeyaw3qqb3x8bo

  Even if using Mattermost,the URL is still to be placed at
  Operations/[]/ResourceStatus/Config/Slack and not Operations/[]/ResourceStatus/Config/Mattermost

"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

__RCSID__ = "$Id$"

import json
import requests
import six

from DIRAC import S_ERROR, S_OK
from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
from DIRAC.ResourceStatusSystem.PolicySystem.Actions.BaseAction import BaseAction
from DIRAC.Core.Utilities.SiteSEMapping import getSitesForSE
from DIRAC.ConfigurationSystem.Client.Helpers.Resources import getCESiteMapping


class SlackAction(BaseAction):
    """
    Action that sends a brief Slack Message.
    """

    def __init__(self, name, decisionParams, enforcementResult, singlePolicyResults, clients=None, url=None):

        super(SlackAction, self).__init__(name, decisionParams, enforcementResult, singlePolicyResults, clients)
        if url is not None:
            self.url = url
        else:
            self.url = Operations().getValue("ResourceStatus/Config/Slack")

    def run(self):
        """
        Checks it has the parameters it needs and tries to send an sms to the users
        that apply.
        """

        if self.url is None:
            return S_ERROR("Slack URL not set")

        # Minor security checks
        element = self.decisionParams["element"]
        if element is None:
            return S_ERROR("element should not be None")

        name = self.decisionParams["name"]
        if name is None:
            return S_ERROR("name should not be None")

        statusType = self.decisionParams["statusType"]
        if statusType is None:
            return S_ERROR("statusType should not be None")

        previousStatus = self.decisionParams["status"]
        if previousStatus is None:
            return S_ERROR("status should not be None")

        status = self.enforcementResult["Status"]
        if status is None:
            return S_ERROR("status should not be None")

        reason = self.enforcementResult["Reason"]
        if reason is None:
            return S_ERROR("reason should not be None")

        if self.decisionParams["element"] == "Site":
            siteName = self.decisionParams["name"]
        else:
            elementType = self.decisionParams["elementType"]

            if elementType == "StorageElement":
                siteName = getSitesForSE(name)
            elif elementType == "ComputingElement":
                res = getCESiteMapping(name)
                if not res["OK"]:
                    self.log.error("Failure getting Site2CE mapping", res["Message"])
                    siteName = "ERROR"
                else:
                    siteName = res
            else:
                siteName = {"OK": True, "Value": "Unassigned"}

            if not siteName["OK"]:
                self.log.error("Resource %s does not exist at any site: %s" % (name, siteName["Message"]))
                siteName = "Unassigned Resources"
            elif not siteName["Value"]:
                siteName = "Unassigned Resources"
            else:
                siteName = (
                    siteName["Value"] if isinstance(siteName["Value"], six.string_types) else siteName["Value"][0]
                )

        message = "*{name}* _{statusType}_ --> _{status}_ \n{reason}".format(
            name=name, statusType=statusType, status=status, reason=reason
        )
        return self.sendSlackMessage(message)

    def sendSlackMessage(self, message):
        """
        Sends a slack message to self.url

        :param str message: text message to send
        """

        payload = {"text": message}
        response = requests.post(self.url, data=json.dumps(payload), headers={"Content-Type": "application/json"})
        response.raise_for_status()
        return S_OK()
