-- 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 skynet = require 'skynet'
local log = require 'mc.logging'
local log_def = require 'macros.log_def'
local task = require 'task_service'
local client = require 'power_mgmt.client'
local psu_service = require 'psu_service'
local class = require 'mc.class'
local singleton = require 'mc.singleton'
local utils = require 'power_mgmt_utils'


---@class power_mgmt_mock
local power_mgmt_mock = class()

function power_mgmt_mock:ctor(bus)
    self.bus = bus
    self.psu_instance = psu_service.get_instance()
    self.task = task
    self.utils_instance = utils.get_instance()
end

local MAX_TASK_NUM <const> = 10
local g_dump_task = {}

local function table_len(tb)
    local tb_len = 0
    for _, _ in pairs(tb) do
        tb_len = tb_len + 1
    end
    return tb_len
end

function power_mgmt_mock:creat_dump_task(psu_id)
    if table_len(g_dump_task) > MAX_TASK_NUM then
        error(string.format('collet ps%d failed, create task failed, exceed %d tasks', psu_id, MAX_TASK_NUM))
    end
    local path = self.psu_instance:get_psu_property(psu_id, 'path')
    local task_id, msg = self.task.create(self.bus, 'dump_psu_blackbox', path)
    if not task_id then
        error(string.format('collet ps%d failed, create task failed, msg: %s', psu_id, msg))
    end
    g_dump_task[task_id] = psu_id
    return task_id
end

function power_mgmt_mock:destroy_dump_task(task_id)
    self.task.destroy_task_by_id(task_id)
    g_dump_task[task_id] = nil
end

function power_mgmt_mock:write_ps_black_box_log(psu_id)
    local bmc_time = self.utils_instance:get_bmc_time()
    if not bmc_time then
        return
    end
    local black_box_info = self.psu_instance:psm_get_black_box_info(psu_id)
    for dev_id, value in pairs(black_box_info) do
        log:ps_black_box_print('PSU%d black box info:', dev_id)
        log:ps_black_box_print('BMC Time:%s    Power SN:%s', bmc_time, value.serial_number)
        for i = 1, value.black_box_max_length // log_def.BLACK_BOX_LINE_LEN do
            local str_tmp = value.black_box_data:sub(
                (i - 1) * log_def.BLACK_BOX_LINE_LEN + 1, i * log_def.BLACK_BOX_LINE_LEN)
            local str_len = #str_tmp
            log:ps_black_box_print(string.format('0x%03x: ' .. string.rep('0x%02x ', str_len), i - 1,
                string.unpack(string.rep('B', str_len), str_tmp)) ..
                string.rep('0x00 ', log_def.BLACK_BOX_LINE_LEN - str_len))
        end
    end
end

function power_mgmt_mock:dump_psu_blackbox(psu_id)
    local task_id = self:creat_dump_task(psu_id)
    skynet.fork_once(function ()
        self:write_ps_black_box_log(psu_id)
        skynet.timeout(500, function() -- 5s后销毁任务
            self:destroy_dump_task(task_id)
        end)
    end)
    return task_id
end


return singleton(power_mgmt_mock)
