local lu = require 'luaunit'
local retimer_agent = require 'retimer.agent.retimer_agent_jbog_retimer'
local skynet = require 'skynet'
local signal_monitor = require 'signal_monitor'
local event = require 'infrastructure.event'
local factory = require 'factory'
local smc = require 'protocol.smc'
local common_interface = require 'common_interface'

TestRetimerAgentJbogRetimer = {}

function TestRetimerAgentJbogRetimer:test_start()
    local orig_get_instance = signal_monitor.get_instance
    local orig_get_retimer_firmware_load_status = retimer_agent.get_retimer_firmware_load_status
    
    signal_monitor.get_instance = function()
        return {
            on_os_state_changed = {
                on = function(_, cb)
                    cb(true)
                end
            }
        }
    end
    skynet.sleep = function()
    end
    retimer_agent.monitor_task = true
    retimer_agent.box_i2c_access_moitor_task = true
    retimer_agent.get_retimer_firmware_load_status = function()
        return 0x01
    end
    local origin_start_set_box_id_to_box = retimer_agent.start_set_box_id_to_box
    local origin_start_monitor_bmc_properties = retimer_agent.start_monitor_bmc_properties
    retimer_agent.start_set_box_id_to_box = function()
        return 0
    end
    retimer_agent.start_monitor_bmc_properties = function()
        return 0
    end
    local ret = retimer_agent:start()
    lu.assertEquals(ret, nil)
    retimer_agent.get_retimer_firmware_load_status = function()
        return 0
    end
    ret = retimer_agent:start()
    lu.assertEquals(ret, nil)
    signal_monitor.get_instance = orig_get_instance
    retimer_agent.get_retimer_firmware_load_status = orig_get_retimer_firmware_load_status
    retimer_agent.start_set_box_id_to_box  = origin_start_set_box_id_to_box
    retimer_agent.start_monitor_bmc_properties  = origin_start_monitor_bmc_properties
end

function TestRetimerAgentJbogRetimer:test_stop()
    local orig_kill = skynet.killthread
    retimer_agent.monitor_task = true
    retimer_agent.box_i2c_access_moitor_task = true
    skynet.killthread = function()
    end
    retimer_agent:stop()
    lu.assertEquals(retimer_agent.monitor_task, nil)
    lu.assertEquals(retimer_agent.box_i2c_access_moitor_task, nil)
    skynet.killthread = orig_kill
end

function TestRetimerAgentJbogRetimer:test_update_box_i2c_access_failure_alarm()
    local orig_get_device_name = retimer_agent.get_device_name
    local orig_get_latest_alarm_list = event.get_latest_alarm_list

    retimer_agent.get_device_name = function()
        return false
    end
    local ret = retimer_agent:update_box_i2c_access_failure_alarm()
    lu.assertEquals(ret, false)

    retimer_agent.get_device_name = function()
        return true
    end
    event.get_latest_alarm_list = function()
        return false, nil
    end
    ret = retimer_agent:update_box_i2c_access_failure_alarm()
    lu.assertEquals(ret, false)

    event.get_latest_alarm_list = function()
        return true, {}
    end
    ret = retimer_agent:update_box_i2c_access_failure_alarm()
    lu.assertEquals(ret, true)

    retimer_agent.device_name = 'ComponentName'
    event.get_latest_alarm_list = function()
        return true, {
            [1] = {
                ComponentName = 'ComponentName',
                EventName = 'BMCAccessI2CDeviceFailure',
            }
        }
    end
    ret = retimer_agent:update_box_i2c_access_failure_alarm()
    lu.assertEquals(ret, true)

    retimer_agent.get_device_name = orig_get_device_name
    event.get_latest_alarm_list = orig_get_latest_alarm_list
end

function TestRetimerAgentJbogRetimer:test_get_device_name()
    local orig_get_obj = factory.get_obj

    skynet.sleep = function()
    end
    factory.get_obj = function()
        return {
            get_board_obj_by_position = function()
                return {
                    mds_obj = {
                        DeviceName = 'device_name'
                    }
                }
            end
        }
    end
    retimer_agent.retimer = {
        position = 'position'
    }
    local ret = retimer_agent:get_device_name()
    lu.assertEquals(ret, true)

    factory.get_obj = orig_get_obj
end

function TestRetimerAgentJbogRetimer:test_get_retimer_firmware_load_status()
    local orig_chip_blkread = smc.chip_blkread

    skynet.sleep = function()
    end
    smc.chip_blkread = function()
        return {
            byte = function()
                return 'byte'
            end
        }
    end
    retimer_agent.retimer = {
        name = 'name',
        retimer_obj = {
            RefChip = 'RefChip'
        }
    }
    local ret = retimer_agent:get_retimer_firmware_load_status()
    lu.assertEquals(ret, 'byte')

    smc.chip_blkread = function()
        error('chip_blkread error')
    end
    local ret = retimer_agent:get_retimer_firmware_load_status()
    lu.assertEquals(ret, nil)

    smc.chip_blkread = orig_chip_blkread
end

function TestRetimerAgentJbogRetimer:test_box_i2c_access_monitor_task()
    local orig_chip_blkread = smc.chip_blkread
    local orig_update_box_i2c_access_failure_alarm = retimer_agent.update_box_i2c_access_failure_alarm

    skynet.sleep = function()
    end
    retimer_agent.retimer = {
        name = 'name',
        retimer_obj = {
            RefChip = 'RefChip'
        }
    }
    smc.chip_blkread = function()
        error('chip_blkread error')
    end
    local ret = retimer_agent.box_i2c_access_monitor_task(retimer_agent, 1)
    lu.assertEquals(ret, 1)

    smc.chip_blkread = function()
        return "\003"
    end
    ret = retimer_agent.box_i2c_access_monitor_task(retimer_agent, 1)
    lu.assertEquals(ret, 1)

    smc.chip_blkread = function()
        return "\001"
    end
    retimer_agent.update_box_i2c_access_failure_alarm = function()
        return false
    end
    ret = retimer_agent.box_i2c_access_monitor_task(retimer_agent, 1)
    lu.assertEquals(ret, 1)

    retimer_agent.update_box_i2c_access_failure_alarm = function()
        return true
    end
    ret = retimer_agent.box_i2c_access_monitor_task(retimer_agent, 1)
    lu.assertEquals(ret, 2)

    smc.chip_blkread = orig_chip_blkread
    retimer_agent.update_box_i2c_access_failure_alarm = orig_update_box_i2c_access_failure_alarm
end

function TestRetimerAgentJbogRetimer:test_set_bmc_ipv4_to_box()
    local SET_RETRY_TIMES <const> = 60
    local DEFAULT_MANAGER_ID = 1
    local orig_set_box_bmc_ipv4 = retimer_agent.retimer_utils.set_box_bmc_ipv4
    skynet.sleep = function() end  -- 禁用 sleep

    -- 场景1: manager_id 不匹配 → 返回 nil
    local ret = retimer_agent:set_bmc_ipv4_to_box(999, "192.168.1.1")
    lu.assertIsNil(ret)

    -- 场景2: 设置成功（第一次调用即成功）
    retimer_agent.retimer_utils.set_box_bmc_ipv4 = function(_, ip)
        lu.assertEquals(ip, "192.168.1.1")
        return true
    end
    ret = retimer_agent:set_bmc_ipv4_to_box(DEFAULT_MANAGER_ID, "192.168.1.1")
    lu.assertEquals(ret, true)

    -- 场景3: 重试后仍失败 → 返回 false
    local call_count = 0
    retimer_agent.retimer_utils.set_box_bmc_ipv4 = function()
        call_count = call_count + 1
        return false
    end
    ret = retimer_agent:set_bmc_ipv4_to_box(DEFAULT_MANAGER_ID, "192.168.1.1")
    lu.assertEquals(ret, false)
    lu.assertEquals(call_count, SET_RETRY_TIMES - 1)  -- retry_times < SET_RETRY_TIMES

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_ipv4 = orig_set_box_bmc_ipv4
end

function TestRetimerAgentJbogRetimer:test_set_bmc_ipv6_to_box()
    local orig_set_box_bmc_ipv6 = retimer_agent.retimer_utils.set_box_bmc_ipv6
    skynet.sleep = function() end

    -- manager_id 不匹配 → 返回 nil
    local ret = retimer_agent:set_bmc_ipv6_to_box(999, "::1")
    lu.assertIsNil(ret)

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_ipv6 = orig_set_box_bmc_ipv6
end

function TestRetimerAgentJbogRetimer:test_set_bmc_mac_to_box()
    local orig_set_box_bmc_mac = retimer_agent.retimer_utils.set_box_bmc_mac
    skynet.sleep = function() end

    -- manager_id 不匹配 → 返回 nil
    local ret = retimer_agent:set_bmc_mac_to_box(999, "AA:BB:CC:DD:EE:FF")
    lu.assertIsNil(ret)

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_mac = orig_set_box_bmc_mac
end

function TestRetimerAgentJbogRetimer:test_set_bmc_sn_to_box()
    local orig_set_box_bmc_sn = retimer_agent.retimer_utils.set_box_bmc_sn
    skynet.sleep = function() end

    -- system_id 不匹配 → 返回 nil
    local ret = retimer_agent:set_bmc_sn_to_box(999, "SN123456")
    lu.assertIsNil(ret)

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_sn = orig_set_box_bmc_sn
end

function TestRetimerAgentJbogRetimer:test_set_bmc_id_to_box()
    local orig_set_box_bmc_id = retimer_agent.retimer_utils.set_box_bmc_id
    skynet.sleep = function() end

    retimer_agent.retimer_utils.set_box_bmc_id = function(retimer_obj, bmc_id)
        -- 第一个参数是 self.retimer（表）
        lu.assertTrue(type(retimer_obj) == "table")
        -- 第二个参数 bmc_id
        lu.assertEquals(bmc_id, 5)
        return true
    end

    local ret = retimer_agent:set_bmc_id_to_box(5)
    lu.assertEquals(ret, true)

    -- 失败场景
    retimer_agent.retimer_utils.set_box_bmc_id = function(retimer_obj, bmc_id)
        lu.assertEquals(bmc_id, 10)
        return false
    end
    ret = retimer_agent:set_bmc_id_to_box(10)
    lu.assertEquals(ret, false)

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_id = orig_set_box_bmc_id
end

function TestRetimerAgentJbogRetimer:test_register_jbog_callback_to_common_interface()
    local orig_get_instance = common_interface.get_instance
    local registered = {}

    common_interface.get_instance = function()
        return {
            register_callback = function(_, func, self_obj, key, name)
                table.insert(registered, {func = func, self_obj = self_obj, key = key, name = name})
            end
        }
    end

    if not retimer_agent.retimer_utils then
        retimer_agent.retimer_utils = {}
    end

    retimer_agent:register_jbog_callback_to_common_interface()

    lu.assertEquals(#registered, 4)
    lu.assertEquals(registered[1].key, 'ipv4')
    lu.assertEquals(registered[2].key, 'ipv6')
    lu.assertEquals(registered[3].key, 'mac')
    lu.assertEquals(registered[4].key, 'sn')

    common_interface.get_instance = orig_get_instance
end

function TestRetimerAgentJbogRetimer:test_start_set_box_id_to_box()

    local orig_get_obj = factory.get_obj
    local orig_set_bmc_id_to_box = retimer_agent.set_bmc_id_to_box

    factory.get_obj = function(name)
        if name == "unit_manager" then
            return {
                get_board_obj_by_position = function(_, pos)
                    lu.assertEquals(pos, retimer_agent.retimer.position)
                    return { mds_obj = { Slot = 2 } }
                end
            }
        end
    end

    local called_with = nil
    retimer_agent.set_bmc_id_to_box = function(_, id)
        called_with = id
        return true
    end

    retimer_agent:start_set_box_id_to_box()

    lu.assertEquals(called_with, 1)

    -- 恢复
    factory.get_obj = orig_get_obj
    retimer_agent.set_bmc_id_to_box = orig_set_bmc_id_to_box
end

function TestRetimerAgentJbogRetimer:test_start_monitor_bmc_properties_box_id_is_1()
    local orig_get_instance = common_interface.get_instance
    local callback_called = false
    local listening_called = false

    retimer_agent.box_id = 1  -- 触发提前返回分支
    common_interface.get_instance = function()
        return {
            register_callback = function() callback_called = true end,
            register_bmc_listening = function() listening_called = true end
        }
    end

    retimer_agent:start_monitor_bmc_properties()

    -- 验证：两个注册函数均未被调用
    lu.assertEquals(callback_called, false)
    lu.assertEquals(listening_called, false)

    common_interface.get_instance = orig_get_instance
end

function TestRetimerAgentJbogRetimer:test_start_monitor_bmc_properties_box_id_not_1()
    local orig_get_instance = common_interface.get_instance
    local callback_count = 0
    local listening_called = false

    retimer_agent.box_id = 2  -- 非1，走完整流程
    common_interface.get_instance = function()
        return {
            register_callback = function() callback_count = callback_count + 1 end,
            register_bmc_listening = function() listening_called = true end
        }
    end

    retimer_agent:start_monitor_bmc_properties()

    lu.assertEquals(callback_count, 4)  -- register_jbog_callback_to_common_interface 内部注册4次
    lu.assertEquals(listening_called, true)

    common_interface.get_instance = orig_get_instance
end

function TestRetimerAgentJbogRetimer:test_start_set_box_id_to_box_riser_nil()
    local orig_get_obj = factory.get_obj
    local set_bmc_id_called_with = nil

    factory.get_obj = function(name)
        if name == "unit_manager" then
            return {
                get_board_obj_by_position = function() return nil end  -- 模拟 riser_obj 为 nil
            }
        end
    end

    retimer_agent.retimer = { position = "slot1" }
    retimer_agent.set_bmc_id_to_box = function(_, id)
        set_bmc_id_called_with = id
    end

    retimer_agent:start_set_box_id_to_box()

    lu.assertEquals(retimer_agent.box_id, 0)       -- or 0 生效
    lu.assertEquals(set_bmc_id_called_with, 0)     -- 验证后续调用参数

    factory.get_obj = orig_get_obj
end

-- 完整覆盖 set_bmc_ipv6_to_box 的成功/失败路径
function TestRetimerAgentJbogRetimer:test_set_bmc_ipv6_to_box_success_and_failure()
    local SET_RETRY_TIMES <const> = 60
    local DEFAULT_MANAGER_ID = 1
    local orig_set_box_bmc_ipv6 = retimer_agent.retimer_utils.set_box_bmc_ipv6
    skynet.sleep = function() end

    -- 成功场景
    retimer_agent.retimer_utils.set_box_bmc_ipv6 = function(_, ip)
        lu.assertEquals(ip, "::1")
        return true
    end
    local ret = retimer_agent:set_bmc_ipv6_to_box(DEFAULT_MANAGER_ID, "::1")
    lu.assertEquals(ret, true)

    -- 失败场景（重试耗尽）
    local call_count = 0
    retimer_agent.retimer_utils.set_box_bmc_ipv6 = function()
        call_count = call_count + 1
        return false
    end
    ret = retimer_agent:set_bmc_ipv6_to_box(DEFAULT_MANAGER_ID, "::1")
    lu.assertEquals(ret, false)
    lu.assertEquals(call_count, SET_RETRY_TIMES - 1)

    -- 恢复
    retimer_agent.retimer_utils.set_box_bmc_ipv6 = orig_set_box_bmc_ipv6
end

-- 完整覆盖 set_bmc_mac_to_box 的成功/失败路径
function TestRetimerAgentJbogRetimer:test_set_bmc_mac_to_box_success_and_failure()
    local SET_RETRY_TIMES <const> = 60
    local DEFAULT_MANAGER_ID = 1
    local orig_set_box_bmc_mac = retimer_agent.retimer_utils.set_box_bmc_mac
    skynet.sleep = function() end

    -- 成功场景
    retimer_agent.retimer_utils.set_box_bmc_mac = function(_, mac)
        lu.assertEquals(mac, "AA:BB:CC:DD:EE:FF")
        return true
    end
    local ret = retimer_agent:set_bmc_mac_to_box(DEFAULT_MANAGER_ID, "AA:BB:CC:DD:EE:FF")
    lu.assertEquals(ret, true)

    -- 失败场景
    local call_count = 0
    retimer_agent.retimer_utils.set_box_bmc_mac = function()
        call_count = call_count + 1
        return false
    end
    ret = retimer_agent:set_bmc_mac_to_box(DEFAULT_MANAGER_ID, "AA:BB:CC:DD:EE:FF")
    lu.assertEquals(ret, false)
    lu.assertEquals(call_count, SET_RETRY_TIMES - 1)

    retimer_agent.retimer_utils.set_box_bmc_mac = orig_set_box_bmc_mac
end

-- 完整覆盖 set_bmc_sn_to_box 的成功/失败路径（注意参数是 system_id）
function TestRetimerAgentJbogRetimer:test_set_bmc_sn_to_box_success_and_failure()
    local SET_RETRY_TIMES <const> = 60
    local DEFAULT_SYSTEM_ID = 1
    local orig_set_box_bmc_sn = retimer_agent.retimer_utils.set_box_bmc_sn
    skynet.sleep = function() end

    -- 成功场景
    retimer_agent.retimer_utils.set_box_bmc_sn = function(_, sn)
        lu.assertEquals(sn, "SN123456789")
        return true
    end
    local ret = retimer_agent:set_bmc_sn_to_box(DEFAULT_SYSTEM_ID, "SN123456789")
    lu.assertEquals(ret, true)

    -- 失败场景
    local call_count = 0
    retimer_agent.retimer_utils.set_box_bmc_sn = function()
        call_count = call_count + 1
        return false
    end
    ret = retimer_agent:set_bmc_sn_to_box(DEFAULT_SYSTEM_ID, "SN123456789")
    lu.assertEquals(ret, nil)
    lu.assertEquals(call_count, SET_RETRY_TIMES - 1)

    retimer_agent.retimer_utils.set_box_bmc_sn = orig_set_box_bmc_sn
end

-- 覆盖 start_monitor_bmc_properties 中 box_id == 1 的未覆盖分支
function TestRetimerAgentJbogRetimer:test_start_monitor_bmc_properties_box_id_1()
    -- 保存原始值
    local original_box_id = retimer_agent.box_id
    local orig_get_instance = common_interface.get_instance

    -- 模拟 box_id == 1，应直接返回，不注册回调
    retimer_agent.box_id = 1

    local register_called = false
    local listening_called = false

    common_interface.get_instance = function()
        return {
            register_callback = function()
                register_called = true
            end,
            register_bmc_listening = function()
                listening_called = true
            end
        }
    end

    retimer_agent:start_monitor_bmc_properties()

    -- 验证：两个注册函数都未被调用
    lu.assertEquals(register_called, false)
    lu.assertEquals(listening_called, false)

    -- 恢复
    retimer_agent.box_id = original_box_id
    common_interface.get_instance = orig_get_instance
end

-- 覆盖 start_monitor_bmc_properties 中 box_id ~= 1 的正常路径（确保回调注册）
function TestRetimerAgentJbogRetimer:test_start_monitor_bmc_properties_normal_path()
    local original_box_id = retimer_agent.box_id
    local orig_get_instance = common_interface.get_instance

    retimer_agent.box_id = 2  -- 非1值

    local callbacks = {}
    common_interface.get_instance = function()
        return {
            register_callback = function(_, func, self_obj, key, name)
                table.insert(callbacks, key)
            end,
            register_bmc_listening = function() end
        }
    end

    retimer_agent:start_monitor_bmc_properties()

    lu.assertEquals(#callbacks, 4)
    lu.assertTrue(lu.contains(callbacks, 'ipv4'))
    lu.assertTrue(lu.contains(callbacks, 'ipv6'))
    lu.assertTrue(lu.contains(callbacks, 'mac'))
    lu.assertTrue(lu.contains(callbacks, 'sn'))

    -- 恢复
    retimer_agent.box_id = original_box_id
    common_interface.get_instance = orig_get_instance
end

-- 辅助函数
function lu.contains(tbl, item)
    for _, v in ipairs(tbl) do
        if v == item then return true end
    end
    return false
end