-- Copyright (c) 2026 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 singleton = require 'mc.singleton'
local c_device_service = require 'device.device_service'
local c_biz_topo_service = require 'biz_topo.biz_topo_service'
local def = require 'biz_topo.def'

local mock_list = {
    ['PCIe'] = 'pcie_card_list',
    ['OCP'] = 'ocp_card_list'
}

local type_to_num = {
    ['PCIe'] = 8,
    ['OCP'] = 83
}

local pcie_mock = class()

function pcie_mock:ctor()
    self.pcie_addrinfo_list = {}
    self.pcie_device_list = {}
    self.pcie_card_list = {}
end

function pcie_mock:clear_pcie_list()
    for k, _ in pairs(self.pcie_addrinfo_list) do
        self.pcie_addrinfo_list[k] = nil
    end
    for k, _ in pairs(self.pcie_device_list) do
        self.pcie_device_list[k] = nil
    end
    for k, _ in pairs(self.pcie_card_list) do
        self.pcie_card_list[k] = nil
    end
end

function pcie_mock:update_pcie_info(device_type)
    self:clear_pcie_list()
    -- 遍历PCIeAddrInfo
    for _, addr_info in ipairs(c_biz_topo_service.get_instance().biz_topo.pcie_addr_info_list) do
        if addr_info.mds_obj.ComponentType == type_to_num[device_type] and 
            addr_info.mds_obj.SlotID ~= 255 and addr_info.mds_obj.SlotID ~= 0 then
            self.pcie_addrinfo_list[addr_info.mds_obj.SlotID] = true
        end
    end
    -- 遍历PCIeDevice
    for _, device in ipairs(c_device_service.get_instance().pcie_device_list) do
        if device.mds.DeviceType == type_to_num[device_type] then
            self.pcie_device_list[device.mds.SlotID] = true
        end
    end
    -- 遍历PCIeCard
    for _, card in ipairs(c_device_service.get_instance()[mock_list[device_type]]) do
        self.pcie_card_list[card.mds.SlotID] = card.mds.Name
    end
end

function pcie_mock:mock_get_connector(device_type)
    local result = {}
    local ok, connector
    self:update_pcie_info(device_type)
    for slot, _ in pairs(self.pcie_addrinfo_list) do
        ok, connector = c_biz_topo_service.get_instance().biz_topo:get_mgmt_connector(
                                        def.com_type_to_type[type_to_num[device_type]], slot)
        if not ok or not connector then
            goto continue
        end
        -- 还未加载
        if not self.pcie_device_list[slot] then
            result[#result + 1] = {SlotNumber = slot, Presence = 'Absent', Name = '',
                                        Id = connector.Id, AuxId = connector.AuxId}
        else
            if not self.pcie_card_list[slot] then
                result[#result + 1] = {SlotNumber = slot, Presence = 'Present', Name = '',
                                        Id = connector.Id, AuxId = connector.AuxId}
            else
                result[#result + 1] = {SlotNumber = slot, Presence = 'Present', Name = self.pcie_card_list[slot],
                                        Id = connector.Id, AuxId = connector.AuxId}
            end
        end
        ::continue::
    end
    return result
end

function pcie_mock:mock_load_device(device_type, slot, id, auxid)
    self:update_pcie_info(device_type)
    -- 已有pcie设备，则不再加载
    if self.pcie_device_list[slot] then
        error("This PCIe device has been loaded")
    end
    local ok, connector = c_biz_topo_service.get_instance().biz_topo:get_mgmt_connector(
                                def.com_type_to_type[type_to_num[device_type]], slot)
    if not ok or not connector then
        error("Can not match the connector")
    end
    connector.Id = id
    connector.AuxId = auxid
    connector.Presence = 0
    connector.Presence = 1
end

function pcie_mock:mock_unload_device(device_type, slot)
    self:update_pcie_info(device_type)
    -- 未加载的PCIe设备，不需要卸载
    if not self.pcie_device_list[slot] then
        error("Can not unload a PCIe device that has not been loaded")
    end
    local ok, connector = c_biz_topo_service.get_instance().biz_topo:get_mgmt_connector(
                                def.com_type_to_type[type_to_num[device_type]], slot)
    if not ok or not connector then
        error("Can not match the connector")
    end
    connector.Presence = 0
end

return singleton(pcie_mock)