-- 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.

require 'general_hardware.json_types.SystemsFruCtrl'
require 'general_hardware.json_types.Retimer'
local client_debug_ok, client_debug = pcall(require, 'debug.client')
local skynet = require 'skynet'
local unit_manager = require 'unit_manager.unit_manager'
local card_manager = require 'card_manager.card_manager'
local logic_fw_signal = require 'unit_manager.class.logic_fw.signal'
local reboot_manage = require 'mc.mdb.micro_component.reboot'
local class = require 'mc.class'
local log = require 'mc.logging'
local mc_admin = require 'mc.mc_admin'
local intf_debug = require 'mc.mdb.micro_component.debug'
local orm_object_manage = require 'mc.orm.object_manage'
local config_manage = require 'mc.mdb.micro_component.config_manage'
local object_manage = require 'mc.mdb.object_manage'
local singleton = require 'mc.singleton'
local ipmi_req = require 'general_hardware.ipmi.ipmi'
local dpu_service = require 'dpu_service.dpu_service'
local c_service_manager = require 'service_manager'
local common_ipmi = require 'common_ipmi'
local vrd_chip_service = require 'vrd.chip.vrd_chip_service'
local vrd_manager = require 'vrd.vrd_manager'
local vrd_power_service = require 'vrd.chip.power.vrd_power_service'
local client = require 'general_hardware.client'
local c_service = require 'general_hardware.service'
local utils_core = require 'utils.core'
local log_collector = require 'log_collector'
local import_export = require 'import_export'
local factory = require 'factory'
local cpu_ipmi = require 'cpu_service.cpu_ipmi'
local sr_upg_service = require 'sr_upg_service.sr_upg_service'
local security_service = require 'security_module.security_service'
local cmn = require 'common'
local multihost_common = require 'multihost.common'
local gpu_service = require 'gpu_service.gpu_service'
local mcu_service = require 'mcu.mcu_service'
local upgrade_service_handle = require 'mcu.upgrade.upgrade_service.upgrade_service_handle'
local retimer_service = require 'retimer.retimer_service'
local gpu_ipmi = require 'gpu_service.gpu_ipmi'
local dpu_ipmi = require 'dpu_service.dpu_ipmi'
local starter_ok, starter = pcall(require, 'mc.mem_collect.starter')
local upgrade_subject = require 'upgrade_subject.upgrade_subject'
local maintenance_service = require 'maintenance_service.maintenance_service'
local device_mgmt = require 'device_mgmt.device_mgmt'
local independent_vrd_service = require 'independent_vrd.ind_vrd_service'
local metric_collect = require 'metric_collect'
local smc_firmware_status = require 'release_command.smc_firmware_status'
local gen_hw_bus = require 'general_hardware_bus'

local DFT_SWITCH<const> = {
    ['DftMemoryVolt'] = 1,
    ['Dft12V0Vlot'] = 1,
    ['Dft5V0Vlot'] = 1,
    ['Dft3V3Vlot'] = 1,
    ['DftCardPresence'] = 1,
    ['DftButtonCell'] = 1,
    ['DftFlash'] = 1,
    ['DftJTAG'] = 1,
    ['DftCpld'] = 1,
    ['DftIOTest'] = 1,
    ['DftHwChannel'] = 1
}

local gen_hw_app = class(c_service, nil, true)

function gen_hw_app:ctor()
    self.gen_hw_bus = gen_hw_bus.new(self)
    self.service_manager = c_service_manager.new()
    self.unit_manager = unit_manager.new(self.service_manager)
    factory.register_to_factory("unit_manager", self.unit_manager)
    self.card_manager = card_manager.new(self.service_manager)
    self.gpu_service = gpu_service.new(self.bus)
    self.dft_list = {}
    self.upg_subject_service = upgrade_subject.new()
    self.vrd_manager = vrd_manager.new()
    self.vrd_power_service = vrd_power_service.new()
    self.sr_upg_service = sr_upg_service.new()
    self.mcu_service = mcu_service.new()
    self.independent_vrd_service = independent_vrd_service.new()
    self.service_manager:register('mcu', self.mcu_service)
    self.retimer_service = retimer_service.new()
    self.security_service = security_service.new()
    self.dpu_service = dpu_service.new()
    self.common_ipmi = common_ipmi.new()
    self.gpu_ipmi = gpu_ipmi.new(self.bus)
    self.cpu_ipmi = cpu_ipmi.new()
    self.dpu_ipmi = dpu_ipmi.new(self.dpu_service)
    self.maintenance_service = maintenance_service.new(self.bus)
    self.device_mgmt = device_mgmt.new(self)
    self.vrd_chip_service = vrd_chip_service.new()
end

function gen_hw_app:check_dependencies()
    local admin = mc_admin.new()
    admin:parse_dependency(utils_core.getcwd() .. '/mds/service.json')
    admin:check_dependency(self.bus)
end

function gen_hw_app:register_listen_cb(sys_id)
    local fru_path = '/bmc/kepler/Systems/' .. sys_id .. '/FruCtrl'
    client:OnSystemsFruCtrlPropertiesChanged(function(values, path, _)
        if not string.find(path, fru_path) then
            return
        end
        if values['PowerState'] and values['PowerState']:value() == 'OFF' then
            self.dpu_service:send_host_os_status_to_sdi_mcu(0)
        elseif values['PowerState'] and values['PowerState']:value() == 'ON' then
            self.dpu_service:send_host_os_status_to_sdi_mcu(1)
        end
    end)
end

function gen_hw_app:on_add_dft_object(class_name, object, position)
    if DFT_SWITCH[class_name] then
        self.dft_list[class_name .. '_' .. object.Id .. "_" .. object.Slot .. "_" .. object.DeviceNum] = object
    end
end

function gen_hw_app:on_delete_dft_object(class_name, object, position)
    if DFT_SWITCH[class_name] then
        local key_str = class_name .. '_' .. object.Id .. "_" .. object.Slot .. "_" .. object.DeviceNum
        self.dft_list[key_str] = nil
    end
end

function gen_hw_app:on_reboot_prepare()
    log:info('[general_hardware] reboot prepare')
end

function gen_hw_app:on_reboot_cancel()
    log:info('[general_hardware] reboot cancel')
end

function gen_hw_app:on_reboot_action()
    log:info('[general_hardware] reboot action')
end

function gen_hw_app:register_reboot_methods()
    -- 注册平滑重启回调函数
    -- Prepare准备重启回调
    reboot_manage.on_prepare(function()
        self:on_reboot_prepare()
        local maintenance_csr = require('maintenance_service.maintenance_csr')
        if upgrade_service_handle.get_instance():is_upgrading_or_activing() then
            log:error('Reboot iBMC failed.Vrd upgrade is progress,please wait')
            return -1
        end
        if independent_vrd_service.get_instance().smc_vrd_upgrade_obj:is_upgrading_or_activing() then
            log:error('Reboot iBMC failed. ind_vrd upgrade is progress, please wait')
            return -1
        end
        if maintenance_csr:get_is_importing() then
            log:error('Reboot iBMC failed.Csr import is progress,please wait')
            return -1
        end
        return 0
    end)
    -- Action执行重启回调
    reboot_manage.on_action(function()
        self:on_reboot_action()
        return 0
    end)
    -- Cancel取消重启回调
    reboot_manage.on_cancel(function()
        self:on_reboot_cancel()
    end)
end

function gen_hw_app:init_on_add_object()
    object_manage.on_add_object(self.bus, function(class_name, object, position)
        multihost_common:on_add_object(class_name, object, position)
        self.unit_manager:on_add_object(class_name, object, position)
        self.card_manager:on_add_object(class_name, object, position)
        self.vrd_manager:on_add_object(class_name, object, position)
        self.vrd_power_service:on_add_object(class_name, object, position)
        self.sr_upg_service:on_add_object(class_name, object, position)
        self.mcu_service:on_add_object(class_name, object, position)
        self.vrd_chip_service:on_add_object(class_name, object, position)
        self.retimer_service:on_add_object(class_name, object, position)
        self.security_service:on_add_object(class_name, object, position)
        self.dpu_service:on_add_object(class_name, object, position)
        self.gpu_service:on_add_object(class_name, object, position)
        self.independent_vrd_service:on_add_object(class_name, object, position)
        self:on_add_dft_object(class_name, object, position)
    end)
end

function gen_hw_app:init_on_delete_object()
    object_manage.on_delete_object(self.bus, function(class_name, object, position)
        self.unit_manager:on_delete_object(class_name, object, position)
        self.mcu_service:on_delete_object(class_name, object, position)
        self.vrd_manager:on_delete_object(class_name, object, position)
        self.vrd_power_service:on_delete_object(class_name, object, position)
        self.vrd_chip_service:on_delete_object(class_name, object, position)
        self.retimer_service:on_delete_object(class_name, object, position)
        self.security_service:on_delete_object(class_name, object, position)
        self.sr_upg_service:on_delete_object(class_name, object, position)
        self.card_manager:on_delete_object(class_name, object, position)
        self.dpu_service:on_delete_object(class_name, object, position)
        self.gpu_service:on_delete_object(class_name, object, position)
        self.independent_vrd_service:on_delete_object(class_name, object, position)
        self:on_delete_dft_object(class_name, object, position)
    end)
end

local function register_object(self)
    log_collector.init()
    self.npu_boards = self:CreateNpuBoards(cmn.DEFAULT_SYSTEM_ID)
    self:CreateMaintenanceCsr()
    self:CreateSmcFirmwareStatus(cmn.DEFAULT_SYSTEM_ID, function(obj)
        obj.ObjectName = 'SmcFirmwareStatus_0'
    end)
    self.unit_manager:init(self.bus, self.db)
    self.card_manager:init(self.bus)
    self.upg_subject_service:init()
    self.sr_upg_service:init(self.bus)
    self.mcu_service:init(self.bus, self.db)
    self.independent_vrd_service:init(self.bus, self.db)
    self.retimer_service:init(self.bus)
    self.security_service:init(self.db)
    self.dpu_service:init(self.bus)
    self.common_ipmi:init(self.db)
    self.vrd_chip_service:init()
    self.signal = logic_fw_signal.init(self.bus, self.db, self.unit_manager.logic_fw)
end

local function register_object_mgmt(self)
    orm_object_manage.get_instance(self.db, self.bus):start()
    -- 注册对象响应回调函数
    -- 添加对象回调
    self:init_on_add_object()
    -- 删除对象回调
    self:init_on_delete_object()
    -- 添加对象完成回调
    object_manage.on_add_object_complete(self.bus, function(position)
        self.unit_manager:on_add_object_complete(position)
        self.sr_upg_service:on_add_object_complete(position)
        self.independent_vrd_service:on_add_object_complete(position)
    end)
    -- 删除对象完成回调
    object_manage.on_delete_object_complete(self.bus, function(position)
    end)
end

local function register_listen_task(self)
    self:register_listen_cb(1)
    skynet.fork_loop({count = 0}, function()
        self.vrd_manager:start_monitor_vrd(self.bus)
    end)
end

local function register_api(self)
    self:register_reboot_methods()
    self:register_ipmi()
    self:register_rpc()
    intf_debug.on_dump(function(...)
        self.unit_manager:on_dump_cb(...)
        self.mcu_service:on_dump_cb(...)
        self.vrd_manager:on_dump_cb(...)
        self.dpu_service:on_dump_cb(...)
        self.gpu_service:on_dump_cb(...)
    end)
end

function gen_hw_app:init()
    log:notice('[general_hardware] super init')
    gen_hw_app.super.init(self)
    log:notice('[general_hardware] check dependencies')
    self:check_dependencies()
    skynet.fork_once(function()
        log:notice('[general_hardware] fork init start')
        register_object(self)
        register_object_mgmt(self)
        register_listen_task(self)
        register_api(self)
        if starter_ok and client_debug_ok then
            -- 拉起malloc_info采集工具，每个进程只能一个组件拉起一次
            local starter_obj = starter.new(client_debug, client_debug.GetPerformanceObjects,
                client_debug.OnPerformancePropertiesChanged)
            pcall(starter_obj.start, starter_obj, 'hardware')
        end
        log:notice('[general_hardware] fork init end')
    end)
end

function gen_hw_app:register_common_ipmi()
    self:register_ipmi_cmd(ipmi_req.SetSystemInfoParameters, function(...)
        return self.common_ipmi:set_system_info_parameters(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetSystemInfoParameters, function(...)
        return self.common_ipmi:get_system_info_parameters(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDeviceAction, function(...)
        return self.common_ipmi:set_device_action(...)
    end)
    self:register_ipmi_cmd(ipmi_req.ResetNpuBoard, function(...)
        return self.common_ipmi:reset_npuboard(...)
    end)
end

function gen_hw_app:register_ipmi_extras()
    self:register_ipmi_cmd(ipmi_req.GetDpuBootOption, function(...)
        return self.dpu_service:get_dpu_boot_option(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuPxeOption, function(...)
        return self.dpu_service:get_pxe_option(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuPxeOption, function(...)
        return self.dpu_service:set_pxe_option_for_sdi(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuSecureBoot, function(...)
        return self.dpu_service:get_secure_boot(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuSecureBoot, function(...)
        return self.dpu_service:set_secure_boot(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetHttpsEnable, function(...)
        return self.dpu_service:get_pxe_option(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetHttpsEnable, function(...)
        return self.dpu_service:set_pxe_option(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuStorageIP, function(...)
        return self.dpu_service:get_dpu_ip(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuSystemStatus, function(...)
        return self.dpu_service:get_dpu_os_status(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuBiosLogLevel, function(...)
        return self.dpu_service:get_dpu_bios_log_level(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetAllDpuEPInitStatus, function(...)
        return self.dpu_service:get_dpu_ep_status(...)
    end)
end

function gen_hw_app:register_ipmi()
    self:register_ipmi_cmd(ipmi_req.ReportTrustedModuleInfo, function(...)
        return self.security_service:report_trusted_module_info(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetSecurityModuleInfo, function(...)
        return self.security_service:get_security_module_info(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuBootOption, function(...)
        return self.dpu_service:set_dpu_boot_option(...)
    end)
    self:register_ipmi_cmd(ipmi_req.RestSDI, function(...)
        return self.dpu_service:reset_sdi_card(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuNMI, function(...)
        return self.dpu_service:set_dpu_nmi(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuPowerState, function(...)
        return self.dpu_service:set_dpu_power_state(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuResetLinkage, function(...)
        return self.dpu_service:set_dpu_reset_linkage(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuResetLinkage, function(...)
        return self.dpu_ipmi:get_dpu_reset_linkage(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuIp, function(...)
        return self.dpu_service:set_dpu_ip(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuSolSwitch, function(...)
        return self.dpu_service:set_dpu_sol_switch(...)
    end)
    self:register_ipmi_cmd(ipmi_req.SetDpuBiosLogLevel, function(...)
        return self.dpu_service:set_dpu_bios_log_level(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetDpuSolSwitch, function(...)
        return self.dpu_service:get_dpu_sol_switch(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetCpuModulePower, function(...)
        return self.cpu_ipmi:get_cpu_module_power(...)
    end)
    self:register_ipmi_cmd(ipmi_req.GetGpuChipInfo, function (req, ctx, ...)
        return self.gpu_ipmi:get_gpu_chip_info(req, ctx, ...)
    end)

    self:register_ipmi_extras()
    self:register_common_ipmi()
end

-- mcu升级不依赖装备模式，去掉此设置接口
function gen_hw_app:set_dft_mode()
end

function gen_hw_app:register_rpc()
    self:ImplDPUCardDPUCardSetDpuNmi(function(obj, ctx, ...)
        return self.dpu_service:set_dpu_nmi_rpc(ctx, ...)
    end)
    self:ImplDPUCardDPUCardReset(function(obj, ctx)
        return self.dpu_service:reset_dpu_rpc(obj, ctx)
    end)
    self:ImplDPUCardDPUCardSetPowerState(function(obj, ctx, power_state)
        return self.dpu_service:set_power_state(obj, ctx, power_state)
    end)
    self:ImplNpuBoardsNpuBoardsSetNpuPowerCap(function(obj, ctx, ...)
        return self.unit_manager:set_npu_power_cap(obj, ctx, ...)
    end)
    self:ImplNpuBoardNpuBoardReset(function(obj, ctx, slot)
        return self.unit_manager:reset_npu(obj, ctx, slot)
    end)
    self:ImplNpuBoardNpuBoardResetDevice(function(obj, ctx, region_id)
        return self.unit_manager:reset_npu_device(obj, ctx, region_id)
    end)
    self:ImplDPUCardDPUCardSetBootOption(function(obj, ctx, mode, enabled)
        return self.dpu_service:set_dpu_boot_option_rpc(obj, ctx, mode, enabled)
    end)
    self:ImplDPUCardDPUCardImportPublicKey(function(obj, ctx, type, file_path)
        return self.dpu_service:import_public_key(obj, ctx, type, file_path)
    end)
    self:ImplDPUCardDPUCardGetLLDPStatus(function(obj, ctx, port_id)
        return self.dpu_service:get_LLDP_status(obj, ctx, port_id)
    end)
    self:ImplDPUCardDPUCardSetLLDPStatus(function(obj, ctx, port_id, status)
        return self.dpu_service:set_LLDP_status(obj, ctx, port_id, status)
    end)
    self:ImplNpuBoardMetricGetItems(function(obj, ctx, ...)
        return self.unit_manager:get_npu_metric_collection_items(obj, ...)
    end)
    self:ImplNpuBoardMetricGetData(function(obj, ctx, ...)
        return self.unit_manager:get_npu_metric_collection_data(obj, ...)
    end)

    -- 导入导出注册
    config_manage.on_import(function(ctx, config_data, import_type)
        import_export.import(ctx, config_data, import_type, self.db)
    end)
    config_manage.on_export(function(ctx, export_type)
        return import_export.export(ctx, export_type, self.db)
    end)
    config_manage.on_verify(function(ctx, config_data)
        return import_export.verify(ctx, config_data)
    end)
    self:ImplMaintenanceCsrMaintenanceImport(function(obj, ctx, ...)
        return self.maintenance_service.maintenance_csr:import_csr(ctx, ...)
    end)
    self:ImplDPUCardSOLSetSerialDirection(function(obj, ctx, ...)
        return self.dpu_service:set_serial_direction(obj, ctx, ...)
    end)
    self:ImplVrdMgmtMetricGetItems(function(obj, ctx, ...)
        return metric_collect:get_cpu_voltage_items(self.bus, obj)
    end)
    self:ImplVrdMgmtMetricGetData(function(obj, ctx, ...)
        return metric_collect:get_cpu_voltage_data(self.bus, obj, ...)
    end)
    self:ImplSmcFirmwareStatusSmcFirmwareStatusGetFirmwareObjectDetails(function(obj, ctx, ...)
        return smc_firmware_status:get_update_details(self.mcu_service, self.independent_vrd_service, ...)
    end)
end

return singleton(gen_hw_app)
