-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--          http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.
local mdb = require 'mc.mdb'
local class = require 'mc.class'
local app_base = require 'mc.client_app_base'
local mdb_service = require 'mc.mdb.mdb_service'
local subscribe_signal = require 'mc.mdb.subscribe_signal'
local org_freedesktop_dbus = require 'sd_bus.org_freedesktop_dbus'

local match_rule = org_freedesktop_dbus.MatchRule
local get_non_virtual_interface_objects = mdb_service.get_non_virtual_interface_objects
local foreach_non_virtual_interface_objects = mdb_service.foreach_non_virtual_interface_objects

local Manufacture = require 'manufacture.json_types.Manufacture'
local Accessor = require 'manufacture.json_types.Accessor'
local FruCtrl = require 'manufacture.json_types.FruCtrl'
local SystemControl = require 'manufacture.json_types.SystemControl'
local Bios = require 'manufacture.json_types.Bios'
local FirmwareInfo = require 'manufacture.json_types.FirmwareInfo'
local Board = require 'manufacture.json_types.Board'
local CpuBoard = require 'manufacture.json_types.CpuBoard'
local Component = require 'manufacture.json_types.Component'
local DPUCard = require 'manufacture.json_types.DPUCard'
local PCIeCard = require 'manufacture.json_types.PCIeCard'
local NetworkAdapter = require 'manufacture.json_types.NetworkAdapter'
local Status = require 'manufacture.json_types.Status'
local EthernetInterfaces = require 'manufacture.json_types.EthernetInterfaces'
local Ipv4 = require 'manufacture.json_types.Ipv4'
local GPUTool = require 'manufacture.json_types.GPUTool'
local Extension = require 'manufacture.json_types.Extension'
local Multihost = require 'manufacture.json_types.Multihost'

---@class manufacture_client: BasicClient
local manufacture_client = class(app_base.Client)

function manufacture_client:GetManufactureObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture', true)
end

function manufacture_client:ForeachManufactureObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture', cb, true)
end

function manufacture_client:GetAccessorObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Accessor', true)
end

function manufacture_client:ForeachAccessorObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Accessor', cb, true)
end

function manufacture_client:GetFruCtrlObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.FruCtrl', true)
end

function manufacture_client:ForeachFruCtrlObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.FruCtrl', cb, true)
end

function manufacture_client:GetSystemControlObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.SystemControl', true)
end

function manufacture_client:ForeachSystemControlObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.SystemControl', cb, true)
end

function manufacture_client:GetBiosObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Bios', true)
end

function manufacture_client:ForeachBiosObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Bios', cb, true)
end

function manufacture_client:GetFirmwareInfoObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.UpdateService.FirmwareInfo', true)
end

function manufacture_client:ForeachFirmwareInfoObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.UpdateService.FirmwareInfo', cb, true)
end

function manufacture_client:GetBoardObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Board', true)
end

function manufacture_client:ForeachBoardObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Board', cb, true)
end

function manufacture_client:GetComponentObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Component', true)
end

function manufacture_client:ForeachComponentObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.Component', cb, true)
end

function manufacture_client:GetDPUCardObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.DPUCard', true)
end

function manufacture_client:ForeachDPUCardObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.DPUCard', cb, true)
end

function manufacture_client:GetPCIeCardObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.PCIeDevices.PCIeCard', true)
end

function manufacture_client:ForeachPCIeCardObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.PCIeDevices.PCIeCard', cb, true)
end

function manufacture_client:GetNetworkAdapterObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.NetworkAdapter', true)
end

function manufacture_client:ForeachNetworkAdapterObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Systems.NetworkAdapter', cb, true)
end

function manufacture_client:GetStatusObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture.Status', true)
end

function manufacture_client:ForeachStatusObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture.Status', cb, true)
end

function manufacture_client:GetEthernetInterfacesObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces', true)
end

function manufacture_client:ForeachEthernetInterfacesObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces', cb, true)
end

function manufacture_client:GetIpv4Objects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.Ipv4', true)
end

function manufacture_client:ForeachIpv4Objects(cb)
    return
        foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.Ipv4', cb, true)
end

function manufacture_client:GetExtensionObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture.Extension', true)
end

function manufacture_client:ForeachExtensionObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Manufacture.Extension', cb, true)
end

function manufacture_client:GetMultihostObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.Multihost', true)
end

function manufacture_client:ForeachMultihostObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.Multihost', cb, true)
end

function manufacture_client:OnManufactureInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture')
end

function manufacture_client:OnManufactureInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture')
end

function manufacture_client:OnAccessorInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Accessor')
end

function manufacture_client:OnAccessorInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Accessor')
end

function manufacture_client:OnFruCtrlInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.FruCtrl')
end

function manufacture_client:OnFruCtrlInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.FruCtrl')
end

function manufacture_client:OnSystemControlInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.SystemControl')
end

function manufacture_client:OnSystemControlInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.SystemControl')
end

function manufacture_client:OnBiosInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Bios')
end

function manufacture_client:OnBiosInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Bios')
end

function manufacture_client:OnFirmwareInfoInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.UpdateService.FirmwareInfo')
end

function manufacture_client:OnFirmwareInfoInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.UpdateService.FirmwareInfo')
end

function manufacture_client:OnBoardInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Board')
end

function manufacture_client:OnBoardInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Board')
end

function manufacture_client:GetCpuBoardCpuBoardObject(path_params)
    return mdb.try_get_object(self:get_bus(),
        path_params and ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Boards/CpuBoard/' .. path_params['Id']) or
            '/bmc/kepler/Systems/${SystemId}/Boards/CpuBoard/${Id}', 'bmc.kepler.Systems.Board.CpuBoard')
end

function manufacture_client:OnCpuBoardInterfacesAdded(cb, path_params)
    local path_namespace = path_params and
                               ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Boards/CpuBoard/' ..
                                   path_params['Id']) or '/bmc/kepler/Systems'
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), path_namespace, cb,
        'bmc.kepler.Systems.Board.CpuBoard')
end

function manufacture_client:OnCpuBoardInterfacesRemoved(cb, path_params)
    local path_namespace = path_params and
                               ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Boards/CpuBoard/' ..
                                   path_params['Id']) or '/bmc/kepler/Systems'
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), path_namespace,
        cb, 'bmc.kepler.Systems.Board.CpuBoard')
end

function manufacture_client:OnComponentInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Component')
end

function manufacture_client:OnComponentInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.Component')
end

function manufacture_client:OnDPUCardInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.DPUCard')
end

function manufacture_client:OnDPUCardInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.DPUCard')
end

function manufacture_client:OnPCIeCardInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.PCIeDevices.PCIeCard')
end

function manufacture_client:OnPCIeCardInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.PCIeDevices.PCIeCard')
end

function manufacture_client:OnNetworkAdapterInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.NetworkAdapter')
end

function manufacture_client:OnNetworkAdapterInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Systems.NetworkAdapter')
end

function manufacture_client:OnStatusInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture.Status')
end

function manufacture_client:OnStatusInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture.Status')
end

function manufacture_client:OnEthernetInterfacesInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces')
end

function manufacture_client:OnEthernetInterfacesInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces')
end

function manufacture_client:OnIpv4InterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces.Ipv4')
end

function manufacture_client:OnIpv4InterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces.Ipv4')
end

function manufacture_client:GetBmcDfxGPUToolObject(path_params)
    return mdb.try_get_object(self:get_bus(),
        path_params and ('/bmc/kepler/Managers/' .. path_params['ManagerId'] .. '/SOC/BmcDfx') or
            '/bmc/kepler/Managers/:ManagerId/SOC/BmcDfx', 'bmc.kepler.Managers.SOC.GPUTool')
end

function manufacture_client:OnGPUToolInterfacesAdded(cb, path_params)
    local path_namespace = path_params and ('/bmc/kepler/Managers/' .. path_params['ManagerId'] .. '/SOC/BmcDfx') or
                               '/bmc/kepler/Managers'
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), path_namespace, cb,
        'bmc.kepler.Managers.SOC.GPUTool')
end

function manufacture_client:OnGPUToolInterfacesRemoved(cb, path_params)
    local path_namespace = path_params and ('/bmc/kepler/Managers/' .. path_params['ManagerId'] .. '/SOC/BmcDfx') or
                               '/bmc/kepler/Managers'
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), path_namespace,
        cb, 'bmc.kepler.Managers.SOC.GPUTool')
end

function manufacture_client:OnExtensionInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture.Extension')
end

function manufacture_client:OnExtensionInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Manufacture.Extension')
end

function manufacture_client:OnMultihostInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.Multihost')
end

function manufacture_client:OnMultihostInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.Multihost')
end

---@param Path string
---@param Resolution string
---@param BBP integer
---@return GPUTool.ImportRsp
function manufacture_client:BmcDfxGPUToolImport(ctx, path_params, Path, Resolution, BBP)
    local req = GPUTool.ImportReq.new(Path, Resolution, BBP):validate()
    local obj = self:GetBmcDfxGPUToolObject(path_params)

    return GPUTool.ImportRsp.new(obj:Import(ctx, req:unpack(true)))
end

function manufacture_client:PBmcDfxGPUToolImport(ctx, path_params, Path, Resolution, BBP)
    return pcall(function()
        local req = GPUTool.ImportReq.new(Path, Resolution, BBP):validate()
        local obj = self:GetBmcDfxGPUToolObject(path_params)

        return GPUTool.ImportRsp.new(obj:Import(ctx, req:unpack(true)))
    end)
end

function manufacture_client:SubscribeFruCtrlBeforePowerOnSignal(cb)
    local sig = match_rule.signal('BeforePowerOnSignal', 'bmc.kepler.Systems.FruCtrl')
    self.signal_slots[#self.signal_slots + 1] = self:get_bus():match(sig, function(msg)
        cb(msg:read())
    end)
end

function manufacture_client:SubscribeEthernetInterfacesActivePortChangedSignal(cb)
    local sig = match_rule.signal('ActivePortChangedSignal', 'bmc.kepler.Managers.EthernetInterfaces')
    self.signal_slots[#self.signal_slots + 1] = self:get_bus():match(sig, function(msg)
        cb(msg:read())
    end)
end

function manufacture_client:SubscribeEthernetInterfacesNCSIInfoChangedSignal(cb)
    local sig = match_rule.signal('NCSIInfoChangedSignal', 'bmc.kepler.Managers.EthernetInterfaces')
    self.signal_slots[#self.signal_slots + 1] = self:get_bus():match(sig, function(msg)
        cb(msg:read())
    end)
end

function manufacture_client:SubscribeEthernetInterfacesEthMacChangedSignal(cb)
    local sig = match_rule.signal('EthMacChangedSignal', 'bmc.kepler.Managers.EthernetInterfaces')
    self.signal_slots[#self.signal_slots + 1] = self:get_bus():match(sig, function(msg)
        cb(msg:read())
    end)
end

function manufacture_client:SubscribeIpv4ChangedSignal(cb)
    local sig = match_rule.signal('ChangedSignal', 'bmc.kepler.Managers.EthernetInterfaces.Ipv4')
    self.signal_slots[#self.signal_slots + 1] = self:get_bus():match(sig, function(msg)
        cb(msg:read())
    end)
end

function manufacture_client:ctor()
    self.signal_slots = {}
end

---@type manufacture_client
return manufacture_client.new('manufacture')
