-- 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 context = require 'mc.context'
local log = require 'mc.logging'
local menums = require 'types.enums'
local ctx_new = context.get_context_or_default()
local c_multihost = require 'multi_host'

local ipmi_func = {}
local multihost = c_multihost:get_instance()

-- Cold Reset
function ipmi_func:ipmi_cold_reset(fru_dev_id, ctx, fructrl, powerapi)
    local sys_id = ctx.HostId or 1
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    if menums.PGSignalState[fructrl:get_FruPowerState(fru_dev_id)] ~= 'ON' then
        ipmi.ipmi_operation_log(ctx, 'fructrl', '%sFRU0 forced system reset failed', print_sys)
        return {CompletionCode = 0xd5}
    end

    ctx_new['fru_id'] = fru_dev_id
    local ok, result = pcall(function()
        return powerapi:system_reset(ctx_new, 'ForceRestart', 'ChassisControlCommand')
    end)
    if ok and result == 0x00 then
        ipmi.ipmi_operation_log(ctx, 'fructrl', '%sSet FRU0 to forced system reset successfully', print_sys)
        return {CompletionCode = 0x00}
    end
    ipmi.ipmi_operation_log(ctx, 'fructrl', '%sFRU0 forced system reset failed', print_sys)
    return {CompletionCode = 0xd5}
end

-- Warm Reset
function ipmi_func:ipmi_warm_reset(_, ctx, fructrl)
    local sys_id = ctx.HostId or 1
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    if menums.PGSignalState[fructrl:get_PowerState()] ~= 'ON' then
        ipmi.ipmi_operation_log(ctx, 'fructrl', '%sFRU0 warm reset failed', print_sys)
        return {CompletionCode = 0xd5}
    end

    -- 不支持热复位
    ipmi.ipmi_operation_log(ctx, 'fructrl', '%sFRU0 warm reset failed', print_sys)
    return {CompletionCode = 0xd5}
end

-- Force Reboot
function ipmi_func:ipmi_force_reboot(fru_dev_id, ctx, fructrl, powerapi)
    local sys_id = ctx.HostId or 1
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    if menums.PGSignalState[fructrl:get_PowerState()] ~= 'ON' then
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sFRU0 forced power off the service system, and then power it on failed', print_sys)
        return {CompletionCode = 0xd5}
    end
    ctx_new['fru_id'] = 0
    local result = powerapi:system_reset(ctx_new, 'ForcePowerCycle', 'ChassisControlCommand')
    if result == 0x00 then
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sSet FRU0 to forced power off the service system, and then power it on successfully',
            print_sys)

        return {CompletionCode = 0x00}
    else
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sFRU0 forced power off the service system, and then power it on failed', print_sys)
        return {CompletionCode = 0xd5}
    end
end

-- Graceful Reboot
function ipmi_func:ipmi_graceful_reboot(fru_dev_id, ctx, fructrl, powerapi)
    local sys_id = ctx.HostId or 1
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    if menums.PGSignalState[fructrl:get_FruPowerState(fru_dev_id)] ~= 'ON' then
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sFRU0 graceful power off the service system, and then power it on failed', print_sys)
        return {CompletionCode = 0xd5}
    end
    ctx_new['fru_id'] = fru_dev_id
    local result = powerapi:system_reset(ctx_new, 'PowerCycle', 'ChassisControlCommand')
    if result == 0x00 then
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sSet FRU0 to graceful power off the service system, and then power it on successfully',
            print_sys)

        return {CompletionCode = 0x00}
    else
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sFRU0 graceful power off the service system, and then power it on failed', print_sys)
        return {CompletionCode = 0xd5}
    end
end

-- Issue Diagnostic Interrupt
function ipmi_func:ipmi_issue_diagnostic_interrupt(_, ctx)
    local sys_id = ctx.HostId or 1
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    log:error('Nmi command is not supported on BMC')
    ipmi.ipmi_operation_log(ctx, 'fructrl', '%sFRU0 issue diagnostic interrupt failed', print_sys)
    return {CompletionCode = 0xd5}
end

function ipmi_func:ipmi_graceful_shutdown(fru_dev_id, ctx, powerapi)
    local sys_id = ctx.HostId or 1
    ctx_new['fru_id'] = fru_dev_id
    local result = powerapi:system_reset(ctx_new, 'GracefulShutdown', 'ChassisControlCommand', fru_dev_id)
    local print_sys = multihost:is_multihost_type() and '[System:' .. sys_id .. ']' or ''
    if result == 0x00 then
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sSet FRU0 to normal power off successfully', print_sys)
        return {CompletionCode = 0x00}
    else
        ipmi.ipmi_operation_log(ctx, 'fructrl',
            '%sFRU0 normal power off faild', print_sys)
        return {CompletionCode = 0xd5}
    end
end

return ipmi_func
