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

__RCSID__ = "$Id$"

import six
import os

from DIRAC import gLogger
from DIRAC.Core.Security import Locations
from DIRAC.Core.Utilities.ReturnValues import S_ERROR, S_OK
from DIRAC.Core.Security.X509Chain import X509Chain  # pylint: disable=import-error
from DIRAC.Core.Security.X509Certificate import X509Certificate  # pylint: disable=import-error


# Eventhough SSLTransport is not used in this file, it is imported in other module from there,
# so do not remove these imports !
from DIRAC.Core.DISET.private.Transports.M2SSLTransport import SSLTransport


def delegate(delegationRequest, kwargs):
    """
    Check delegate!
    """
    if kwargs.get("useCertificates"):
        chain = X509Chain()
        certTuple = Locations.getHostCertificateAndKeyLocation()
        chain.loadChainFromFile(certTuple[0])
        chain.loadKeyFromFile(certTuple[1])
    elif "proxyObject" in kwargs:
        chain = kwargs["proxyObject"]
    else:
        if "proxyLocation" in kwargs:
            procLoc = kwargs["proxyLocation"]
        else:
            procLoc = Locations.getProxyLocation()
        chain = X509Chain()
        chain.loadChainFromFile(procLoc)
        chain.loadKeyFromFile(procLoc)
    return chain.generateChainFromRequestString(delegationRequest)


def checkSanity(urlTuple, kwargs):
    """
    Check that all ssl environment is ok
    """
    useCerts = False
    certFile = ""
    if "useCertificates" in kwargs and kwargs["useCertificates"]:
        certTuple = Locations.getHostCertificateAndKeyLocation()
        if not certTuple:
            gLogger.error("No cert/key found! ")
            return S_ERROR("No cert/key found! ")
        certFile = certTuple[0]
        useCerts = True
    elif "proxyString" in kwargs:
        if not isinstance(kwargs["proxyString"], six.string_types if six.PY2 else bytes):
            gLogger.error("proxyString parameter is not a valid type", str(type(kwargs["proxyString"])))
            return S_ERROR("proxyString parameter is not a valid type")
    else:
        if "proxyLocation" in kwargs:
            certFile = kwargs["proxyLocation"]
        else:
            certFile = Locations.getProxyLocation()
        if not certFile:
            gLogger.error("No proxy found")
            return S_ERROR("No proxy found")
        elif not os.path.isfile(certFile):
            gLogger.error("Proxy file does not exist", certFile)
            return S_ERROR("%s proxy file does not exist" % certFile)

    # For certs always check CA's. For clients skipServerIdentityCheck
    if "skipCACheck" not in kwargs or not kwargs["skipCACheck"]:
        if not Locations.getCAsLocation():
            gLogger.error("No CAs found!")
            return S_ERROR("No CAs found!")

    if "proxyString" in kwargs:
        certObj = X509Chain()
        retVal = certObj.loadChainFromString(kwargs["proxyString"])
        if not retVal["OK"]:
            gLogger.error("Can't load proxy string")
            return S_ERROR("Can't load proxy string")
    else:
        if useCerts:
            certObj = X509Certificate()
            certObj.loadFromFile(certFile)
        else:
            certObj = X509Chain()
            certObj.loadChainFromFile(certFile)

    retVal = certObj.hasExpired()
    if not retVal["OK"]:
        gLogger.error("Can't verify proxy or certificate file", "%s:%s" % (certFile, retVal["Message"]))
        return S_ERROR("Can't verify file %s:%s" % (certFile, retVal["Message"]))
    else:
        if retVal["Value"]:
            notAfter = certObj.getNotAfterDate()
            if notAfter["OK"]:
                notAfter = notAfter["Value"]
            else:
                notAfter = "unknown"
            gLogger.error("PEM file has expired", "%s is not valid after %s" % (certFile, notAfter))
            return S_ERROR("PEM file %s has expired, not valid after %s" % (certFile, notAfter))

    idDict = {}
    retVal = certObj.getDIRACGroup(ignoreDefault=True)
    if retVal["OK"] and retVal["Value"] is not False:
        idDict["group"] = retVal["Value"]
    if useCerts:
        idDict["DN"] = certObj.getSubjectDN()["Value"]
    else:
        idDict["DN"] = certObj.getIssuerCert()["Value"].getSubjectDN()["Value"]

    return S_OK(idDict)
