-- Copyright (c) 2026 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 jbog_utils = require 'retimer.agent.retimer_agent_jbog_retimer_utils'

TestJbogUtils = {}

-- === 测试 generate_cmd ===
function TestJbogUtils:test_generate_cmd()
    local spec = { func = 0x21, command = 3, ms = 0, rw = 1, parameter = 0 }
    local cmd = jbog_utils.generate_cmd(spec)
    local expected = (0x21 << 26) | (3 << 10) | (1 << 8)
    lu.assertEquals(cmd, expected)

    -- 默认值测试
    local default_cmd = jbog_utils.generate_cmd({})
    lu.assertEquals(default_cmd, 0)
end

-- === 测试 safe_byte_dec ===
function TestJbogUtils:test_safe_byte_dec()
    lu.assertEquals(jbog_utils.safe_byte_dec(nil), nil)
    lu.assertEquals(jbog_utils.safe_byte_dec('abc'), nil)
    lu.assertEquals(jbog_utils.safe_byte_dec('-1'), nil)
    lu.assertEquals(jbog_utils.safe_byte_dec('256'), nil)
    lu.assertEquals(jbog_utils.safe_byte_dec('0'), string.char(0))
    lu.assertEquals(jbog_utils.safe_byte_dec('255'), string.char(255))
    lu.assertEquals(jbog_utils.safe_byte_dec('192'), string.char(192))
end

-- === 测试 safe_byte_hex ===
function TestJbogUtils:test_safe_byte_hex()
    lu.assertEquals(jbog_utils.safe_byte_hex(nil), nil)
    lu.assertEquals(jbog_utils.safe_byte_hex('GG'), nil)
    lu.assertEquals(jbog_utils.safe_byte_hex('100'), nil)           -- >255
    lu.assertEquals(jbog_utils.safe_byte_hex('a'), string.char(10)) -- "0a"
    lu.assertEquals(jbog_utils.safe_byte_hex('FF'), string.char(255))
    lu.assertEquals(jbog_utils.safe_byte_hex('0'), string.char(0))
end

-- === 测试 expand_ipv6 ===
function TestJbogUtils:test_expand_ipv6()
    lu.assertEquals(jbog_utils.expand_ipv6("::1"),
        "0000:0000:0000:0000:0000:0000:0000:0001")
    lu.assertEquals(jbog_utils.expand_ipv6("2001:db8::1"),
        "2001:0db8:0000:0000:0000:0000:0000:0001")
    lu.assertEquals(jbog_utils.expand_ipv6("::"),
        "0000:0000:0000:0000:0000:0000:0000:0000")
    lu.assertEquals(jbog_utils.expand_ipv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
        "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
    lu.assertEquals(jbog_utils.expand_ipv6(nil), nil)
    lu.assertEquals(jbog_utils.expand_ipv6("invalid"), nil)
    lu.assertEquals(jbog_utils.expand_ipv6("1:2:3:4:5:6:7:8:9"), nil) -- too many segments
end

-- === 测试 compress_ipv6 ===
function TestJbogUtils:test_compress_ipv6()
    local words = { 0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x8001 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "::ffff:c00a:8001")

    words = { 0x2001, 0xdb8, 0, 0, 0, 0, 0, 1 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "2001:db8::1")

    words = { 1, 2, 3, 4, 5, 6, 7, 8 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "1:2:3:4:5:6:7:8")
end

-- === 测试 dal_ipv4_addr_pack ===
function TestJbogUtils:test_dal_ipv4_addr_pack()
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack(nil), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack(''), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.168.1.1'), string.char(192, 168, 1, 1))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('0.0.0.0'), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.256.1.1'), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.-1.1.1'), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.abc.1.1'), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.168.1'), string.rep('\0', 4))
    lu.assertEquals(jbog_utils.dal_ipv4_addr_pack('192.168.1.1.2'), string.rep('\0', 4))
end

-- === 测试 dal_mac_pack ===
function TestJbogUtils:test_dal_mac_pack()
    lu.assertEquals(jbog_utils.dal_mac_pack(nil), string.rep('\0', 6))
    lu.assertEquals(jbog_utils.dal_mac_pack(''), string.rep('\0', 6))
    lu.assertEquals(jbog_utils.dal_mac_pack('aa:bb:cc:dd:ee:ff'),
        string.char(0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff))
    lu.assertEquals(jbog_utils.dal_mac_pack('AA:BB:CC:DD:EE:FF'),
        string.char(0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff))
    lu.assertEquals(jbog_utils.dal_mac_pack('gg:bb:cc:dd:ee:ff'), string.rep('\0', 6))
    lu.assertEquals(jbog_utils.dal_mac_pack('aa:bb:cc:dd:ee'), string.rep('\0', 6))
end

-- === 测试 dal_ipv6_addr_pack ===
function TestJbogUtils:test_dal_ipv6_addr_pack()
    -- 正常 ::1
    local packed = jbog_utils.dal_ipv6_addr_pack("::1")
    local expected = string.rep('\0', 15) .. '\1'
    lu.assertEquals(packed, expected)

    -- 全零
    packed = jbog_utils.dal_ipv6_addr_pack("::")
    lu.assertEquals(packed, string.rep('\0', 16))

    -- 标准格式
    packed = jbog_utils.dal_ipv6_addr_pack("2001:db8::1")
    expected = string.char(
        0x20, 0x01, 0x0d, 0xb8,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01
    )
    lu.assertEquals(packed, expected)

    -- 非法输入
    packed = jbog_utils.dal_ipv6_addr_pack("invalid")
    lu.assertEquals(packed, string.rep('\0', 16))

    -- 空输入
    packed = jbog_utils.dal_ipv6_addr_pack("")
    lu.assertEquals(packed, string.rep('\0', 16))
end

-- === 测试构造函数和命令初始化 ===
local mock_chip = {
    Write = function() return true end,
    Read = function() return "" end
}

function TestJbogUtils:test_ctor_and_cmds()
    local utils = jbog_utils:new(mock_chip)
    lu.assertTrue(type(utils.cmds.SetBmcIpv4) == "number")
    lu.assertTrue(type(utils.cmds.SetBmcIpv6) == "number")
    lu.assertTrue(type(utils.cmds.SetBmcMac) == "number")
    lu.assertTrue(type(utils.cmds.SetBmcSN) == "number")
    lu.assertTrue(type(utils.cmds.SetBmcId) == "number")
end

function TestJbogUtils:test_compress_ipv6_edge_cases()
    -- 多个等长零段：应压缩最左边的
    local words = { 0, 0, 1, 0, 0, 2, 3, 4 }                          -- 两个长度为2的零段
    lu.assertEquals(jbog_utils.compress_ipv6(words), "::1:0:0:2:3:4") -- 压缩前两个

    -- 零段在末尾
    words = { 1, 2, 3, 4, 5, 6, 0, 0 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "1:2:3:4:5:6::")

    -- 零段在开头
    words = { 0, 0, 1, 2, 3, 4, 5, 6 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "::1:2:3:4:5:6")

    -- 单个零（不压缩）
    words = { 1, 0, 2, 3, 4, 5, 6, 7 }
    lu.assertEquals(jbog_utils.compress_ipv6(words), "1:0:2:3:4:5:6:7")

    -- 输入不是8个元素
    lu.assertEquals(jbog_utils.compress_ipv6({ 1, 2, 3 }), nil)
    lu.assertEquals(jbog_utils.compress_ipv6({}), nil)
end

function TestJbogUtils:test_expand_ipv6_invalid_and_edge()
    -- 多个 ::
    lu.assertEquals(jbog_utils.expand_ipv6("1::2::3"), nil)

    -- 带 zone ID
    lu.assertEquals(jbog_utils.expand_ipv6("fe80::1%eth0"),
        "fe80:0000:0000:0000:0000:0000:0000:0001")

    -- 以 :: 开头或结尾的边界
    lu.assertEquals(jbog_utils.expand_ipv6("::1:2"), "0000:0000:0000:0000:0000:0000:0001:0002")
    lu.assertEquals(jbog_utils.expand_ipv6("1:2::"), "0001:0002:0000:0000:0000:0000:0000:0000")

    -- 空段（如连续 :::）
    lu.assertEquals(jbog_utils.expand_ipv6("1::::2"), nil) -- 非法

    -- 混合大小写
    lu.assertEquals(jbog_utils.expand_ipv6("2001:DB8::a"),
        "2001:0db8:0000:0000:0000:0000:0000:000a")
end
