-- 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 log = require 'mc.logging'
local cjson = require 'cjson'
local custom_messages = require 'messages.custom'
local lower = string.lower

local m = {
    i_types = {
        [5] = 'DiskBackplane',
        [6] = 'RAIDCard',
        [11] = 'MezzCard',
        [14] = 'MemoryBoard',
        [15] = 'PCIeRiserCard',
        [22] = 'ChassisBackplane',
        [24] = 'FanBackplane',
        [25] = 'IOBoard',
        [35] = 'IOBoard',
        [36] = 'CPUBoard',
        [38] = 'PCIeTransformCard',
        [45] = 'M2TransformCard',
        [50] = 'ExpandBoard',
        [64] = 'GPUBoard',
        [67] = 'PassThroughCard',
        [76] = 'HorizontalConnectionBoard',
        [84] = 'LeakageDetectionCard',
        [87] = 'CICCard',
        [88] = 'ExpansionModule',
        [89] = 'FanModule',
        [90] = 'ARCard',
        [92] = 'SoCBoard',
        [93] = 'ExpandBoard'
    },
    s_types = {
        CpuBoard = 'CPUBoard',
        NpuBoard = 'NPUBoard',
        ExpBoard = 'ExpandBoard',
        FanBoard = 'FanBackplane',
        HddBackplane = 'DiskBackplane',
        RiserCard = 'PCIeRiserCard',
        PsuBoard = 'PsuBoard',
        PeuBoard = 'PeuBoard',
        M2TransferCard = 'M2TransferCard'
    }
}

function m.get_boards(slot, paths)
    local boards = {}
    for _, v in ipairs(paths) do
        local obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.Board')
        if obj.FruID ~= 255 then
            local node_id = ''
            local ok, ret = pcall(string.gsub, obj.NodeId, '%s+', '')
            if ok then
                node_id = ret
            end
            boards[#boards + 1] = {
                ['@odata.id'] = '/redfish/v1/Chassis/' .. slot .. '/Boards/' .. node_id
            }
        end
    end
    table.sort(boards, function(a, b) return a['@odata.id'] < b['@odata.id'] end)
    return boards
end


function m.get_npus(systemid, deviceName)
    local NPU_MDB_INTF <const> = 'bmc.kepler.Systems.Processor'
    local NPU_MDB_PATH <const> = '/bmc/kepler/Systems/'..systemid..'/Processors/NPU'
    local npus = {}
    local npu_objs = mdb.get_sub_objects(bus, NPU_MDB_PATH, NPU_MDB_INTF)
    for _, obj in pairs(npu_objs) do
        if string.find(deviceName, obj.Position) then
            npus[#npus + 1] = {
                ['@odata.id'] = '/redfish/v1/Systems/' .. systemid .. '/Processors/NPU' .. obj.Id
            }
        end
    end
    table.sort(npus, function(a, b) return a['@odata.id'] < b['@odata.id'] end)
    return npus
end

function m.get_card_no(input)
    if string.find(input, 'M2TransferCard') then
        local input_ret = string.match(input, 'M2TransferCard(.*)')
        return string.match(input_ret, '%d+') or '0'
    end
    return string.match(input, '%d+') or '0'
end

function m.get_oem_boards(slot, paths, deviceArr)
    local oem_boards = cjson.json_object_new_object()
    local device_max_num = {
        CPUBoard = nil,
        PCIeRiserCard = nil,
        ExpandBoard = nil,
        FanBackplane = nil,
        DiskBackplane = nil,
        PsuBoard = nil,
        PeuBoard = nil,
        M2TransferCard = nil
    }
    for _, v in ipairs(deviceArr) do
        device_max_num[v[1]] = v[2]
    end
    local get_board = function(obj)
        local property_name = m.s_types[obj.BoardType or '']
        if not property_name then
            log:info('Invalid board type:%s', obj.BoardType)
            return
        end
        if device_max_num[property_name] ~= 0 then
            if not oem_boards[property_name] then
                oem_boards[property_name] = cjson.json_object_new_object()
            end
            oem_boards[property_name]['MaxNumberSupported'] = device_max_num[property_name] or cjson.null
            local link = cjson.json_object_new_object()
            link['@odata.id'] = '/redfish/v1/Chassis/' .. slot .. '/Boards/' .. obj.NodeId
            local links
            if not oem_boards[property_name]['Links'] then
                links = cjson.json_object_new_array()
                oem_boards[property_name]['Links'] = cjson.json_object_new_object()
            else
                links = oem_boards[property_name]['Links']
            end
            links[#links+1] = link
            oem_boards[property_name]['Links'] = links
        end
    end

    for _, v in ipairs(paths) do
        local obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.Board')
        if obj.FruID ~= 255 then
            get_board(obj)
        end
    end

    return oem_boards
end

function m.get_board_path(member_id, paths)
    for _, v in ipairs(paths) do
        local obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.Board')
        local nodeid = string.gsub(obj.NodeId, "%s+", "")
        if obj.FruID ~= 255 and lower(member_id) == lower(nodeid) then
            return v
        end
    end

    log:error('Did not find board, member_id:%s', member_id)
end

function m.get_all_health_info(location, name, paths)
    local health = nil

    for _, v in ipairs(paths) do
        local obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.Component')
        if obj.Location == location and obj.Name == name then
            if not health or obj.Health > health then
                health = obj.Health
            end
        end
    end

    return health
end

return m
