""" This is a test of the DIRACCAProxyProvider
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=invalid-name,wrong-import-position,protected-access
import os
import re
import sys
import shutil
# TODO: This should be modernised to use subprocess(32)
try:
  import commands
except ImportError:
  # Python 3's subprocess module contains a compatibility layer
  import subprocess as commands
import unittest
import tempfile

import pytest

from DIRAC import gLogger, rootPath
from DIRAC.Core.Security.X509Chain import X509Chain  # pylint: disable=import-error
from DIRAC.Resources.ProxyProvider.DIRACCAProxyProvider import DIRACCAProxyProvider


certsPath = os.path.join(rootPath, 'DIRAC/Core/Security/test/certs')

testCAPath = os.path.join(tempfile.mkdtemp(dir='/tmp'), 'ca')
testCAConfigFile = os.path.join(testCAPath, 'openssl_config_ca.cnf')

diracCADict = {'ProviderType': 'DIRACCA',
               'CertFile': os.path.join(certsPath, 'ca/ca.cert.pem'),
               'KeyFile': os.path.join(certsPath, 'ca/ca.key.pem'),
               'Supplied': ['O', 'OU', 'CN'],
               'Optional': ['emailAddress'],
               'DNOrder': ['O', 'OU', 'CN', 'emailAddress'],
               'OU': 'CA',
               'C': 'DN',
               'O': 'DIRACCA',
               'ProviderName': 'DIRAC_CA'}
diracCAConf = {'ProviderType': 'DIRACCA',
               'CAConfigFile': testCAConfigFile,
               'ProviderName': 'DIRAC_CA_CFG'}


class DIRACCAProviderTestCase(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.failed = False

    shutil.copytree(os.path.join(certsPath, 'ca'), testCAPath)

    # Parse
    lines = []
    with open(testCAConfigFile, "r") as caCFG:
      for line in caCFG:
        if re.findall('=', re.sub(r'#.*', '', line)):
          # Ignore comments
          field = re.sub(r'#.*', '', line).replace(' ', '').rstrip().split('=')[0]
          # Put the right dir
          line = 'dir = %s #PUT THE RIGHT DIR HERE!\n' % (testCAPath) if field == 'dir' else line
        lines.append(line)
    # Write modified conf. file
    with open(testCAConfigFile, "w") as caCFG:
      caCFG.writelines(lines)

    # Result
    status, output = commands.getstatusoutput('ls -al %s' % testCAPath)
    if status:
      gLogger.error(output)
      exit()
    gLogger.debug('Test path:\n', output)

  def setUp(self):
    gLogger.debug('\n')
    if self.failed:
       self.fail(self.failed)

  def tearDown(self):
    pass

  @classmethod
  def tearDownClass(cls):
    if os.path.exists(testCAPath):
      shutil.rmtree(testCAPath)


class testDIRACCAProvider(DIRACCAProviderTestCase):

  @pytest.mark.slow
  def test_getProxy(self):
    """ Test 'getProxy' - try to get proxies for different users and check it
    """
    def check(proxyStr, proxyProvider, name):
      """ Check proxy

          :param str proxyStr: proxy as string
          :param str proxyProvider: proxy provider name
          :param str name: proxy name
      """
      proxyFile = os.path.join(testCAPath, proxyProvider + name.replace(' ', '') + '.pem')
      gLogger.info('Check proxy..')
      chain = X509Chain()
      result = chain.loadProxyFromString(proxyStr)
      self.assertTrue(result['OK'], '\n' + result.get('Message', 'Error message is absent.'))
      for result in [chain.getRemainingSecs(),
                     chain.getIssuerCert(),
                     chain.getPKeyObj(),
                     chain.getCertList(),
                     chain.getNumCertsInChain(),
                     chain.generateProxyToString(3600),
                     chain.generateProxyToFile(proxyFile, 3600),
                     chain.isProxy(),
                     chain.isLimitedProxy(),
                     chain.isValidProxy(),
                     chain.isVOMS(),
                     chain.isRFC()]:
        self.assertTrue(result['OK'], '\n' + result.get('Message', 'Error message is absent.'))

    for proxyProvider, log in [(diracCADict, 'configuring only in DIRAC CFG'),
                               (diracCAConf, 'read configuration file')]:
      gLogger.info('\n* Try proxy provider that %s..' % log)
      ca = DIRACCAProxyProvider()
      result = ca.setParameters(proxyProvider)
      self.assertTrue(result['OK'], '\n' + result.get('Message', 'Error message is absent.'))

      gLogger.info('* Get proxy using FullName and Email of user..')
      for name, email, res in [('MrUser', 'good@mail.com', True),
                               ('MrUser_1', 'good_1@mail.com', True),
                               (False, 'good@mail.com', False),
                               ('MrUser', False, True)]:
        gLogger.info('\nFullName: %s' % name or 'absent', 'Email: %s..' % email or 'absent')
        # Create user DN
        result = ca.generateDN(FullName=name, Email=email)
        text = 'Must be ended %s%s' % ('successful' if res else 'with error',
                                       ': %s' % result.get('Message', 'Error message is absent.'))
        self.assertEqual(result['OK'], res, text)
        if not res:
          gLogger.info('Msg: %s' % (result['Message']))
        else:
          userDN = result['Value']
          gLogger.info('Created DN:', userDN)

          result = ca.getProxy(userDN)
          text = 'Must be ended %s%s' % ('successful' if res else 'with error',
                                         ': %s' % result.get('Message', 'Error message is absent.'))
          self.assertEqual(result['OK'], res, text)
          if not res:
            gLogger.info('Msg: %s' % (result['Message']))
          else:
            check(result['Value'], proxyProvider['ProviderName'], name)

      gLogger.info('\n* Get proxy using user DN..')
      for dn, name, res in [('/O=DIRAC/OU=DIRAC CA/CN=user_3/emailAddress=some@mail.org', 'user_3', True),
                            ('/O=Dirac/OU=DIRAC CA/CN=user/emailAddress=some@mail.org', 'user', True),
                            ('/O=Dirac/OU=Without supplied field/emailAddress=some@mail.org', 'not_suplied', False),
                            ('/O=Dirac/OU=DIRAC CA/CN=without email', 'no_email', True),
                            ('/some=bad/DN=', 'badDN', False),
                            ('/BF=Bad Field/O=IN/CN=DN', 'badField', False),
                            (False, 'absent', False)]:
        gLogger.info('\nDN:', dn or 'absent')
        try:
          result = ca.getProxy(dn)
        except Exception as e:
          result['Message'] = str(e)
          self.assertFalse(res, e)
        text = 'Must be ended %s%s' % ('successful' if res else 'with error',
                                       ': %s' % result.get('Message', 'Error message is absent.'))
        self.assertEqual(result['OK'], res, text)
        if not res:
          gLogger.info('Msg: %s' % (result['Message']))
        else:
          check(result['Value'], proxyProvider['ProviderName'], name)


if __name__ == '__main__':
  suite = unittest.defaultTestLoader.loadTestsFromTestCase(DIRACCAProviderTestCase)
  suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(testDIRACCAProvider))
  testResult = unittest.TextTestRunner(verbosity=2).run(suite)
  sys.exit(not testResult.wasSuccessful())
