""" VOMSService class encapsulates connection to the VOMS service for a given VO
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

__RCSID__ = "$Id$"

import requests

from DIRAC import gConfig, gLogger, S_OK, S_ERROR
from DIRAC.Core.Utilities import DErrno
from DIRAC.Core.Security.Locations import getProxyLocation, getCAsLocation
from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOOption
from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO


class VOMSService(object):
    def __init__(self, vo=None):
        """c'tor

        :param str vo: name of the virtual organization (community)
        """

        if vo is None:
            vo = getVO()
        if not vo:
            raise Exception("No VO name given")

        self.vo = vo
        self.vomsVO = getVOOption(vo, "VOMSName")
        if not self.vomsVO:
            raise Exception("Can not get VOMS name for VO %s" % vo)

        self.urls = []
        result = gConfig.getSections("/Registry/VO/%s/VOMSServers" % self.vo)
        if result["OK"]:
            for server in result["Value"]:
                gLogger.verbose("Adding 'https://%s:8443/voms/%s/apiv2/users'" % (server, self.vomsVO))
                self.urls.append("https://%s:8443/voms/%s/apiv2/users" % (server, self.vomsVO))
        else:
            gLogger.error("Section '/Registry/VO/%s/VOMSServers' not found" % self.vo)

        self.userDict = None

    def attGetUserNickname(self, dn, _ca=None):
        """Get user nickname for a given DN if any

        :param str dn: user DN
        :param str _ca: CA, kept for backward compatibility
        :return:  S_OK with Value: nickname
        """

        if self.userDict is None:
            result = self.getUsers()
            if not result["OK"]:
                return result

        uDict = self.userDict.get(dn)
        if not uDict:
            return S_ERROR(DErrno.EVOMS, "No nickname defined")
        nickname = uDict.get("nickname")
        if not nickname:
            return S_ERROR(DErrno.EVOMS, "No nickname defined")
        return S_OK(nickname)

    def getUsers(self):
        """Get all the users of the VOMS VO with their detailed information

        :return: user dictionary keyed by the user DN
        """

        if not self.urls:
            return S_ERROR(DErrno.ENOAUTH, "No VOMS server defined")

        userProxy = getProxyLocation()
        caPath = getCAsLocation()
        rawUserList = []
        result = None
        for url in self.urls:
            rawUserList = []
            startIndex = 0
            result = None
            error = None
            urlDone = False
            while not urlDone:
                try:
                    result = requests.get(
                        url,
                        headers={"X-VOMS-CSRF-GUARD": "y"},
                        cert=userProxy,
                        verify=caPath,
                        params={"startIndex": str(startIndex), "pageSize": "100"},
                    )
                except requests.ConnectionError as exc:
                    error = "%s:%s" % (url, repr(exc))
                    urlDone = True
                    continue

                if result.status_code != 200:
                    error = "Failed to contact the VOMS server: %s" % result.text
                    urlDone = True
                    continue

                userList = result.json()["result"]
                rawUserList.extend(userList)
                if len(userList) < 100:
                    urlDone = True
                startIndex += 100

            # This URL did not work, try another one
            if error:
                continue
            else:
                break

        if error:
            return S_ERROR(DErrno.ENOAUTH, "Failed to contact the VOMS server: %s" % error)

        # We have got the user info, reformat it
        resultDict = {}
        for user in rawUserList:
            for cert in user["certificates"]:
                dn = cert["subjectString"]
                resultDict[dn] = user
                resultDict[dn]["CA"] = cert["issuerString"]
                resultDict[dn]["certSuspended"] = cert.get("suspended")
                resultDict[dn]["suspended"] = user.get("suspended")
                resultDict[dn]["mail"] = user.get("emailAddress")
                resultDict[dn]["Roles"] = user.get("fqans")
                attributes = user.get("attributes")
                if attributes:
                    for attribute in user.get("attributes", []):
                        if attribute.get("name") == "nickname":
                            resultDict[dn]["nickname"] = attribute.get("value")

        self.userDict = dict(resultDict)
        return S_OK(resultDict)
