-- 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 Accessor = require 'lsw.json_types.Accessor'
local EthConfig = require 'lsw.json_types.EthConfig'
local Events = require 'lsw.json_types.Events'
local EthernetInterfaces = require 'lsw.json_types.EthernetInterfaces'
local MgmtPort = require 'lsw.json_types.MgmtPort'
local NetConfig = require 'lsw.json_types.NetConfig'

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

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

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

function lsw_client:GetEthConfigObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.EthConfig', true)
end

function lsw_client:ForeachEthConfigObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.EthConfig', cb,
        true)
end

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

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

function lsw_client:GetMgmtPortObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.MgmtPort', true)
end

function lsw_client:ForeachMgmtPortObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.EthernetInterfaces.MgmtPort', cb,
        true)
end

function lsw_client:GetNetConfigObjects()
    return get_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.Chassis.NetConfig', true)
end

function lsw_client:ForeachNetConfigObjects(cb)
    return foreach_non_virtual_interface_objects(self:get_bus(), 'bmc.kepler.Managers.Chassis.NetConfig', cb, true)
end

function lsw_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 lsw_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 lsw_client:OnEthConfigInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces.EthConfig')
end

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

function lsw_client:GetEventsEventsObject(path_params)
    return mdb.try_get_object(self:get_bus(),
        path_params and ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Events') or
            '/bmc/kepler/Systems/:SystemId/Events', 'bmc.kepler.Systems.Events')
end

function lsw_client:OnEventsInterfacesAdded(cb, path_params)
    local path_namespace = path_params and ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Events') 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.Events')
end

function lsw_client:OnEventsInterfacesRemoved(cb, path_params)
    local path_namespace = path_params and ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/Events') 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.Events')
end

function lsw_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 lsw_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 lsw_client:OnMgmtPortPropertiesChanged(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_properties_changed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.EthernetInterfaces.MgmtPort', {'VLANId'})
end

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

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

function lsw_client:OnNetConfigInterfacesAdded(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_added(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.Chassis.NetConfig')
end

function lsw_client:OnNetConfigInterfacesRemoved(cb)
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_interfaces_removed(self:get_bus(), '/bmc', cb,
        'bmc.kepler.Managers.Chassis.NetConfig')
end

---@param EventCode string
---@param Enabled integer
---@param ObjectIndex integer
---@param MockState integer
---@return Events.MockEventRsp
function lsw_client:EventsEventsMockEvent(ctx, path_params, EventCode, Enabled, ObjectIndex, MockState)
    local req = Events.MockEventReq.new(EventCode, Enabled, ObjectIndex, MockState):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.MockEventRsp.new(obj:MockEvent(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsMockEvent(ctx, path_params, EventCode, Enabled, ObjectIndex, MockState)
    return pcall(function()
        local req = Events.MockEventReq.new(EventCode, Enabled, ObjectIndex, MockState):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.MockEventRsp.new(obj:MockEvent(ctx, req:unpack(true)))
    end)
end

---@param StartId integer
---@param Count integer
---@param QueryParameters Events.KeyValueTable[]
---@return Events.GetAlarmListRsp
function lsw_client:EventsEventsGetAlarmList(ctx, path_params, StartId, Count, QueryParameters)
    local req = Events.GetAlarmListReq.new(StartId, Count, QueryParameters):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.GetAlarmListRsp.new(obj:GetAlarmList(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsGetAlarmList(ctx, path_params, StartId, Count, QueryParameters)
    return pcall(function()
        local req = Events.GetAlarmListReq.new(StartId, Count, QueryParameters):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.GetAlarmListRsp.new(obj:GetAlarmList(ctx, req:unpack(true)))
    end)
end

---@param StartId integer
---@param Count integer
---@param QueryParameters Events.KeyValueTable[]
---@return Events.GetEventListRsp
function lsw_client:EventsEventsGetEventList(ctx, path_params, StartId, Count, QueryParameters)
    local req = Events.GetEventListReq.new(StartId, Count, QueryParameters):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.GetEventListRsp.new(obj:GetEventList(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsGetEventList(ctx, path_params, StartId, Count, QueryParameters)
    return pcall(function()
        local req = Events.GetEventListReq.new(StartId, Count, QueryParameters):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.GetEventListRsp.new(obj:GetEventList(ctx, req:unpack(true)))
    end)
end

---@return Events.ClearEventListRsp
function lsw_client:EventsEventsClearEventList(ctx, path_params)
    local obj = self:GetEventsEventsObject(path_params)

    return Events.ClearEventListRsp.new(obj:ClearEventList(ctx))
end

function lsw_client:PEventsEventsClearEventList(ctx, path_params)
    return pcall(function()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.ClearEventListRsp.new(obj:ClearEventList(ctx))
    end)
end

---@return Events.GetEventInfoRsp
function lsw_client:EventsEventsGetEventInfo(ctx, path_params)
    local obj = self:GetEventsEventsObject(path_params)

    return Events.GetEventInfoRsp.new(obj:GetEventInfo(ctx))
end

function lsw_client:PEventsEventsGetEventInfo(ctx, path_params)
    return pcall(function()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.GetEventInfoRsp.new(obj:GetEventInfo(ctx))
    end)
end

---@param EventCode string
---@param MaskState integer
---@param Mode integer
---@return Events.MaskEventRsp
function lsw_client:EventsEventsMaskEvent(ctx, path_params, EventCode, MaskState, Mode)
    local req = Events.MaskEventReq.new(EventCode, MaskState, Mode):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.MaskEventRsp.new(obj:MaskEvent(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsMaskEvent(ctx, path_params, EventCode, MaskState, Mode)
    return pcall(function()
        local req = Events.MaskEventReq.new(EventCode, MaskState, Mode):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.MaskEventRsp.new(obj:MaskEvent(ctx, req:unpack(true)))
    end)
end

---@return Events.GetMaskedEventListRsp
function lsw_client:EventsEventsGetMaskedEventList(ctx, path_params)
    local obj = self:GetEventsEventsObject(path_params)

    return Events.GetMaskedEventListRsp.new(obj:GetMaskedEventList(ctx))
end

function lsw_client:PEventsEventsGetMaskedEventList(ctx, path_params)
    return pcall(function()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.GetMaskedEventListRsp.new(obj:GetMaskedEventList(ctx))
    end)
end

---@param EventInfo Events.KeyValueTable[]
---@return Events.AddEventRsp
function lsw_client:EventsEventsAddEvent(ctx, path_params, EventInfo)
    local req = Events.AddEventReq.new(EventInfo):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.AddEventRsp.new(obj:AddEvent(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsAddEvent(ctx, path_params, EventInfo)
    return pcall(function()
        local req = Events.AddEventReq.new(EventInfo):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.AddEventRsp.new(obj:AddEvent(ctx, req:unpack(true)))
    end)
end

---@param Path string
---@return Events.ExportEventRsp
function lsw_client:EventsEventsExportEvent(ctx, path_params, Path)
    local req = Events.ExportEventReq.new(Path):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.ExportEventRsp.new(obj:ExportEvent(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsExportEvent(ctx, path_params, Path)
    return pcall(function()
        local req = Events.ExportEventReq.new(Path):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.ExportEventRsp.new(obj:ExportEvent(ctx, req:unpack(true)))
    end)
end

---@param EventName string[]
---@return Events.CheckEventNameRsp
function lsw_client:EventsEventsCheckEventName(ctx, path_params, EventName)
    local req = Events.CheckEventNameReq.new(EventName):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.CheckEventNameRsp.new(obj:CheckEventName(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsCheckEventName(ctx, path_params, EventName)
    return pcall(function()
        local req = Events.CheckEventNameReq.new(EventName):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.CheckEventNameRsp.new(obj:CheckEventName(ctx, req:unpack(true)))
    end)
end

---@param AlarmName string
---@return Events.SetAlarmNameRsp
function lsw_client:EventsEventsSetAlarmName(ctx, path_params, AlarmName)
    local req = Events.SetAlarmNameReq.new(AlarmName):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.SetAlarmNameRsp.new(obj:SetAlarmName(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsSetAlarmName(ctx, path_params, AlarmName)
    return pcall(function()
        local req = Events.SetAlarmNameReq.new(AlarmName):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.SetAlarmNameRsp.new(obj:SetAlarmName(ctx, req:unpack(true)))
    end)
end

---@param EventCode string
---@param Severity integer
---@return Events.SetEventSeverityRsp
function lsw_client:EventsEventsSetEventSeverity(ctx, path_params, EventCode, Severity)
    local req = Events.SetEventSeverityReq.new(EventCode, Severity):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.SetEventSeverityRsp.new(obj:SetEventSeverity(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsSetEventSeverity(ctx, path_params, EventCode, Severity)
    return pcall(function()
        local req = Events.SetEventSeverityReq.new(EventCode, Severity):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.SetEventSeverityRsp.new(obj:SetEventSeverity(ctx, req:unpack(true)))
    end)
end

---@param EventKeyId string
---@param Action integer
---@return Events.SetEventActionRsp
function lsw_client:EventsEventsSetEventAction(ctx, path_params, EventKeyId, Action)
    local req = Events.SetEventActionReq.new(EventKeyId, Action):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.SetEventActionRsp.new(obj:SetEventAction(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsSetEventAction(ctx, path_params, EventKeyId, Action)
    return pcall(function()
        local req = Events.SetEventActionReq.new(EventKeyId, Action):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.SetEventActionRsp.new(obj:SetEventAction(ctx, req:unpack(true)))
    end)
end

---@param EventInfo Events.KeyValueTable[]
---@return Events.AddSelRsp
function lsw_client:EventsEventsAddSel(ctx, path_params, EventInfo)
    local req = Events.AddSelReq.new(EventInfo):validate()
    local obj = self:GetEventsEventsObject(path_params)

    return Events.AddSelRsp.new(obj:AddSel(ctx, req:unpack(true)))
end

function lsw_client:PEventsEventsAddSel(ctx, path_params, EventInfo)
    return pcall(function()
        local req = Events.AddSelReq.new(EventInfo):validate()
        local obj = self:GetEventsEventsObject(path_params)

        return Events.AddSelRsp.new(obj:AddSel(ctx, req:unpack(true)))
    end)
end

function lsw_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 lsw_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 lsw_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 lsw_client:ctor()
    self.signal_slots = {}
end

---@type lsw_client
return lsw_client.new('lsw')
