-- 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'
local defs = require 'independent_vrd.ind_vrd_defs'
local file_sec = require 'utils.file'
local utils = require 'mc.utils'

local DATA_PATH <const> = './test_data/vrd_upgrade/'

-- 测试套件
TestMp2882Pmbus = {}

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

-- Mock辅助函数
local function setup_mocks()
    -- 保存原始模块
    local originals = {}
    originals.skynet = package.loaded['skynet']
    originals.mc_crc8 = package.loaded['mc.crc8']
    originals.mp2882_pmbus = package.loaded['independent_vrd.chip.mp2882_pmbus']

    -- 设置mock
    package.loaded['skynet'] = require 'skynet'
    package.loaded['mc.crc8'] = require 'mc.crc8'

    return originals
end

local function restore_mocks(originals)
    package.loaded['skynet'] = originals.skynet
    package.loaded['mc.crc8'] = originals.mc_crc8
    package.loaded['independent_vrd.chip.mp2882_pmbus'] = nil
end

-- 创建mock chip对象
local function create_mock_chip(addr)
    addr = addr or 0x40
    -- 模拟page寄存器默认在page 0h
    local page = 0
    return {
        Read = function(self, ctx, cmd, len)
            local crc8 = package.loaded['mc.crc8']
            local head = string.char(addr, cmd, addr | 1)
            -- Mock返回版本号，低字节1，高字节2
            local data = string.char(1, 2)
            -- Mock返回cml_status
            if cmd == 0x7e then
                data = string.char(0x11)
            end
            -- Mock读页号
            if cmd == 0x00 then
                data = string.char(page)
            end
            local full = head .. data
            local crc_val = crc8(full)
            return data .. string.char(crc_val)
        end,
        Write = function(self, ctx, cmd, data)
            -- Mock写页寄存器
            if cmd == 0x00 then
                page = string.byte(data, 1)
            end
            return true
        end,
        PluginRequest = function(self, ctx, plugin, method, args)
            local skynet = require 'skynet'
            return skynet.packstring(true)
        end
    }
end

-- 创建mp2882实例并返回模块引用
local function create_mp2882_instance()
    local mp2882 = require 'independent_vrd.chip.mp2882_pmbus'
    local obj = {
        VrdId = 1,
        UID = 'test_uid',
        Address = 0x40,
        RefChip = create_mock_chip(0x40),
        ValidateReg = 0,
        UpgradeFileName = {
            FirmwareFileName = 'mp2882_pmbus.txt'
        }
    }
    local tab = { object = obj }
    local instance = mp2882.new(tab, 1)
    return instance, mp2882
end

-- 测试：mp2882_select_page
function TestMp2882Pmbus:test_mp2882_select_page()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()
    local result = instance:mp2882_select_page(instance.obj.RefChip, 1, instance.obj.Address)
    lu.assertEquals(result, 0)

    instance.obj.RefChip.Read = function(self, ctx, cmd, len)
            -- 切页回读失败
            return string.char(0x00, 0x00)
        end
    result = instance:mp2882_select_page(instance.obj.RefChip, 1, instance.obj.Address)
    lu.assertEquals(result, -1)

    instance.obj.RefChip.Write = function(self, ctx, cmd, data)
            -- 切页写失败
            return false
        end 
    result = instance:mp2882_select_page(instance.obj.RefChip, 1, instance.obj.Address)
    lu.assertEquals(result, -1)

    restore_mocks(originals)
end

-- 测试：get_version
function TestMp2882Pmbus:test_get_version()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()
    local version = instance:get_version()
    lu.assertNotNil(version)
    lu.assertEquals(type(version), 'number')
    -- 版本号取高字节
    lu.assertEquals(version, 2)

    instance.obj.RefChip.Read = function(self, ctx, cmd, len)
            -- 切页回读失败
            return string.char(0x00, 0x00)
        end
    version = instance:get_version()
    lu.assertEquals(version, '')
    restore_mocks(originals)
end

-- 测试：check_chip_accessible
function TestMp2882Pmbus:test_check_chip_accessible()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()

    local result = instance:check_chip_accessible()
    lu.assertTrue(result)

    restore_mocks(originals)
end

-- 测试：check_chip_accessible - 失败场景
function TestMp2882Pmbus:test_check_chip_accessible_no_refchip()
    local originals = setup_mocks()
    local mp2882 = require 'independent_vrd.chip.mp2882_pmbus'
    local obj = {
        VrdId = 1,
        UID = 'test_uid',
        Address = 0x40,
        RefChip = nil
    }
    local tab = { object = obj }
    local instance = mp2882.new(tab, 1)

    local result = instance:check_chip_accessible()
    lu.assertFalse(result)

    restore_mocks(originals)
end

-- 测试： read_data_from_data_file
function TestMp2882Pmbus:test_read_data_from_data_file()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()
    local file = DATA_PATH .. 'mp2882_pmbus.txt'
    local ret, data = instance:read_data_from_data_file(utils.realpath(file), 3072)

    -- 解析完数据一定为长度3072字节，索引从0开始的表
    lu.assertEquals(ret, defs.RET.OK)
    lu.assertEquals(data[0], 0)
    lu.assertEquals(data[512], 0)
    lu.assertEquals(data[3069], 90)
    lu.assertEquals(data[3070], 3)
    lu.assertEquals(data[3071], 122)
    lu.assertEquals(data[3072], nil)

    restore_mocks(originals)
end

-- 测试： upgrade
function TestMp2882Pmbus:test_upgrade()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()
    local path = utils.realpath(DATA_PATH) .. '/'
    local ret = instance:upgrade(path)
    lu.assertEquals(ret, defs.RET.OK)

    restore_mocks(originals)
end

-- 测试：valid_vrd
function TestMp2882Pmbus:test_valid_vrd()
    local originals = setup_mocks()
    local instance = create_mp2882_instance()

    local result = instance:valid_vrd()
    lu.assertEquals(result, defs.RET.OK)
    lu.assertEquals(instance.obj.ValidateReg, 1)

    instance.obj.ValidateReg = nil
    result = instance:valid_vrd()
    lu.assertEquals(result, defs.RET.ERR)

    restore_mocks(originals)
end