-- 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 ipmi = require 'ipmi'
local mdb = require 'mc.mdb'
local class = require 'mc.class'
local context = require 'mc.context'
local open_db = require 'fructrl.db'
local app_base = require 'mc.service_app_base'
local object_manage = require 'mc.mdb.object_manage'
local persist_client = require 'persistence.persist_client_lib'
local orm_classes = require 'fructrl.orm_classes'
local ok, datas = pcall(require, 'fructrl.datas')
if not ok then
    datas = nil -- 如果没有datas配置，证明当前组件不需要datas，仅打开数据库
end

local ChassisFruCtrlTypes = require 'fructrl.json_types.ChassisFruCtrl'
local ChassisPowerOnLockTypes = require 'fructrl.json_types.ChassisPowerOnLock'
local PowerOffLockTypes = require 'fructrl.json_types.PowerOffLock'
local PropertiesTypes = require 'mdb.bmc.kepler.Object.PropertiesInterface'
local SystemsPowerOnLockTypes = require 'fructrl.json_types.SystemsPowerOnLock'
local DelayedPowerOnPolicyTypes = require 'fructrl.json_types.DelayedPowerOnPolicy'
local SystemsFruCtrlTypes = require 'fructrl.json_types.SystemsFruCtrl'
local ThermalTripTypes = require 'fructrl.json_types.ThermalTrip'
local ManufactureTypes = require 'fructrl.json_types.Manufacture'
local SystemLockDownTypes = require 'fructrl.json_types.SystemLockDown'
local PowerActionTypes = require 'fructrl.json_types.PowerAction'
local MultihostTypes = require 'fructrl.json_types.Multihost'
local FruCtrlCapabilitiesTypes = require 'fructrl.json_types.FruCtrlCapabilities'

local ChassisFruCtrl = mdb.register_object('/bmc/kepler/Chassis/:ChassisId/FruCtrl', {
    {name = 'bmc.kepler.Chassis.FruCtrl', interface = ChassisFruCtrlTypes.interface},
    {name = 'bmc.kepler.Chassis.PowerOnLock', interface = ChassisPowerOnLockTypes.interface},
    {name = 'bmc.kepler.FruCtrl.PowerOffLock', interface = PowerOffLockTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function ChassisFruCtrl:ctor(ChassisId)
    self.path = '/bmc/kepler/Chassis/' .. ChassisId .. '/FruCtrl'
end

local FruCtrl = mdb.register_object('/bmc/kepler/Systems/:SystemId/FruCtrl/:Id', {
    {name = 'bmc.kepler.Systems.PowerOnLock', interface = SystemsPowerOnLockTypes.interface},
    {name = 'bmc.kepler.FruCtrl.PowerOffLock', interface = PowerOffLockTypes.interface},
    {name = 'bmc.kepler.Systems.DelayedPowerOnPolicy', interface = DelayedPowerOnPolicyTypes.interface},
    {name = 'bmc.kepler.Systems.FruCtrl', interface = SystemsFruCtrlTypes.interface},
    {name = 'bmc.kepler.Systems.ThermalTrip', interface = ThermalTripTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function FruCtrl:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/FruCtrl/' .. Id
end

local DftPowerButton = mdb.register_object('/bmc/kepler/Manufacture/OperateTest/DftPowerButton/:Id', {
    {name = 'bmc.kepler.Manufacture', interface = ManufactureTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function DftPowerButton:ctor(Id)
    self.path = '/bmc/kepler/Manufacture/OperateTest/DftPowerButton/' .. Id
end

local SystemLockDown = mdb.register_object('/bmc/kepler/Systems/:SystemId', {
    {name = 'bmc.kepler.Systems.SystemLockDown', interface = SystemLockDownTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function SystemLockDown:ctor(SystemId)
    self.path = '/bmc/kepler/Systems/' .. SystemId
end

local PowerAction = mdb.register_object('/bmc/kepler/Systems/:SystemId/PowerAction', {
    {name = 'bmc.kepler.Systems.PowerAction', interface = PowerActionTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function PowerAction:ctor(SystemId)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PowerAction'
end

local Multihost = mdb.register_object('/bmc/kepler/Managers/:ManagerId/Multihost', {
    {name = 'bmc.kepler.Managers.Multihost', interface = MultihostTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function Multihost:ctor(ManagerId)
    self.path = '/bmc/kepler/Managers/' .. ManagerId .. '/Multihost'
end

local FruCtrlCapabilities = mdb.register_object('/bmc/kepler/ProductInfo/FruCtrlCapabilities', {
    {name = 'bmc.kepler.ProductInfo.FruCtrlCapabilities', interface = FruCtrlCapabilitiesTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function FruCtrlCapabilities:ctor()
    self.path = '/bmc/kepler/ProductInfo/FruCtrlCapabilities'
end

local model = require 'class.model'

local fructrl_service = class(app_base.Service)

fructrl_service.package = 'fructrl'

function fructrl_service:CreateChassisFruCtrl(ChassisId, prop_setting_cb)
    local path = '/bmc/kepler/Chassis/' .. ChassisId .. '/FruCtrl'
    return object_manage.create_object('ChassisFruCtrl', path, path, prop_setting_cb)
end

function fructrl_service:CreateFruCtrl(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/FruCtrl/' .. Id
    return object_manage.create_object('FruCtrl', path, path, prop_setting_cb)
end

function fructrl_service:CreateDftPowerButton(Id, prop_setting_cb)
    local path = '/bmc/kepler/Manufacture/OperateTest/DftPowerButton/' .. Id
    return object_manage.create_object('DftPowerButton', path, path, prop_setting_cb)
end

function fructrl_service:CreateSystemLockDown(SystemId, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId
    return object_manage.create_object('SystemLockDown', path, path, prop_setting_cb)
end

function fructrl_service:CreatePowerAction(SystemId, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PowerAction'
    return object_manage.create_object('PowerAction', path, path, prop_setting_cb)
end

function fructrl_service:CreateMultihost(ManagerId, prop_setting_cb)
    local path = '/bmc/kepler/Managers/' .. ManagerId .. '/Multihost'
    return object_manage.create_object('Multihost', path, path, prop_setting_cb)
end

function fructrl_service:CreateFruCtrlCapabilities(prop_setting_cb)
    return object_manage.create_object('FruCtrlCapabilities', 'FruCtrlCapabilities_0',
        '/bmc/kepler/ProductInfo/FruCtrlCapabilities', prop_setting_cb)
end

function fructrl_service:ImplChassisFruCtrlChassisFruCtrlPowerCtrl(cb)
    model.ImplChassisFruCtrlChassisFruCtrlPowerCtrl(cb)
end

function fructrl_service:ImplChassisFruCtrlChassisFruCtrlSetPowerOnStrategyExceptions(cb)
    model.ImplChassisFruCtrlChassisFruCtrlSetPowerOnStrategyExceptions(cb)
end

function fructrl_service:ImplChassisFruCtrlChassisPowerOnLockSetPowerOnLock(cb)
    model.ImplChassisFruCtrlChassisPowerOnLockSetPowerOnLock(cb)
end

function fructrl_service:ImplChassisFruCtrlPowerOffLockSetPowerOffLock(cb)
    model.ImplChassisFruCtrlPowerOffLockSetPowerOffLock(cb)
end

function fructrl_service:ImplFruCtrlSystemsPowerOnLockSetPowerOnLock(cb)
    model.ImplFruCtrlSystemsPowerOnLockSetPowerOnLock(cb)
end

function fructrl_service:ImplFruCtrlPowerOffLockSetPowerOffLock(cb)
    model.ImplFruCtrlPowerOffLockSetPowerOffLock(cb)
end

function fructrl_service:ImplFruCtrlSystemsFruCtrlPowerCtrl(cb)
    model.ImplFruCtrlSystemsFruCtrlPowerCtrl(cb)
end

function fructrl_service:ImplFruCtrlSystemsFruCtrlSetPowerOnStrategyExceptions(cb)
    model.ImplFruCtrlSystemsFruCtrlSetPowerOnStrategyExceptions(cb)
end

function fructrl_service:ImplFruCtrlSystemsFruCtrlSetACLost(cb)
    model.ImplFruCtrlSystemsFruCtrlSetACLost(cb)
end

function fructrl_service:ImplFruCtrlSystemsFruCtrlFruPowerCtrl(cb)
    model.ImplFruCtrlSystemsFruCtrlFruPowerCtrl(cb)
end

function fructrl_service:ImplDftPowerButtonManufactureStart(cb)
    model.ImplDftPowerButtonManufactureStart(cb)
end

function fructrl_service:ImplDftPowerButtonManufactureStop(cb)
    model.ImplDftPowerButtonManufactureStop(cb)
end

function fructrl_service:ImplDftPowerButtonManufactureGetResult(cb)
    model.ImplDftPowerButtonManufactureGetResult(cb)
end

---@param mdb_object object
---@param Timeout integer
function fructrl_service:FruCtrlSystemsFruCtrlBeforePowerOnSignal(mdb_object, Timeout)
    self.bus:signal(mdb_object.path, 'bmc.kepler.Systems.FruCtrl', 'BeforePowerOnSignal', 'a{ss}y',
        context.get_context() or {}, Timeout)
end

function fructrl_service:get_bus()
    return self.bus
end

function fructrl_service:register_ipmi_cmd(ipmi_cmd, cb)
    self.ipmi_cmds[ipmi_cmd.name] = ipmi.register_ipmi_cmd(self.bus, self.service_name, ipmi_cmd,
        cb or self[ipmi_cmd.name])
end

function fructrl_service:unregister_ipmi_cmd(ipmi_cmd)
    local cmd_obj = self.ipmi_cmds[ipmi_cmd.name]
    if not cmd_obj then
        return
    end

    cmd_obj:unregister()
    self.ipmi_cmds[ipmi_cmd.name] = nil
end

function fructrl_service:ctor()
    self.ipmi_cmds = {}
    self.signal_slots = {}
    self.name = self.name or fructrl_service.package
    self.db = open_db(':memory:', datas)

    orm_classes.init(self.db)
    self.bus:request_name(app_base.Service.get_service_name(self.name))
    model.init(self.bus)
    fructrl_service.bus = self.bus
end

function fructrl_service:pre_init()
    fructrl_service.super.pre_init(self)
    self.persist = persist_client.new(self.bus, self.db, self, {
        ['t_chassis_fructrl_tb'] = true,
        ['t_fructrl_tb'] = true,
        ['t_system_lockdown'] = true,
        ['t_powerbtn_tb'] = true
    })
    object_manage.set_persist_client(self.persist)
end

function fructrl_service:init()
    fructrl_service.super.init(self)
end

return fructrl_service
