-- 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 lu = require 'luaunit'
local ncsi_protocol_intf = require 'ncsi_protocol_intf'
local ncsi_utils = require 'ncsi.ncsi_protocol.ncsi_utils'
local ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_parameter = require 'ncsi.ncsi_protocol.ncsi_parameter'

-- 测试套件
TestNCSIPackage = {}

-- 命令类型常量定义
local SELECT_PACKAGE = 0x01
local SELECT_PACKAGE_RSP = 0x81
local DESELECT_PACKAGE = 0x02
local DESELECT_PACKAGE_RSP = 0x82

-- 初始化全局NCSI参数
local mock_ncsi_parameter = {
    package_exist = {},
    channel_exist = {},
    iid = 1,  -- 添加iid字段，这是NCSI协议需要的包ID
    channel_cnt = 4,  -- 添加channel_cnt字段
    recv_buf = ''     -- 添加recv_buf字段
}
for i = 0, 7 do
    mock_ncsi_parameter.channel_exist[i] = {}
end

-- 保存原始的get_ncsi_parameter函数
local original_get_ncsi_parameter = ncsi_parameter.get_instance().get_ncsi_parameter

-- 替换get_ncsi_parameter函数
ncsi_parameter.get_instance().get_ncsi_parameter = function() 
    return mock_ncsi_parameter
end

-- 重新加载ncsi_package模块以使用mock参数
package.loaded['ncsi.ncsi_protocol.ncsi_package'] = nil
local ncsi_package = require 'ncsi.ncsi_protocol.ncsi_package'

-- 模拟发送NCSI命令的函数
local function mock_send_ncsi_cmd(req_data, len, eth_name)
    TestNCSIPackage.last_req_data = req_data
    TestNCSIPackage.last_len = len
    TestNCSIPackage.last_eth_name = eth_name
    return 0
end

-- 初始化函数，在每个测试用例前执行
function TestNCSIPackage:setUp()
    ncsi_parameter.get_instance():init_ncsi_parameter()
    -- 保存原始函数
    self.original_send_ncsi_cmd = ncsi_protocol_intf.send_ncsi_cmd
    self.original_cmd_ctrl = ncsi_utils.ncsi_cmd_ctrl

    -- 使用模拟函数替换原始函数
    ncsi_protocol_intf.send_ncsi_cmd = mock_send_ncsi_cmd

    -- 初始化测试变量
    self.last_req_data = nil
    self.last_len = nil
    self.last_eth_name = nil

    -- 清空mock参数的状态
    for k in pairs(mock_ncsi_parameter.package_exist) do
        mock_ncsi_parameter.package_exist[k] = nil
    end

    -- 模拟cmd_ctrl函数以便测试
    ncsi_utils.ncsi_cmd_ctrl = function(_, _, req_packet, eth_name, cmd_process_table)
        -- 确保cmd_process_table存在
        assert(cmd_process_table, "cmd_process_table is nil")

        -- 调用请求处理函数
        if req_packet and req_packet.packet_head and req_packet.packet_head.packet_type and
           cmd_process_table[req_packet.packet_head.packet_type] then
            cmd_process_table[req_packet.packet_head.packet_type](req_packet, eth_name)
        end

        -- 返回成功
        return ncsi_def.NCSI_SUCCESS
    end
end

-- 清理函数，在每个测试用例后执行
function TestNCSIPackage:tearDown()
    -- 恢复原始函数
    ncsi_protocol_intf.send_ncsi_cmd = self.original_send_ncsi_cmd
    ncsi_utils.ncsi_cmd_ctrl = self.original_cmd_ctrl
end

-- 全局清理函数，在所有测试结束后执行
function TestNCSIPackage.tearDownClass()
    -- 恢复原始的get_ncsi_parameter函数
    ncsi_parameter.get_instance().get_ncsi_parameter = original_get_ncsi_parameter
end

-- 测试选择包功能
function TestNCSIPackage:test_select_package()
    -- 测试参数
    local package_id = 0
    local eth_name = "eth0"

    -- 执行测试
    local result = ncsi_package.ncsi_select_package(package_id, eth_name)

    -- 验证结果
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)
    lu.assertNotNil(self.last_req_data)
    lu.assertEquals(self.last_eth_name, eth_name)
    lu.assertEquals(mock_ncsi_parameter.package_exist[package_id], 1)

    -- 测试不同的package_id
    self.last_req_data = nil
    result = ncsi_package.ncsi_select_package(1, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)
    lu.assertNotNil(self.last_req_data)
    lu.assertEquals(mock_ncsi_parameter.package_exist[1], 1)
end

-- 测试取消选择包功能
function TestNCSIPackage:test_deselect_package()
    -- 测试参数
    local package_id = 0
    local eth_name = "eth0"

    -- 执行测试
    local result = ncsi_package.ncsi_deselect_package(package_id, eth_name)

    -- 验证结果
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)
    lu.assertNotNil(self.last_req_data)
    lu.assertEquals(self.last_eth_name, eth_name)

    -- 测试不同的package_id
    self.last_req_data = nil
    result = ncsi_package.ncsi_deselect_package(1, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)
    lu.assertNotNil(self.last_req_data)
end

-- 测试响应处理
function TestNCSIPackage:test_response_processing()
    -- 模拟响应包
    local function create_mock_response(rsp_code, reason_code, packet_type)
        local rsp = {packet_head = {}, payload = ''}
        rsp.packet_head.payload_len_hi = 0
        rsp.packet_head.payload_len_lo = 4
        rsp.packet_head.packet_type = packet_type

        -- 创建响应payload
        local rsp_data = string.char(
            (rsp_code >> 8) & 0xFF, rsp_code & 0xFF,  -- rsp_code (2字节)
            (reason_code >> 8) & 0xFF, reason_code & 0xFF,  -- reason_code (2字节)
            0, 0, 0, 0  -- check_sum (4字节)
        ) .. string.rep("\0", 22)  -- pad_data (22字节)

        rsp.payload = rsp_data
        return rsp
    end

    -- 测试参数
    local package_id = 0
    local eth_name = "eth0"

    -- 测试成功响应
    local success_rsp_select = create_mock_response(ncsi_def.CMD_COMPLETED, 0, SELECT_PACKAGE_RSP)
    local success_rsp_deselect = create_mock_response(ncsi_def.CMD_COMPLETED, 0, DESELECT_PACKAGE_RSP)
    
    local original_cmd_ctrl = ncsi_utils.ncsi_cmd_ctrl

    -- 测试选择包的成功响应
    ncsi_utils.ncsi_cmd_ctrl = function(_, _, req_packet, _, cmd_process_table)
        if req_packet.packet_head.packet_type == SELECT_PACKAGE then
            return cmd_process_table[SELECT_PACKAGE_RSP](success_rsp_select)
        else
            return cmd_process_table[DESELECT_PACKAGE_RSP](success_rsp_deselect)
        end
    end

    local result = ncsi_package.ncsi_select_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)

    -- 测试取消选择包的成功响应
    result = ncsi_package.ncsi_deselect_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_SUCCESS)

    -- 测试失败响应
    local fail_rsp_select = create_mock_response(0x0123, 1, SELECT_PACKAGE_RSP)
    local fail_rsp_deselect = create_mock_response(0x0123, 1, DESELECT_PACKAGE_RSP)
    
    ncsi_utils.ncsi_cmd_ctrl = function(_, _, req_packet, _, cmd_process_table)
        if req_packet.packet_head.packet_type == SELECT_PACKAGE then
            return cmd_process_table[SELECT_PACKAGE_RSP](fail_rsp_select)
        else
            return cmd_process_table[DESELECT_PACKAGE_RSP](fail_rsp_deselect)
        end
    end

    result = ncsi_package.ncsi_select_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_FAIL)

    result = ncsi_package.ncsi_deselect_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_FAIL)

    -- 恢复原始函数
    ncsi_utils.ncsi_cmd_ctrl = original_cmd_ctrl
end

-- 测试错误处理
function TestNCSIPackage:test_error_handling()
    -- 模拟cmd_ctrl返回失败
    local original_cmd_ctrl = ncsi_utils.ncsi_cmd_ctrl
    ncsi_utils.ncsi_cmd_ctrl = function(_, _, _, _, _)
        return ncsi_def.NCSI_FAIL
    end

    -- 测试参数
    local package_id = 0
    local eth_name = "eth0"

    -- 测试选择包失败
    local result = ncsi_package.ncsi_select_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_FAIL)

    -- 测试取消选择包失败
    result = ncsi_package.ncsi_deselect_package(package_id, eth_name)
    lu.assertEquals(result, ncsi_def.NCSI_FAIL)

    -- 恢复原始函数
    ncsi_utils.ncsi_cmd_ctrl = original_cmd_ctrl
end