-- 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 c_optical_module = require 'device.class.optical_module'
local fructl = require 'infrastructure.fructl'
local skynet = require 'skynet'
local npu_imu_cmd = require 'npu.hdk_cmd'
local npu_om_event_debounce_config = require 'event.debounce_config.npu_om'

TEST_optical_module = {}

function TEST_optical_module:test_reset_npu_om()
    c_optical_module:reset_npu_om()
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0xFFFF)
end

function TEST_optical_module:test_get_optical_temp_scheduler()    
    c_optical_module.ncsi_config_obj = {
        channel_id = 1,
        package_id = 1,
        test1 = {respons_first = "test_func", value = function ()
            return "test_func"
        end},
        test2 = {respons_second = "test2", value = function ()
            return nil
        end},
        test_func = function(obj, t)
            return t
        end,
    }
    function c_optical_module.ncsi_config_obj:OpticalGetIdentifier(t1)
        if t1.channel_id == self.channel_id then
            return self.test1
        end
        return self.test2
    end
    function c_optical_module.ncsi_config_obj:OpticalTemp(t1)
        return t1
    end
    c_optical_module.PortID = 2
    c_optical_module.package_id = 2
    local ret = c_optical_module:get_optical_temp_scheduler()
    lu.assertEquals(ret.channel_id, 2)
    lu.assertEquals(ret.package_id, 2)
    c_optical_module.PortID = 1
    c_optical_module.package_id = 1
    local ret = c_optical_module:get_optical_temp_scheduler()
    lu.assertEquals(ret.channel_id, 1)
    lu.assertEquals(ret.package_id, 1)
end

function TEST_optical_module:test_get_info_from_imu_task()
    fructl.get_power_status = function()
        return "OFF"
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 0})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0xFFFF)

    fructl.get_power_status = function()
        return "ON"
    end
    c_optical_module.is_npu_heartbeat_loss = true
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})

    c_optical_module.is_npu_heartbeat_loss = false
    c_optical_module.init_npu_optical_module_info = function()
        c_optical_module.MediaInterfaceFaultStatus = 0x00
        return false, "test error"
    end
    npu_imu_cmd.get_optical_info_from_imu = function()
        return false;
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0x00)
    c_optical_module.init_npu_optical_module_info = function(id)
        c_optical_module.MediaInterfaceFaultStatus = 0x01
        return id[1]
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0x01)

    local c_get_parent = c_optical_module.get_parent
    local c_init = c_optical_module.init
    local c_check_info_from_imu = c_optical_module.check_info_from_imu
    c_optical_module.get_parent = function()
        return {}
    end
    c_optical_module.init = function()
        return {}
    end
    local count = 0
    c_optical_module.check_info_from_imu = function()
        count = count + 1
        if count > 1 then
            error("count 1")
        end
    end
    pcall(c_optical_module.get_info_from_imu_task, c_optical_module)
    c_optical_module.get_parent = c_get_parent
    c_optical_module.init = c_init
    c_optical_module.check_info_from_imu = c_check_info_from_imu
end

function TEST_optical_module:test_update_prbs_test_info()
    c_optical_module.init_npu_optical_module_info = function(id)
        c_optical_module.SerialNumber = '035JUALDQ5003303'
        c_optical_module.Presence = 1
        c_optical_module.PRBSTestSupported = nil
        return id[1]
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.SerialNumber = '035JUALDQ5003304'
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.SerialNumber = ''
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.Presence = 0
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)
end

function TEST_optical_module:test_npu_om_event_conf()
    local npu_om = npu_om_event_debounce_config 
    lu.assertNotEquals(npu_om, nil)
    local om_obj = {
        get_parent = function()
            return {
                get_parent = function()
                    return {
                        Name = 1,
                    }
                end,
                NpuID = 1
            }
        end
    }
    local event_test = {}
    local function test_event(event)       
            event_test.EventKeyId = event.EventKeyId
            event_test.SubjectType = event.SubjectType
            if event.EventCode == "0x29000017" or event.EventCode == "0x29000011" then
                    om_obj[event.prop_names[1]] = {1, 2, 3, 5, 6, 7, 8, 9, 10}
                    om_obj[event.prop_names[2]] = 3
                    om_obj[event.prop_names[3]] = 0
            else
                for k, prop in ipairs(event.prop_names) do                
                    om_obj[prop] = k
                end
            end
            event_test.type = event.type
            event_test.cont_num = event.cont_num
            event_test.trigger_fun = event.trigger_fun
            event_test.get_args = event.get_args
            event_test.trigger_fun = event.trigger_fun
            lu.assertNotEquals(event_test.trigger_fun(om_obj), nil)
            lu.assertNotEquals(event.get_args(om_obj), nil)
    end
    for _, events in pairs(npu_om) do
        for _, event in pairs(events) do
            test_event(event)
        end
    end
end

function TEST_optical_module:test_mctp()
    c_optical_module.schedulers = {}
    c_optical_module.connect_signal = function () end
    local mctp_obj = {
        OpticalModuleInfo = function()
            return {
                on_data_change = {
                    on = function(data) end
                },
                start = function () end
            }
        end,
        OpticalTemp = function()
            return {
                on_data_change = {
                    on = function(data) end
                },
                start = function () end
            }
        end
    }
    c_optical_module:update_ncsi_properties(mctp_obj, 1)
    c_optical_module:update_optical_temp_by_ncsi()
    c_optical_module:update_NSCI_optical_module_info()
end