""" Utility class for dealing with MyProxy
"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
__RCSID__ = "$Id$"

import re
from DIRAC import gLogger, S_OK, S_ERROR
from DIRAC.Core.Utilities.Subprocess import shellCall
from DIRAC.Core.Utilities import List
from DIRAC.Core.Security.ProxyFile import multiProxyArgument, deleteMultiProxy
from DIRAC.Core.Security.X509Chain import X509Chain  # pylint: disable=import-error
from DIRAC.Core.Security.BaseSecurity import BaseSecurity


class MyProxy(BaseSecurity):

  def uploadProxy(self, proxy=False, useDNAsUserName=False):
    """
    Upload a proxy to myproxy service.
      proxy param can be:
        : Default -> use current proxy
        : string -> upload file specified as proxy
        : X509Chain -> use chain
    """
    retVal = multiProxyArgument(proxy)
    if not retVal['OK']:
      return retVal
    proxyDict = retVal['Value']
    chain = proxyDict['chain']
    proxyLocation = proxyDict['file']

    timeLeft = int(chain.getRemainingSecs()['Value'] / 3600)

    cmdArgs = ['-n']
    cmdArgs.append('-s "%s"' % self._secServer)
    cmdArgs.append('-c "%s"' % (timeLeft - 1))
    cmdArgs.append('-t "%s"' % self._secMaxProxyHours)
    cmdArgs.append('-C "%s"' % proxyLocation)
    cmdArgs.append('-y "%s"' % proxyLocation)
    if useDNAsUserName:
      cmdArgs.append('-d')
    else:
      retVal = self._getUsername(chain)
      if not retVal['OK']:
        deleteMultiProxy(proxyDict)
        return retVal
      mpUsername = retVal['Value']
      cmdArgs.append('-l "%s"' % mpUsername)

    mpEnv = self._getExternalCmdEnvironment()
    # Hack to upload properly
    mpEnv['GT_PROXY_MODE'] = 'old'

    cmd = "myproxy-init %s" % " ".join(cmdArgs)
    result = shellCall(self._secCmdTimeout, cmd, env=mpEnv)

    deleteMultiProxy(proxyDict)

    if not result['OK']:
      errMsg = "Call to myproxy-init failed: %s" % retVal['Message']
      return S_ERROR(errMsg)

    status, _, error = result['Value']

    # Clean-up files
    if status:
      errMsg = "Call to myproxy-init failed"
      extErrMsg = 'Command: %s; StdOut: %s; StdErr: %s' % (cmd, result, error)
      return S_ERROR("%s %s" % (errMsg, extErrMsg))

    return S_OK()

  def getDelegatedProxy(self, proxyChain, lifeTime=604800, useDNAsUserName=False):
    """
      Get delegated proxy from MyProxy server
      return S_OK( X509Chain ) / S_ERROR
    """
    # TODO: Set the proxy coming in proxyString to be the proxy to use

    # Get myproxy username diracgroup:diracuser
    retVal = multiProxyArgument(proxyChain)
    if not retVal['OK']:
      return retVal
    proxyDict = retVal['Value']
    chain = proxyDict['chain']
    proxyLocation = proxyDict['file']

    retVal = self._generateTemporalFile()
    if not retVal['OK']:
      deleteMultiProxy(proxyDict)
      return retVal
    newProxyLocation = retVal['Value']

    # myproxy-get-delegation works only with environment variables
    cmdEnv = self._getExternalCmdEnvironment()
    if self._secRunningFromTrustedHost:
      cmdEnv['X509_USER_CERT'] = self._secCertLoc
      cmdEnv['X509_USER_KEY'] = self._secKeyLoc
      if 'X509_USER_PROXY' in cmdEnv:
        del cmdEnv['X509_USER_PROXY']
    else:
      cmdEnv['X509_USER_PROXY'] = proxyLocation

    cmdArgs = []
    cmdArgs.append("-s '%s'" % self._secServer)
    cmdArgs.append("-t '%s'" % (int(lifeTime / 3600)))
    cmdArgs.append("-a '%s'" % proxyLocation)
    cmdArgs.append("-o '%s'" % newProxyLocation)
    if useDNAsUserName:
      cmdArgs.append('-d')
    else:
      retVal = self._getUsername(chain)
      if not retVal['OK']:
        deleteMultiProxy(proxyDict)
        return retVal
      mpUsername = retVal['Value']
      cmdArgs.append('-l "%s"' % mpUsername)

    cmd = "myproxy-logon %s" % " ".join(cmdArgs)
    gLogger.verbose("myproxy-logon command:\n%s" % cmd)

    result = shellCall(self._secCmdTimeout, cmd, env=cmdEnv)

    deleteMultiProxy(proxyDict)

    if not result['OK']:
      errMsg = "Call to myproxy-logon failed: %s" % result['Message']
      deleteMultiProxy(proxyDict)
      return S_ERROR(errMsg)

    status, _, error = result['Value']

    # Clean-up files
    if status:
      errMsg = "Call to myproxy-logon failed"
      extErrMsg = 'Command: %s; StdOut: %s; StdErr: %s' % (cmd, result, error)
      deleteMultiProxy(proxyDict)
      return S_ERROR("%s %s" % (errMsg, extErrMsg))

    chain = X509Chain()
    retVal = chain.loadProxyFromFile(newProxyLocation)
    if not retVal['OK']:
      deleteMultiProxy(proxyDict)
      return S_ERROR("myproxy-logon failed when reading delegated file: %s" % retVal['Message'])

    deleteMultiProxy(proxyDict)
    return S_OK(chain)

  def getInfo(self, proxyChain, useDNAsUserName=False):
    """
      Get info from myproxy server

      :return: S_OK( { 'username' : myproxyusername,
                     'owner' : owner DN,
                     'timeLeft' : secs left } ) / S_ERROR
    """
    # TODO: Set the proxy coming in proxyString to be the proxy to use

    # Get myproxy username diracgroup:diracuser
    retVal = multiProxyArgument(proxyChain)
    if not retVal['OK']:
      return retVal
    proxyDict = retVal['Value']
    chain = proxyDict['chain']
    proxyLocation = proxyDict['file']

    # myproxy-get-delegation works only with environment variables
    cmdEnv = self._getExternalCmdEnvironment()
    if self._secRunningFromTrustedHost:
      cmdEnv['X509_USER_CERT'] = self._secCertLoc
      cmdEnv['X509_USER_KEY'] = self._secKeyLoc
      if 'X509_USER_PROXY' in cmdEnv:
        del cmdEnv['X509_USER_PROXY']
    else:
      cmdEnv['X509_USER_PROXY'] = proxyLocation

    cmdArgs = []
    cmdArgs.append("-s '%s'" % self._secServer)
    if useDNAsUserName:
      cmdArgs.append('-d')
    else:
      retVal = self._getUsername(chain)
      if not retVal['OK']:
        deleteMultiProxy(proxyDict)
        return retVal
      mpUsername = retVal['Value']
      cmdArgs.append('-l "%s"' % mpUsername)

    cmd = "myproxy-info %s" % " ".join(cmdArgs)
    gLogger.verbose("myproxy-info command:\n%s" % cmd)

    result = shellCall(self._secCmdTimeout, cmd, env=cmdEnv)

    deleteMultiProxy(proxyDict)

    if not result['OK']:
      errMsg = "Call to myproxy-info failed: %s" % result['Message']
      deleteMultiProxy(proxyDict)
      return S_ERROR(errMsg)

    status, output, error = result['Value']

    # Clean-up files
    if status:
      errMsg = "Call to myproxy-info failed"
      extErrMsg = 'Command: %s; StdOut: %s; StdErr: %s' % (cmd, result, error)
      return S_ERROR("%s %s" % (errMsg, extErrMsg))

    infoDict = {}
    usernameRE = re.compile(r"username\s*:\s*(\S*)")
    ownerRE = re.compile(r"owner\s*:\s*(\S*)")
    timeLeftRE = re.compile(r"timeleft\s*:\s*(\S*)")
    for line in List.fromChar(output, "\n"):
      match = usernameRE.search(line)
      if match:
        infoDict['username'] = match.group(1)
      match = ownerRE.search(line)
      if match:
        infoDict['owner'] = match.group(1)
      match = timeLeftRE.search(line)
      if match:
        try:
          fields = List.fromChar(match.group(1), ":")
          fields.reverse()
          secsLeft = 0
          for iP in range(len(fields)):
            if iP == 0:
              secsLeft += int(fields[iP])
            elif iP == 1:
              secsLeft += int(fields[iP]) * 60
            elif iP == 2:
              secsLeft += int(fields[iP]) * 3600
          infoDict['timeLeft'] = secsLeft
        except Exception as x:
          print(x)

    return S_OK(infoDict)
