""" Test class for plugins
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=protected-access, missing-docstring, invalid-name,
# line-too-long

# imports
import pytest
from mock import MagicMock

from DIRAC.DataManagementSystem.Client.test.mock_DM import dm_mock
from DIRAC.Resources.Catalog.test.mock_FC import fc_mock

from DIRAC import gLogger, S_OK

from DIRAC.TransformationSystem.Agent.TransformationPlugin import TransformationPlugin

paramsBase = {'AgentType': 'Automatic',
              'DerivedProduction': '0',
              'FileMask': '',
              'GroupSize': 1,
              'InheritedFrom': 0,
              'JobType': 'MCSimulation',
              'MaxNumberOfTasks': 0,
              'OutputDirectories': "['/lhcb/MC/20', '/lhcb/debug/20']",
              'OutputLFNs': "{'LogTargetPath': ['/lhcb/9.tar'], 'LogFilePath': ['/lhcb/9']}",
              'Priority': '0',
              'SizeGroup': '1',
              'Status': 'Active',
              'TransformationID': 1080,
              'Type': 'MCSimulation',
              'outputDataFileMask': 'GAUSSHIST;ALLSTREAMS.DST'}

data = {'/this/is/at.1': ['SE1'],
        '/this/is/at.2': ['SE2'],
        '/this/is/als/at.2': ['SE2'],
        '/this/is/at.12': ['SE1', 'SE2'],
        '/this/is/also/at.12': ['SE1', 'SE2'],
        '/this/is/at_123': ['SE1', 'SE2', 'SE3'],
        '/this/is/at_23': ['SE2', 'SE3'],
        '/this/is/at_4': ['SE4']}


@pytest.fixture
def setup(mocker):
  tpName = 'DIRAC.TransformationSystem.Agent.TransformationPlugin'
  tuName = 'DIRAC.TransformationSystem.Client.Utilities'
  mocker.patch(tpName + '.TransformationClient', new=MagicMock('tClient'))
  mocker.patch(tpName + '.TransformationPlugin._getSiteForSE', return_value=S_OK([]))
  mocker.patch(tuName + '.DataManager', new=dm_mock)
  mocker.patch(tuName + '.FileCatalog', new=fc_mock)
  mocker.patch(tuName + '.StorageElement', new=MagicMock('SEMock'))
  gLogger.setLevel('DEBUG')


def test__Standard_G10(setup):
  """Test StandardPlugin: no input data, active."""
  params = dict(paramsBase)
  params['GroupSize'] = 10
  pluginStandard = TransformationPlugin('Standard')
  pluginStandard.setParameters(params)
  res = pluginStandard.run()
  assert res['OK']
  # no data
  assert res['Value'] == []


def test__Standard_Data_G10(setup):
  """Test StandardPlugin: input data, active."""
  params = dict(paramsBase)
  params['GroupSize'] = 10
  pluginStandard = TransformationPlugin('Standard')
  pluginStandard.setParameters(params)
  pluginStandard.setInputData(data)
  res = pluginStandard.run()
  assert res['OK']
  # data less than 10
  assert res['Value'] == []


def test__Standard_Flush_G10(setup):
  """Test StandardPlugin: input data, flush."""
  pluginStandard = TransformationPlugin('Standard')
  params = dict(paramsBase)
  params['GroupSize'] = 10
  params['Status'] = 'Flush'
  pluginStandard.setParameters(params)
  pluginStandard.setInputData(data)
  res = pluginStandard.run()
  sortedData = [('SE1', {'/this/is/at.1'}),
                ('SE1,SE2', {'/this/is/also/at.12', '/this/is/at.12'}),
                ('SE1,SE2,SE3', {'/this/is/at_123'}),
                ('SE2', {'/this/is/als/at.2', '/this/is/at.2'}),
                ('SE2,SE3', {'/this/is/at_23'}),
                ('SE4', {'/this/is/at_4'})]
  assert res['OK']
  assert [(a, set(b)) for a, b in res['Value']] == sortedData


def test__Standard_G1(setup):
  """Test StandardPlugin: not input data, active."""
  pluginStandard = TransformationPlugin('Standard')
  pluginStandard.setParameters(paramsBase)
  res = pluginStandard.run()
  assert res['OK']
  assert res['Value'] == []


def test__Standard_Data_G1(setup):
  """Test StandardPlugin: input data, active."""
  pluginStandard = TransformationPlugin('Standard')
  pluginStandard.setParameters(paramsBase)
  pluginStandard.setInputData(data)
  res = pluginStandard.run()
  assert res['OK']
  sortedData = sorted([(",".join(SEs), [lfn]) for lfn, SEs in data.items()])
  assert res['Value'], sortedData


def test__Standard_Flush_G1(setup):
  """Test StandardPlugin: input data, flush."""
  pluginStandard = TransformationPlugin('Standard')
  params = dict(paramsBase)
  params['Status'] = 'Flush'
  pluginStandard.setParameters(params)
  pluginStandard.setInputData(data)
  res = pluginStandard.run()
  sortedData = sorted([(",".join(SEs), [lfn]) for lfn, SEs in data.items()])
  assert res['OK']
  assert sorted(res['Value']) == sorted(sortedData)


def test__Broadcast_Active_G1(setup):
  """Test BroadcastPlugin: input data, Active"""
  thePlugin = TransformationPlugin('Broadcast')
  params = dict(paramsBase)
  params['Status'] = 'Active'
  params['SourceSE'] = 'SE1'
  params['TargetSE'] = 'SE2'
  thePlugin.setParameters(params)
  thePlugin.setInputData(data)
  res = thePlugin.run()
  # sort returned values by first lfn in LFNs
  sortedReturn = [(SE, lfns) for SE, lfns in sorted(res['Value'], key=lambda t: t[1][0])]
  # sort data by lfn
  expected = [('SE2', [lfn]) for lfn, SEs in sorted(data.items(), key=lambda t: t[0]) if 'SE1' in SEs]
  assert res['OK']
  assert sortedReturn == expected


def test__Broadcast_Active_G10(setup):
  """Test BroadcastPlugin: input data, Active"""
  thePlugin = TransformationPlugin('Broadcast')
  params = dict(paramsBase)
  params['Status'] = 'Active'
  params['SourceSE'] = "['SE1']"
  params['TargetSE'] = ['SE2']
  params['GroupSize'] = 10
  thePlugin.setParameters(params)
  thePlugin.setInputData(data)
  res = thePlugin.run()
  assert res['OK']
  assert res['Value'] == []


def test__Broadcast_Active_G1_NoSource(setup):
  """Test BroadcastPlugin: input data, Active, noSource"""
  thePlugin = TransformationPlugin('Broadcast')
  params = dict(paramsBase)
  params['Status'] = 'Active'
  params['TargetSE'] = ['SE2']
  params['GroupSize'] = 1
  thePlugin.setParameters(params)
  thePlugin.setInputData(data)
  res = thePlugin.run()
  # sort returned values by first lfn in LFNs
  sortedReturn = [(SE, lfns) for SE, lfns in sorted(res['Value'], key=lambda t: t[1][0])]
  # sort data by lfn
  expected = [('SE2', [lfn]) for lfn, _SEs in sorted(data.items(), key=lambda t: t[0])]
  assert res['OK']
  assert sortedReturn == expected
