# Copyright 2021-2023 VMware, Inc.
# All rights reserved. -- VMware Confidential

import logging

from vmware.esxsoftwarecli import List, Struct
from .DpuLib import getManagedDpuInfo, getDpuInfoFromId, getDpuAlias

log = logging.getLogger(__name__)

def _getForamttedDict(struct):
   """Genrates a new dictionary after formatting CamelCase names
      received from DPU xml output.
      Parameters:
         * struct - Dictionary recevied in CamelCase format.
   """
   newDict = {}
   for key in struct.keys():
      newKey = key[0]
      for ch in key[1:]:
         if ch.isupper() and newKey[-1].islower():
            newKey += ' '
         newKey += ch
      newDict[newKey] = struct.get(key)
   return newDict

# Converting boolean values received as string back to boolean.
restoreBool = lambda boolStr : True if boolStr.lower() == 'true' else False

class CliOutputHandler:
   """Base Class to build an output to show the result of DPU
      installation operations.
   """
   STRUCTTYPE = None
   def __init__(self, dpuRes=None):
      self.output = []

      for dpuId, result in dpuRes.items():
         output = result.get('output')
         output['DPU ID'] = dpuId
         if self.STRUCTTYPE:
            output['structtype'] = self.STRUCTTYPE
         self.output.append(output)

   def outputHandler(self):
      """Method updating the received DPU output
         as required by each esxcli command.
      """
      output, self.output = self.output, []
      for inst in output:
         dpuDict = _getForamttedDict(inst)
         self.output.append(dpuDict)

   def getCliOutput(self):
      """Method returning the received DPU output.
      """
      return self.output

class CliListOutputHandler:
   """Base Class to build an output to show the result of DPU
      list operations.
   """
   STRUCTTYPE = None
   def __init__(self, dpuRes=None):
      self.output = []
      self._dpus = getManagedDpuInfo()

      for dpuId, result in dpuRes.items():
         output = result.get('output')
         dpuInfo = getDpuInfoFromId(self._dpus, dpuId)
         dpuAlias = getDpuAlias(dpuInfo)
         for val in output:
            val['Platforms'] = str(dpuAlias)
         self.output.append(output)

   def outputHandler(self):
      output, self.output = self.output, []
      for dpuInst in output:
         for inst in dpuInst:
            dpuDict = _getForamttedDict(inst)
            self.output.append(dpuDict)

   def getCliOutput(self):
      return self.output

class ProfileGetOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      profile get operation.
   """
   STRUCTTYPE = 'DpuImageProfile'
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUProfiles', [])
         dpuOut['VIBs'] = \
               List('string', sorted(dpuOut.get('VIBs', [])))
      self.output = [Struct(**inst) for inst in self.output]

class InstallationOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      installation operations.
   """
   STRUCTTYPE = 'DpuInstallationResult'
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUResults', [])
         dpuOut['Reboot Required'] = restoreBool(dpuOut['Reboot Required'])
         dpuOut['VIBs Installed'] = \
               List('string', sorted(dpuOut.get('VIBs Installed', [])))
         dpuOut['VIBs Removed'] = \
               List('string', sorted(dpuOut.get('VIBs Removed', [])))
         dpuOut['VIBs Skipped'] = \
               List('string', sorted(dpuOut.get('VIBs Skipped', [])))
      self.output = [Struct(**inst) for inst in self.output]

class InstallationCompOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      component installation operation.
   """
   STRUCTTYPE = 'DpuCompInstallationResult'
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUResults', [])
         dpuOut['Reboot Required'] = restoreBool(dpuOut['Reboot Required'])
         dpuOut['Components Installed'] = \
               List('string', sorted(dpuOut.get('Components Installed', [])))
         dpuOut['Components Removed'] = \
               List('string', sorted(dpuOut.get('Components Removed', [])))
         dpuOut['Components Skipped'] = \
               List('string', sorted(dpuOut.get('Components Skipped', [])))
      self.output = [Struct(**inst) for inst in self.output]

class ProfileValidateOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      profile validate operation.
   """
   STRUCTTYPE = 'ProfileValidationDpuResult'
   def __init__(self, output):
      super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUValidation Results', [])
         dpuOut['Compliant'] = restoreBool(dpuOut['Compliant'])
         dpuOut['DPU Image Profile'] = dpuOut.pop('Host Image Profile', '')
         dpuOut['VIBs in DPU Image Profile Only'] = \
               List('string', sorted(dpuOut.pop('VIBsin Host Image Profile Only', [])))
         dpuOut['VIBs in Validation Profile Only'] = \
               List('string', sorted(dpuOut.pop('VIBsin Validation Profile Only', [])))
      self.output = [Struct(**inst) for inst in self.output]

class BaseImageGetOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      base image get operation.
   """
   STRUCTTYPE = 'DpuBaseImage'
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUBaseimages', [])
         dpuOut['ReleaseID'] = dpuOut.pop('Release ID', '')
         dpuOut['docURL'] = dpuOut.pop('doc URL', '')
         dpuOut['Components'] = \
               List('string', sorted(dpuOut.get('Components', [])))
         dpuOut['Quick Patch Compatible Versions'] = List('string',
                dpuOut.get('Quick Patch Compatible Versions', []))
      self.output = [Struct(**inst) for inst in self.output]

class AddonGetOutputHandler(CliOutputHandler):
   """Class to build an output to show the result of DPU
      addon get operation.
   """
   STRUCTTYPE = 'DpuAddon'
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut.pop('DPUAddons', [])
         dpuOut['ReleaseID'] = dpuOut.pop('Release ID', '')
         dpuOut['docURL'] = dpuOut.pop('doc URL', '')
         dpuOut['Components'] = \
               List('string', sorted(dpuOut.get('Components', [])))
         dpuOut['Removed Component Names'] = \
               List('string', sorted(dpuOut.get('Removed Component Names', [])))
      self.output = [Struct(**inst) for inst in self.output]

class CompGetOutputHandler(CliListOutputHandler):
   """Class to build an output to show the result of DPU
      component get operation.
   """
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut['ReleaseDate'] = dpuOut.pop('Release Date', '')
      self.output = [Struct(**inst) for inst in self.output]

class GetAndListOutputHandler(CliListOutputHandler):
   """Class to build an output to show the result of DPU
      get and list operation.
   """
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      self.output = [Struct(**inst) for inst in self.output]

class VibGetOutputHandler(CliListOutputHandler):
   """Class to build an output to show the result of DPU
      vib get operation.
   """
   def __init__(self, output):
       super().__init__(output)

   def outputHandler(self):
      super().outputHandler()
      for dpuOut in self.output:
         dpuOut['ReferenceURLs'] = \
               List('string', sorted(dpuOut.pop('Reference URLs', [])))
         dpuOut['Depends'] = \
               List('string', sorted(dpuOut.get('Depends', [])))
         dpuOut['Conflicts'] = \
               List('string', sorted(dpuOut.get('Conflicts', [])))
         dpuOut['Replaces'] = \
               List('string', sorted(dpuOut.get('Replaces', [])))
         dpuOut['Provides'] = \
               List('string', sorted(dpuOut.get('Provides', [])))
         dpuOut['Hardware Platforms Required'] = \
               List('string', sorted(dpuOut.get('Hardware Platforms Required', [])))
         dpuOut['Tags'] = \
               List('string', sorted(dpuOut.get('Tags', [])))
         dpuOut['Payloads'] = \
               List('string', sorted(dpuOut.get('Payloads', [])))

      self.output = [Struct(**inst) for inst in self.output]
