-- 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 class = require 'mc.class'
local log = require "mc.logging"
local bs_util = require 'util.base_util'
local prop_def = require 'macros.property_def'
local file_sec = require 'utils.file'
local json = require 'cjson'
local utils = require 'mc.utils'
local bios_factory = require 'factory.bios_factory'
local obj_def = require 'macros.object_def'
local utils_core = require 'utils.core'
local client = require 'bios.client'

local generate_file = class()

local COMPONENT_POWER_TYPE<const> = 3
local SMBIOS_POWER_SUPPLY_STATUS<const> = {
    [0] = 3, -- 011 OK
    [1] = 4, -- 100 Non-critical
    [2] = 4, -- 100 Non-critical
    [3] = 5  -- 101 critical
}
local SMBIOS_POWER_SUPPLY_STATUS_UNKNOW<const> = 2

local function get_psu_header()
    local header_obj = {}
    header_obj[prop_def.BIOS_SILK_JSON_HEADER_TYPE] = "PsuInfo"
    header_obj[prop_def.BIOS_SILK_JSON_HEADER_VERSION] = 1.0
    return header_obj
end

local function get_power_mgmt_path(system_id)
    return '/bmc/kepler/Systems/' .. system_id .. '/PowerMgmt'
end

local function get_ps_component_info(component_info_list)
    client:ForeachComponentObjects(function (obj)
        if obj['Name'] == 'PS' and obj['Type'] == COMPONENT_POWER_TYPE then
            component_info_list[obj['Instance']] = obj
        end
    end)
end

local function get_psu_info(system_id)
    local power_info = {}
    local object_service = bios_factory.get_service('object_service')
    if not object_service then
        return {}
    end

    local status_info_list = object_service:get_object_list(obj_def.POWERMGMT_SERVICE_NAME,
        get_power_mgmt_path(system_id), obj_def.POWER_STATUS_INTERFACE)
    local one_power_info_list = object_service:get_object_list(obj_def.POWERMGMT_SERVICE_NAME,
        get_power_mgmt_path(system_id), obj_def.ONE_POWER_INTERFACE)
    local metrics_info_list = object_service:get_object_list(obj_def.POWERMGMT_SERVICE_NAME,
        get_power_mgmt_path(system_id), obj_def.METRICS_INTERFACE)

    local component_info_list = {}
    get_ps_component_info(component_info_list)
    local index = 1
    for _, obj in pairs(one_power_info_list) do
        power_info[index] = {}
        power_info[index]["PowerUnitGroup"] = obj["RedundancyGroupId"]:value()
        power_info[index]["Location"] = obj["DeviceLocator"]:value()
        power_info[index]["DeviceName"] = obj["Model"]:value()
        power_info[index]["Manufacturer"] = obj["Manufacturer"]:value()
        power_info[index]["SerialNumber"] = obj["SerialNumber"]:value()
        power_info[index]["AssetTagNumber"] = ""
        power_info[index]["ModelPartNumber"] = obj["PartNumber"]:value()
        power_info[index]["RevisionLevel"] = obj["FirmwareVersion"]:value()
        power_info[index]["PowerSupplyHotReplaceable"] = 1
        power_info[index]["PowerSupplyPresent"] = obj["Presence"]:value()
        power_info[index]["InputVoltageRangeSwitch"] = 4
        -- 目前所有电源都是4 Switching
        power_info[index]["PowerSupplyType"] = obj["DMTFPowerSupplyType"] and obj["DMTFPowerSupplyType"]:value() or 4
        if component_info_list[obj["SlotNumber"]:value()] then
            local health = component_info_list[obj["SlotNumber"]:value()]["Health"]
            power_info[index]["PowerSupplyStatus"] =
                SMBIOS_POWER_SUPPLY_STATUS[health] or SMBIOS_POWER_SUPPLY_STATUS_UNKNOW
        end
        index = index + 1
    end

    index = 1
    for _, obj in pairs(status_info_list) do
        power_info[index]["PowerSupplyUnplugged"] = obj["LossOfInput"]:value()
        index = index + 1
    end

    index = 1
    for _, obj in pairs(metrics_info_list) do
        power_info[index]["MaxPowerCapacity"] = obj["Rate"]:value()
        index = index + 1
    end
    return power_info
end


function generate_file.generate_psu_file(path, system_id)
    -- 删除旧的silkconfig.json文件
    local ret = bs_util.is_file_exist(path)
    if ret then
        os.remove(path)
    end

    local file_obj = {}
    file_obj["Header"] = get_psu_header()
    file_obj["PsuInfo"] = get_psu_info(system_id)

    local file_string = json.encode(file_obj)
    local file = file_sec.open_s(path, "w")
    if not file then
        return nil
    end

    file:write(file_string)
    file:close()
    utils_core.chmod_s(path, utils.S_IRUSR) -- 修改权限为400
    return file_string
end

return generate_file