-- 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 custom_msg = require 'messages.custom'
local log = require 'mc.logging'
local mdb_service = require 'mc.mdb.mdb_service'
local cjson = require 'cjson'
local m = {}

local PCIECARD_INTERFACE<const> = 'bmc.kepler.Systems.PCIeDevices.PCIeCard'
local DPUCARD_INTERFACE<const> = 'bmc.kepler.Systems.DPUCard'
-- GetPath函数返回的无效路径
local INVALID_PATH<const> = ''

function m.get_members(slot, pcie_cards, ocp_cards)
    local uri_prefix = '/redfish/v1/Chassis/' .. slot .. '/PCIeDevices/'
    local members = {}

    if pcie_cards then
        for _, v in ipairs(pcie_cards) do
            local obj
            local ok, rsp = pcall(function()
                obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.PCIeDevices.PCIeCard')
            end)
            -- 对于有多个资源树路径的卡需要跳过查询失败的路径
            if not ok then
                log:debug('node id(%s) is invalid, err(%s)', v, rsp)
            else
                members[#members + 1] = {['@odata.id'] = uri_prefix .. (obj.NodeID or '')}
            end
        end
    end

    if ocp_cards then
        for _, v in ipairs(ocp_cards) do
            local obj = mdb.get_object(bus, v, 'bmc.kepler.Systems.PCIeDevices.PCIeCard')
            members[#members + 1] = {['@odata.id'] = uri_prefix .. (obj.NodeID or '')}
        end
    end

    return members
end

function m.get_count(pcie_cards, ocp_cards)
    local count = 0
    if pcie_cards then
        count = count + #pcie_cards
    end

    if ocp_cards then
        count = count + #ocp_cards
    end

    return count
end

function m.get_ExtendCardInfo(NetworkAdapters, SlotID, pf_mac_info)
    if not NetworkAdapters or not SlotID or not pf_mac_info then
        return {}
    end
    local list = {}

    for _, path in ipairs(NetworkAdapters) do
        local obj = mdb.get_object(bus, path, 'bmc.kepler.Systems.NetworkAdapter')
        if obj.ParentCardSlotId == SlotID then
            local PfMacInfoArr = {}
            for index, item in ipairs(pf_mac_info) do
                PfMacInfoArr[index] = {
                    ["Port"] = item[1] + 1,
                    ["PfId"] = item[2],
                    ["PermanentMac"] = item[3]
                }
            end
            list[#list + 1] = {
                ["ProductName"] = obj.Name,
                ["BoardId"] = obj.BoardIDHex,
                ["BoardName"] = obj.Name,
                ["Slot"] = obj.SlotNumber,
                ["PfMacInfo"] = PfMacInfoArr,
                ["Model"] = obj.Model,
                ["PCBVersion"] = obj.PCBVersion,
                ["DeviceId"] = obj.DeviceID ~= '0xFFFF' and obj.DeviceID or cjson.null,
                ["VendorId"] = obj.VendorID ~= '0xFFFF' and obj.VendorID or cjson.null,
                ["SubsystemId"] = obj.SubsystemDeviceID ~= '0xFFFF' and obj.SubsystemDeviceID or cjson.null,
                ["SubsystemVendorId"] = obj.SubsystemVendorID ~= '0xFFFF' and obj.SubsystemVendorID or cjson.null,
                ["Manufacturer"] = obj.Manufacturer,
                ["ChipManufacturer"] = obj.ChipManufacturer,
                ["Description"] = obj.ModelDescription,
            }
            break
        end
    end
    return list
end

local function get_table_len(tbl)
    if type(tbl) ~= 'table' then
        return
    end
    local count = 0
    for _, _ in pairs(tbl) do
        count = count + 1
    end
    return count
end

function m.is_dpu_card(node_id)
    -- node_id为空时应该返回404，而不应该返回400
    if not node_id then
        log:error('node_id is nil')
        return false
    end

    local filter = {NodeID = node_id}
    local ok, rsp = pcall(mdb_service.get_path, bus, PCIECARD_INTERFACE, cjson.encode(filter), true)
    -- 不是PCIe卡代表资源路径错误，返回404，不应该返回400
    if not ok then
        log:error('node id(%s) is invalid, err(%s)', node_id, rsp.message)
        return false
    end

    if rsp.Path == INVALID_PATH then
        log:error('Get invalid path')
        return false
    end

    -- 如果是PCIe卡，但是不是DPU卡，则返回400，表示不支持这个操作
    ok, rsp = pcall(mdb_service.get_object, bus, rsp.Path, {DPUCARD_INTERFACE})
    if not ok then
        log:error('Get DPUCard object failed')
        error(custom_msg.OperationFailed())
    end
    local count = get_table_len(rsp.Object)
    if not count or count == 0 then
        log:error('%s is not dpucard', node_id)
        error(custom_msg.OperationFailed())
    end
    return true
end

return m
