""" JobCommand

  The JobCommand class is a command class to know about present jobs efficiency

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

__RCSID__ = "$Id$"

from DIRAC import S_OK, S_ERROR
from DIRAC.ConfigurationSystem.Client.Helpers.Resources import getSites
from DIRAC.ResourceStatusSystem.Command.Command import Command
from DIRAC.ResourceStatusSystem.Client.ResourceManagementClient import ResourceManagementClient
from DIRAC.WorkloadManagementSystem.Client.WMSAdministratorClient import WMSAdministratorClient


class JobCommand(Command):
    """
    Job "master" Command.
    """

    def __init__(self, args=None, clients=None):

        super(JobCommand, self).__init__(args, clients)

        if "WMSAdministrator" in self.apis:
            self.wmsAdmin = self.apis["WMSAdministrator"]
        else:
            self.wmsAdmin = WMSAdministratorClient()

        if "ResourceManagementClient" in self.apis:
            self.rmClient = self.apis["ResourceManagementClient"]
        else:
            self.rmClient = ResourceManagementClient()

    def _storeCommand(self, result):
        """
        Stores the results of doNew method on the database.
        """

        for jobDict in result:

            resQuery = self.rmClient.addOrModifyJobCache(
                jobDict["Site"], jobDict["MaskStatus"], jobDict["Efficiency"], jobDict["Status"]
            )
            if not resQuery["OK"]:
                return resQuery
        return S_OK()

    def _prepareCommand(self):
        """
        JobCommand requires one arguments:
        - name : <str>
        """

        if "name" not in self.args:
            return S_ERROR('"name" not found in self.args')
        name = self.args["name"]

        return S_OK(name)

    def doNew(self, masterParams=None):
        """
        Gets the parameters to run, either from the master method or from its
        own arguments.

        It contacts the WMSAdministrator with a list of site names, or a single
        site.

        If there are jobs, are recorded and then returned.
        """

        if masterParams is not None:
            name = masterParams
        else:
            params = self._prepareCommand()
            if not params["OK"]:
                return params
            name = params["Value"]

        # selectDict, sortList, startItem, maxItems
        # Returns statistics of Last day !
        results = self.wmsAdmin.getSiteSummaryWeb({"Site": name}, [], 0, 0)
        if not results["OK"]:
            return results
        results = results["Value"]

        if "ParameterNames" not in results:
            return S_ERROR('Wrong result dictionary, missing "ParameterNames"')
        params = results["ParameterNames"]

        if "Records" not in results:
            return S_ERROR('Wrong formed result dictionary, missing "Records"')
        records = results["Records"]

        uniformResult = []

        for record in records:

            # This returns a dictionary with the following keys
            # 'Site', 'GridType', 'Country', 'Tier', 'MaskStatus', 'Received',
            # 'Checking', 'Staging', 'Waiting', 'Matched', 'Running', 'Stalled',
            # 'Done', 'Completed', 'Failed', 'Efficiency', 'Status'
            jobDict = dict(zip(params, record))

            # We cast efficiency to a float
            jobDict["Efficiency"] = float(jobDict["Efficiency"])

            uniformResult.append(jobDict)

        storeRes = self._storeCommand(uniformResult)
        if not storeRes["OK"]:
            return storeRes

        return S_OK(uniformResult)

    def doCache(self):
        """
        Method that reads the cache table and tries to read from it. It will
        return a list of dictionaries if there are results.
        """

        params = self._prepareCommand()
        if not params["OK"]:
            return params
        name = params["Value"]

        result = self.rmClient.selectJobCache(name)
        if result["OK"]:
            result = S_OK([dict(zip(result["Columns"], res)) for res in result["Value"]])

        return result

    def doMaster(self):
        """
        Master method.

        Gets all sites and calls doNew method.
        """

        siteNames = getSites()
        if not siteNames["OK"]:
            return siteNames
        siteNames = siteNames["Value"]

        jobsResults = self.doNew(siteNames)
        if not jobsResults["OK"]:
            self.metrics["failed"].append(jobsResults["Message"])

        return S_OK(self.metrics)


class JobsWMSCommand(Command):
    def __init__(self, args=None, clients=None):

        super(JobsWMSCommand, self).__init__(args, clients)

        if "WMSAdministrator" in self.apis:
            self.wmsAdmin = self.apis["WMSAdministrator"]
        else:
            self.wmsAdmin = WMSAdministratorClient()

    def doCommand(self):
        """
        Returns simple jobs efficiency

        :param args:
           - args[0]: string: should be a ValidElement

           - args[1]: string should be the name of the ValidElement

        :returns: { 'Result': 'Good'|'Fair'|'Poor'|'Idle'|'Bad' }
        """

        if "siteName" not in self.args:
            return self.returnERROR(S_ERROR("siteName is missing"))
        siteName = self.args["siteName"]

        # If siteName is None, we take all sites
        if siteName is None:
            siteName = getSites()
            if not siteName["OK"]:
                return self.returnERROR(siteName)
            siteName = siteName["Value"]

        results = self.wmsAdmin.getSiteSummaryWeb({"Site": siteName}, [], 0, 500)

        if not results["OK"]:
            return self.returnERROR(results)
        results = results["Value"]

        if "ParameterNames" not in results:
            return self.returnERROR(S_ERROR("Malformed result dictionary"))
        params = results["ParameterNames"]

        if "Records" not in results:
            return self.returnERROR(S_ERROR("Malformed result dictionary"))
        records = results["Records"]

        jobResults = []

        for record in records:

            jobDict = dict(zip(params, record))
            try:
                jobDict["Efficiency"] = float(jobDict["Efficiency"])
            except KeyError as e:
                return self.returnERROR(S_ERROR(e))
            except ValueError as e:
                return self.returnERROR(S_ERROR(e))

            jobResults.append(jobDict)

        return S_OK(jobResults)
