-- 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 detection_path = '/bmc/kepler/Chassis/1/ThermalSubsystem/LeakDetection'
local detection_interface = 'bmc.kepler.Chassis.LeakDetection'
local log = require 'mc.logging'
local m = {}

function m.if_unknown_to_null(str)
    local str_lower = string.lower(str)
    local unknown = {
        ['n/a'] = true,
        ['unknown'] = true,
        ['null'] = true
    }
    if unknown[str_lower] or str == nil or string.len(str) == 0 then
        return cjson.null
    end

    return str
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

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_chassis_type_str(chassis_type, software_type)
    if chassis_type == 0 then
        return "Rack"
    end
    if chassis_type == 1 or chassis_type == 2 or
        (chassis_type == 5 and software_type == 2) then
        return "Blade"
    end
    if chassis_type == 4 then
        return "Module"
    end
    return "Other"
end

function m.get_drives_summary_info(members)
    local health_code = 0
    local count = 0

    for _, path in ipairs(members) do
        local drive = mdb.get_object(bus, path, 'bmc.kepler.Systems.Storage.Drive')
        local drive_status = mdb.get_object(bus, path, 'bmc.kepler.Systems.Storage.Drive.DriveStatus')

        if drive.Presence == 1 then
            count = count + 1
        end

        if drive.Presence == 1 and drive_status.Health > health_code then
            health_code = drive_status.Health
        end
    end

    return {
        Count = count,
        Severity = get_drives_severity(health_code),
        HealthRollup = get_drives_health(health_code)
    }
end

function m.get_status_health(paths, interface)
    local health = 0
    for _, v in ipairs(paths) do
        local obj = mdb.get_object(bus, v, interface)
        if obj.Health and obj.Health > health then
            health = obj.Health
        end
    end
    return get_drives_health(health)
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_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

function m.get_chassis_status_by_name(objs, name)
    local status = cjson.json_object_new_object()
    local health = 0
    local component_chassis = {}
    for _, obj in ipairs(objs) do
        if obj.Name == name then
            if obj.Health and obj.Health >= health then
                health = obj.Health
                component_chassis = obj
            end
        end
    end
    status['State'] = component_chassis.Presence == 1 and 'Enabled' or 'Disabled'
    local oem = cjson.json_object_new_object()
    local chassis_info = cjson.json_object_new_object()
    chassis_info['Severity'] = get_drives_severity(health)
    oem['{{OemIdentifier}}'] = chassis_info
    status['Oem'] = oem
    status['Health'] = get_drives_health(health)
    return status
end

-- 是否支持漏液检测
function m.get_leakdetect_support()
    -- 确认资源树对象
    local ok, obj = pcall(mdb.get_object, bus, detection_path, detection_interface)
    local prop_name = 'Oem/{{OemIdentifier}}/LeakStrategy'
    local err = custom_messages.PropertyModificationNotSupported(prop_name)
    err.RelatedProperties = {'#/' .. prop_name}

    if not ok then
        log:error('Get leak detection obj failed, err_msg: %s', obj)
        error(err)
    end

    -- 确认是否支持漏液下电设置动作
    if obj.Enabled ~= true then
        log:error("Don't support leakage detection")
        error(err)
    end
    return true
end

return m
