-- 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 singleton = require 'mc.singleton'
local tasks = require 'mc.orm.tasks'
local bios_factory = require 'factory.bios_factory'
local boot_def = require 'macros.boot_def'
local log = require 'mc.logging'
local obj_def = require 'macros.object_def'
local ipmi = require 'mc.ipmi'
local prop_def = require 'macros.property_def'

local activate_service = {}
activate_service.__index = activate_service

function activate_service.new()
    return setmetatable({count_down_task = nil, boot_config = nil, ctx = nil, valid = nil}, activate_service)
end

function activate_service:create_countdown_task(boot_config, ctx)
    -- 如果任务已存在，先取消之前的任务
    if self:task_running() then
        self:clear_task()
    end

    -- 先保存boot_config
    self.boot_config = boot_config
    self.ctx = ctx
    -- 启动倒计时60s任务，时间到则执行清除数据
    self.count_down_task = tasks.get_instance():timeout_ms(60 * 1000, function()
        self:clear_task()
        log:notice('power status not change, revoke bios boot config')
    end)
end

function activate_service:on_power_state_changed()
    log:debug('activate_service: monitor power state changed')
    if not self:task_running() then
        log:error('activate_service: exist task running.')
        return
    end
    -- 检测到上下电状态变化，保存启动配置
    local config = self.boot_config

    -- 此场景是在非mutihost支持
    local system_id = 1

    local ok, res = pcall(self.deal_cmos, self, config, self.ctx, system_id)
    if not ok or not res then
        log:error('deal_cmos fail.')
    end
    local boot_options_service = bios_factory.get_service('boot_options_service')
    ok = boot_options_service:save_ipmi_boot_config(config)
    if not ok then
        log:error('[activate_service]save ipmi boot config fail.')
        return
    end
    ok = boot_options_service:update_boot_info(config)
    if not ok then
        log:error('[activate_service]update boot info fail.')
        return
    end
    boot_options_service:set_boot_option_valid(boot_def.BIOS_BOOT_FLAGS_CMD, self.valid or 0, system_id)
    self:clear_task()
    log:notice('[activate_service]boot config activate task detected power state changed, execute success')
end

function activate_service:task_running()
    return self.boot_config and self.count_down_task and self.count_down_task:is_running()
end

function activate_service:clear_task()
    self.boot_config = nil
    if self.count_down_task then
        self.count_down_task:cancel()
        self.count_down_task = nil
    end
end

function activate_service:deal_cmos(params_info, ctx, system_id)
    local cmos = params_info[1].clear_cmos
    if cmos == 0 then
        return true
    end

    params_info[1].clear_cmos = 1
    local bios_ser = bios_factory.get_service('bios_service')
    if not bios_ser then
        log:error('[bios]bios_service is nil')
        ipmi.ipmi_operation_log(ctx, 'BIOS', "Failed to issue the command for restoring BIOS Setup default settings")
        return false
    end
    local ret = bios_ser:set_bios_prop(obj_def.RESET_CMOS_PROP, boot_def.BMC_ENABLE, system_id)
    if not ret then
        log:error('[bios]clear_cmos: set_bios_prop fail.')
        ipmi.ipmi_operation_log(ctx, 'BIOS', "Failed to issue the command for restoring BIOS Setup default settings")
        return false
    end
    params_info[1].clear_cmos = 0
    ipmi.ipmi_operation_log(ctx, 'BIOS', "Restoring BIOS Setup default settings issued successfully and " ..
        "the BIOS default settings will be restored upon the next startup")

    ret = bios_ser:set_bios_prop(prop_def.RESET_BIOS_TO_DEFAULTS_PENDING, true, system_id)
    if not ret then
        log:error('[bios]clear_cmos: set_bios_prop fail')
    end
    return true
end

-- valid需要单独进行设置
function activate_service:update_valid(valid)
    self.valid = valid
end


-- 如果在暂存任务期间通过web/redfish进行设置，需要更新暂存数据
local boot_mode_config<const> = {
    [boot_def.BIOS_BOOT_LEGACY] = 0,
    [boot_def.BIOS_BOOT_UEFI] = 1
}

function activate_service:update_config_boot_mode(boot_mode)
    if not self:task_running() then
        return
    end
    log:notice('boot config activate task update boot mode: %s', boot_mode)
    self.boot_config[0].boot_type = boot_mode_config[boot_mode]
end

local effctive_time_config<const> = {
    [boot_def.EFFECTIVE_NONE] = 0,
    [boot_def.EFFECTIVE_ONCE] = 0,
    [boot_def.EFFECTIVE_FOREVER] = 1
}

function activate_service:update_effctive_time(times)
    if not self:task_running() then
        return
    end
    log:notice('boot config activate task update effctive_time: %s', times)
    self.boot_config[0].effect_opt = effctive_time_config[times]
end

function activate_service:update_start_option(start_option)
    if not self:task_running() then
        return
    end
    log:notice('boot config activate task update start_option: %s', start_option)
    self.boot_config[1].boot_dev = start_option & 0x0f
end

return singleton(activate_service)