-- 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 cjson = require 'cjson'
local log = require 'mc.logging'
local mdb_service = require 'mc.mdb.mdb_service'

local COMPONENT_TYPE_FAN<const> = 4

local m = {}

function m.get_power_capacity_watts_and_npu_watts(power_list, npu_paths)
    local watts = m.get_power_capacity_watts(power_list)
    for _, path in ipairs(npu_paths) do
        local obj = mdb.get_object(bus, path, "bmc.kepler.Systems.Board.NpuBoard")
        watts = watts + obj.MaxPowerCapWatts
    end

    return watts
end

function m.get_power_capacity_watts(power_list)
    local watts = 0
    for _, path in ipairs(power_list) do
        local metrics = mdb.get_object(bus, path, 'bmc.kepler.Systems.PowerMgmt.OnePower.Metrics')
        if metrics ~= nil then
            watts = watts + metrics.Rate
        end
    end

    return watts
end

function m.get_present_psu_num(power_list)
    local present = 0
    for _, path in ipairs(power_list) do
        local one_power = mdb.get_object(bus, path, 'bmc.kepler.Systems.PowerMgmt.OnePower')
        if one_power ~= nil and one_power.Presence == 1 then
            present = present + 1
        end
    end

    return present
end

function m.get_present_fan_num(objs)
    local present = 0
    for _, obj in ipairs(objs) do
        if obj.Type == COMPONENT_TYPE_FAN then
            if obj.Presence ~= 1 or obj.Name == 'Fan' then
                goto continue
            end
            present = present + 1
        end
        ::continue::
    end

    return present
end

function m.get_power_count(input)
    local present = 0
    for _, device in pairs(input) do
        if device[1] == 'Psu' then
            present = device[2]
            break
        end
    end

    return present
end

local function get_drives_severity(health_code)
    local severity = {
        [0] = 'Informational',
        [1] = 'Minor',
        [2] = 'Major',
        [3] = 'Critical'
    }

    if severity[health_code] == nil then
        return cjson.null
    end

    return severity[health_code]
end

function m.get_severity_by_type(objs, type)
    local health = 0
    for _, obj in ipairs(objs) do
        if obj.Type == type then
            if obj.Health and obj.Health > health then
                health = obj.Health
            end
        end
    end
    return get_drives_severity(health)
end

local function get_drives_health(health_code)
    local health = {
        [0] = 'OK',
        [1] = 'Warning',
        [2] = 'Warning',
        [3] = 'Critical'
    }

    if health[health_code] == nil then
        return cjson.null
    end

    return health[health_code]
end

function m.get_status_health_by_type(objs, type)
    local health = 0
    for _, obj in ipairs(objs) do
        if obj.Type == type then
            if obj.Health and obj.Health > health then
                health = obj.Health
            end
        end
    end
    return get_drives_health(health)
end

function m.get_fan_components()
    local fan_component_objs = {}
    local component_paths = mdb_service.get_sub_paths(bus, '/bmc/kepler/Systems/1/Components', 1,
        { 'bmc.kepler.Systems.Component' }).SubPaths
    for _, path in pairs(component_paths) do
        local component_obj = mdb.get_object(bus, path, 'bmc.kepler.Systems.Component')
        if component_obj.Type == COMPONENT_TYPE_FAN then
            table.insert(fan_component_objs, {
                Name = component_obj.Name,
                Presence = component_obj.Presence,
                Health = component_obj.Health,
                Type = component_obj.Type
            })
        end
    end
    return fan_component_objs
end

function m.get_fan_infos(fan_component_objs)
    local present = 0
    local health = 0
    for _, fan_obj in ipairs(fan_component_objs) do
        if fan_obj.Type == COMPONENT_TYPE_FAN then
            if fan_obj.Presence ~= 1 or fan_obj.Name == 'Fan' then
                goto continue
            end
            present = present + 1
        end
        ::continue::
        if fan_obj.Type == COMPONENT_TYPE_FAN then
            if fan_obj.Health and fan_obj.Health > health then
                health = fan_obj.Health
            end
        end
    end
    local res = cjson.json_object_new_object()
    res[1] = present
    res[2] = get_drives_severity(health)
    res[3] = get_drives_health(health)
    return res
end

return m
