-- Copyright (c) 2025 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 lu = require 'luaunit'

TestMp2882 = {}

function TestMp2882:setUp()
    -- 清除已加载的模块确保重新加载
    package.loaded['independent_vrd.chip.mp2882_smc'] = nil

    -- 在加载模块前先模拟依赖
    self.mock_interface = {
        get_upgrade_cnt = function(self)
            return 2, 100, 200
        end,
        get_upgrade_detail = function(self, index)
            if index == 0 then
                return { name = "VRD1", version = "1.0" }
            elseif index == 1 then
                return { name = "VRD2", version = "2.0" }
            else
                return nil
            end
        end
    }

    self.mock_signal = {
        emit = function() end
    }

    -- 创建测试上下文引用用于动态模拟
    local test_self = self

    self.mock_subcomp = {
        new = function(index, detail)
            -- 允许测试覆盖new函数行为
            if test_self.custom_subcomp_new then
                return test_self.custom_subcomp_new(index, detail)
            end
            return {
                set_ref_mcu = function(self, mcu)
                    if test_self.on_set_ref_mcu then
                        test_self.on_set_ref_mcu(mcu)
                    end
                end,
                -- 添加属性确保next(component) != nil
                index = index,
                detail = detail
            }
        end,
        register_vrd_firmware_info = function(obj, bus)
            if test_self.on_register_vrd_firmware_info then
                test_self.on_register_vrd_firmware_info(obj, bus)
            end
        end
    }

    -- 模拟mc.class类创建器
    package.loaded['mc.class'] = function(parent_class)
        local class_table = setmetatable({}, {
            __index = parent_class,
            __call = function(cls, init_data, position, signal)
                local instance = setmetatable({}, {
                    __index = cls
                })

                if init_data then
                    for k, v in pairs(init_data) do
                        instance[k] = v
                    end
                end

                instance.super = parent_class

                return instance
            end
        })

        if parent_class then
            for k, v in pairs(parent_class) do
                if type(v) == "function" then
                    class_table[k] = v
                end
            end
        end

        class_table.new = function(init_data, position, signal)
            return class_table(init_data, position, signal)
        end

        return class_table
    end

    package.loaded['mc.logging'] = {
        notice = function(format, ...)
        end
    }

    package.loaded['mcu.smc_mcu_object'] = {
        set_lib_max_size = function(self, size)
            self.lib_max_size = size
        end,
        set_bin_max_size = function(self, size)
            self.bin_max_size = size
        end,
        insert_subcomp_detail = function(self, component)
            if not self.subcomponents then
                self.subcomponents = {}
            end
            table.insert(self.subcomponents, component)
        end,
        register_firmware_info = function(self, bus)
        end
    }

    package.loaded['mcu.upgrade.sub_component'] = self.mock_subcomp

    -- 加载模块并创建测试对象
    local mp2882 = require 'independent_vrd.chip.mp2882_smc'
    self.obj = mp2882.new({
        Id = "TEST_VRD_1",
        BoardType = "TestBoard",
        RefChip = {},
        LockChip = {},
        UID = "test-uid",
        SoftwareId = "test-sw-id",
        Protocol = "SMC",
        MajorVersion = "",
        MinorVersion = "",
        Revision = "",
        SubCompList = {},
        object = {}
    }, 1, self.mock_signal)

    self.obj.interface = self.mock_interface
    self.obj.vrd_info_changed = self.mock_signal
    self.obj.mcu = { BoardType = "TestBoard" }
end

function TestMp2882:test_register_firmware_inventory_success()
    local cnt, lib_max, bin_max = self.obj.interface:get_upgrade_cnt()
    lu.assertEquals(cnt, 2)
    lu.assertEquals(lib_max, 100)
    lu.assertEquals(bin_max, 200)

    self.obj:register_firmware_inventory({})

    lu.assertNotNil(self.obj.sub_component_info_list)
    lu.assertEquals(#self.obj.sub_component_info_list, 2)
    lu.assertEquals(self.obj.vrd_load, true)
end

function TestMp2882:test_register_firmware_inventory_with_nil_detail()
    local original_get_detail = self.obj.interface.get_upgrade_detail
    self.obj.interface.get_upgrade_detail = function(self, index)
        if index == 0 then
            return { name = "VRD1", version = "1.0" }
        else
            return nil
        end
    end

    self.obj:register_firmware_inventory({})

    lu.assertEquals(#self.obj.sub_component_info_list, 1)

    self.obj.interface.get_upgrade_detail = original_get_detail
end

function TestMp2882:test_register_firmware_inventory_with_empty_component()
    self.custom_subcomp_new = function(index, detail)
        if index == 1 then
            return {}
        else
            return {
                set_ref_mcu = function(self, mcu) end,
                index = index,
                detail = detail
            }
        end
    end

    self.obj:register_firmware_inventory({})

    lu.assertEquals(#self.obj.sub_component_info_list, 2)

    self.custom_subcomp_new = nil
end

function TestMp2882:test_register_firmware_inventory_zero_count()
    self.obj.interface.get_upgrade_cnt = function(self) return 0, 0, 0 end

    self.obj:register_firmware_inventory({})

    lu.assertNotNil(self.obj.sub_component_info_list)
    lu.assertEquals(#self.obj.sub_component_info_list, 0)
    lu.assertEquals(self.obj.vrd_load, true)
end

function TestMp2882:test_register_firmware_inventory_with_component_creation()
    local ref_mcu_called = false
    local insert_subcomp_called = false

    self.on_set_ref_mcu = function(mcu)
        ref_mcu_called = true
        lu.assertEquals(mcu, self.obj)
    end

    local original_insert = self.obj.super.insert_subcomp_detail
    self.obj.super.insert_subcomp_detail = function(obj, component)
        insert_subcomp_called = true
        lu.assertEquals(obj, self.obj)
        lu.assertNotNil(component)
    end

    self.obj:register_firmware_inventory({})

    lu.assertTrue(ref_mcu_called)
    lu.assertTrue(insert_subcomp_called)

    self.on_set_ref_mcu = nil
    self.obj.super.insert_subcomp_detail = original_insert
end

function TestMp2882:test_register_firmware_inventory_subcomp_registration()
    local register_called = false
    local passed_obj = nil
    local passed_bus = { test = "bus" }

    self.on_register_vrd_firmware_info = function(obj, bus)
        register_called = true
        passed_obj = obj
        passed_bus = bus
    end

    self.obj:register_firmware_inventory(passed_bus)

    lu.assertTrue(register_called)
    lu.assertEquals(passed_obj, self.obj)
    lu.assertEquals(passed_bus.test, "bus")

    self.on_register_vrd_firmware_info = nil
end

function TestMp2882:tearDown()
    package.loaded['independent_vrd.chip.mp2882_smc'] = nil
    package.loaded['mc.class'] = nil
    package.loaded['mc.logging'] = nil
    package.loaded['mcu.smc_mcu_object'] = nil
    package.loaded['mcu.upgrade.sub_component'] = nil
end
