-- 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 err = require 'sensor_error'


-- 仅测试 sensor_management 逻辑，避免真实 sensor_instance 依赖
local saved_instance_preload = package.preload['sensor.sensor_instance']
local saved_instance_loaded = package.loaded['sensor.sensor_instance']
package.preload['sensor.sensor_instance'] = function()
    return {}
end
package.loaded['sensor.sensor_instance'] = nil

local sensor_management = require 'sensor.sensor_management'

package.preload['sensor.sensor_instance'] = saved_instance_preload
package.loaded['sensor.sensor_instance'] = saved_instance_loaded

-- stub mc.class_mgnt before requiring sensor_instance to avoid os.getenv dependency
local saved_class_mgnt_preload = package.preload['mc.class_mgnt']
local saved_class_mgnt_loaded = package.loaded['mc.class_mgnt']
package.preload['mc.class_mgnt'] = function()
    return function(class_name)
        return {
            get_all = function() return {} end,
            remove = function(obj) end
        }
    end
end
package.loaded['mc.class_mgnt'] = nil

local saved_sensor_management_loaded = package.loaded['sensor.sensor_management']
package.loaded['sensor.sensor_management'] = nil
local fresh_sensor_management = require 'sensor.sensor_management'
package.loaded['sensor.sensor_management'] = saved_sensor_management_loaded

-- preload the stub to ensure it's in package.loaded before sensor_instance requires it
local cls_mgnt = require 'mc.class_mgnt'

local sensor_instance = require 'sensor.sensor_instance'

-- restore mc.class_mgnt
package.preload['mc.class_mgnt'] = saved_class_mgnt_preload
package.loaded['mc.class_mgnt'] = saved_class_mgnt_loaded

local function make_sensor_instance(overrides)
    local inst = {
        sensor_clz = 'ThresholdSensor',
        sensor_number = 101,
        rm = {
            readable_upper_nonrecoverable = 1,
            readable_upper_critical = 1,
            readable_upper_noncritical = 1,
            readable_lower_nonrecoverable = 1,
            readable_lower_critical = 1,
            readable_lower_noncritical = 1
        },
        mdb_obj = {
            UpperNonrecoverable = 200,
            UpperCritical = 150,
            UpperNoncritical = 120,
            LowerNonrecoverable = 30,
            LowerCritical = 40,
            LowerNoncritical = 50,
            ReadingMask = 0,
            -- 添加 convert_normal_to_raw 需要的字段
            Unit = 0x01,  -- 温度单位 (analog = 0, 无符号)
            M = 1,        -- 线性系数 M
            MT = 0,       -- 线性系数 MT (高2位)
            B = 0,        -- 偏移量 B
            BA = 0,       -- 偏移量 BA (高2位)
            RBExp = 0     -- 指数 (bexp 和 rexp 都为 0)
        },
        set_sensor_threshold = function()
            return err.SUCCESS
        end
    }
    if overrides then
        for k, v in pairs(overrides) do
            if k == 'mdb_obj' and type(v) == 'table' then
                -- 合并 mdb_obj 而不是替换
                for mk, mv in pairs(v) do
                    inst.mdb_obj[mk] = mv
                end
            else
                inst[k] = v
            end
        end
    end
    return inst
end

local function new_sensor(name, handler)
    return {
        mdb_obj = { SensorName = name },
        set_threshold_sensor_property = handler
    }
end

local function new_manager(sensor_objs)
    local mgr = { sensor_objs = sensor_objs or {} }
    return setmetatable(mgr, { __index = sensor_management })
end

test_threshold_settings = {}

function test_threshold_settings:test_set_threshold_success()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, initiator, attrs)
            captured = { initiator = initiator, attrs = attrs }
            return err.SUCCESS
        end)
    })

    mgr:set_threshold_sensor_property(nil, { Source = 'UnitTest' }, 'CPU_Temp', 0, {
        UpperCritical = '85',
        LowerCritical = ' 9.5 '
    })

    lu.assertEquals(captured.initiator.Source, 'UnitTest')
    lu.assertEquals(captured.attrs.UpperCritical, '85.000')
    lu.assertEquals(captured.attrs.LowerCritical, '9.500')
end

function test_threshold_settings:test_invalid_persistence_type()
    local mgr = new_manager({
        new_sensor('CPU_Temp', function() return err.SUCCESS end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 5, {
        UpperCritical = '70'
    })
end

function test_threshold_settings:test_attributes_not_table()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, { Source = 'UnitTest' }, 'CPU_Temp', 0, {
        UpperCritical = '70',
        LowerCritical = '15'
    })
    lu.assertEquals(captured.UpperCritical, '70.000')
    lu.assertEquals(captured.LowerCritical, '15.000')
end

function test_threshold_settings:test_sensor_not_found()
    local mgr = new_manager({})
    lu.assertErrorMsgContains('sensor [Missing] does not exist.', function()
        mgr:set_threshold_sensor_property(nil, {}, 'Missing', 0, {
            UpperCritical = '70'
        })
    end)
end

function test_threshold_settings:test_precision_and_key_errors()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    -- 精度超过3位小数时应该截断，不报错
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '12.3456'
    })
    lu.assertEquals(captured.UpperCritical, '12.346')

    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        Unknown = '10'
    })
end

function test_threshold_settings:test_dictionary_item_support()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '81.2',
        LowerCritical = '11'
    })
    lu.assertEquals(captured.UpperCritical, '81.200')
    lu.assertEquals(captured.LowerCritical, '11.000')
end

function test_threshold_settings:test_sensor_returns_nil_and_invalid_code()
    local mgr = new_manager({
        new_sensor('CPU_Temp', function() return nil end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '70'
    })

    mgr.sensor_objs[1] = new_sensor('CPU_Temp', function() return 999 end)
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '70'
    })
end

function test_threshold_settings:test_invalid_dictionary_key_in_item()
    local mgr = new_manager({
        new_sensor('CPU_Temp', function() return err.SUCCESS end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '81',
        UnknownKey = '100'
    })
end

function test_threshold_settings:test_item_not_table()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '65'
    })
    lu.assertEquals(captured.UpperCritical, '65.000')
end

function test_threshold_settings:test_invalid_value_format()
    local mgr = new_manager({
        new_sensor('CPU_Temp', function() return err.SUCCESS end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = 'abc'
    })
end

function test_threshold_settings:test_all_threshold_keys()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperNonrecoverable = '100',
        UpperCritical = '90',
        UpperNoncritical = '80',
        LowerNonrecoverable = '10',
        LowerCritical = '20',
        LowerNoncritical = '30'
    })
    lu.assertEquals(captured.UpperNonrecoverable, '100.000')
    lu.assertEquals(captured.UpperCritical, '90.000')
    lu.assertEquals(captured.UpperNoncritical, '80.000')
    lu.assertEquals(captured.LowerNonrecoverable, '10.000')
    lu.assertEquals(captured.LowerCritical, '20.000')
    lu.assertEquals(captured.LowerNoncritical, '30.000')
end

function test_threshold_settings:test_negative_value()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '-10.5'
    })
    lu.assertEquals(captured.UpperCritical, '-10.500')
end

function test_threshold_settings:test_integer_value()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '100'
    })
    lu.assertEquals(captured.UpperCritical, '100.000')
end

function test_threshold_settings:test_zero_value()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '0'
    })
    lu.assertEquals(captured.UpperCritical, '0.000')
end

function test_threshold_settings:test_persistence_type_one()
    local captured
    local mgr = new_manager({
        new_sensor('CPU_Temp', function(_, _, attrs)
            captured = attrs
            return err.SUCCESS
        end)
    })
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 1, {
        UpperCritical = '85'
    })
    lu.assertEquals(captured.UpperCritical, '85.000')
end


-- sensor_instance specific tests ---------------------------------------------

function test_threshold_settings:test_sensor_instance_success_flow()
    local captured
    local inst = make_sensor_instance({
        set_sensor_threshold = function(_, threshold_data)
            captured = threshold_data
            return err.SUCCESS
        end
    })
    -- 确保 mdb_obj 和 Unit 字段存在
    lu.assertNotNil(inst.mdb_obj)
    lu.assertNotNil(inst.mdb_obj.Unit)
    sensor_instance.set_threshold_sensor_property(inst, { Interface = 'UnitTest' }, {
        UpperCritical = '80'
    })
    lu.assertEquals(captured.UCRFlag, 1)
end

function test_threshold_settings:test_sensor_instance_mask_disabled()
    local inst = make_sensor_instance({
        rm = { readable_upper_critical = 0 }
    })
    sensor_instance.set_threshold_sensor_property(inst, nil, {
        UpperCritical = '80'
    })
end

function test_threshold_settings:test_sensor_instance_threshold_apply_failure()
    local inst = make_sensor_instance({
        set_sensor_threshold = function()
            return err.ERR_INVALID_DATA_FIELD
        end
    })
    -- 确保 mdb_obj 和 Unit 字段存在
    lu.assertNotNil(inst.mdb_obj)
    lu.assertNotNil(inst.mdb_obj.Unit)
    lu.assertErrorMsgContains('Sensor [101] set threshold failed', function()
        sensor_instance.set_threshold_sensor_property(inst, nil, {
            UpperCritical = '80'
        })
    end)
end

function test_threshold_settings:test_sensor_instance_invalid_sensor_type()
    local inst = make_sensor_instance({
        sensor_clz = 'DiscreteSensor'
    })
    lu.assertErrorMsgContains('Sensor [101] is not a ThresholdSensor', function()
        sensor_instance.set_threshold_sensor_property(inst, nil, {
            UpperCritical = '80'
        })
    end)
end

function test_threshold_settings:test_duplicate_sensor_smaller_idx()
    -- 测试重复传感器场景：先找到较大的索引，后找到较小的索引
    -- 这会触发 sensor_management.lua:705 的日志代码
    local sensor1 = new_sensor('CPU_Temp', function() return err.SUCCESS end)
    local sensor2 = new_sensor('CPU_Temp', function() return err.SUCCESS end)
    local mgr = new_manager({
        [5] = sensor1,  -- 较大的索引，先找到
        [2] = sensor2  -- 较小的索引，后找到，会触发重复日志
    })
    
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '70'
    })
end

function test_threshold_settings:test_duplicate_sensor_larger_idx()
    -- 测试重复传感器场景：先找到较小的索引，后找到较大的索引
    -- 这会触发 sensor_management.lua:710 的日志代码
    local sensor1 = new_sensor('CPU_Temp', function() return err.SUCCESS end)
    local sensor2 = new_sensor('CPU_Temp', function() return err.SUCCESS end)
    local mgr = new_manager({
        [2] = sensor1,  -- 较小的索引，先找到
        [5] = sensor2  -- 较大的索引，后找到，会触发重复日志
    })
    
    mgr:set_threshold_sensor_property(nil, {}, 'CPU_Temp', 0, {
        UpperCritical = '70'
    })
end

function test_threshold_settings:test_IsValid_obj()
    local obj = {
        get_object_name = function()
            return 0
        end,
        BelongsToSystem = false,
        IsValid = false
    }
    local ret = fresh_sensor_management:register_sensor(nil, obj)
    lu.assertEquals(ret, false)
end

function test_threshold_settings:test_sensor_instance_value_out_of_range_unsigned()
    -- 测试无符号传感器值超出范围（> 255）
    -- Unit = 0x00 表示 analog = 0（无符号），范围 0 ~ 255
    local inst = make_sensor_instance({
        mdb_obj = {
            Unit = 0x00,  -- analog = 0, 无符号
            M = 1,
            MT = 0,
            B = 0,
            BA = 0,
            RBExp = 0
        }
    })
    -- 传入 256，转换后 raw = 256，超过 255 的范围
    -- 这里只校验触发范围错误的自定义消息（PropertyValueOutOfRange），不关心完整文案
    lu.assertErrorMsgContains('PropertyValueOutOfRange', function()
        sensor_instance.set_threshold_sensor_property(inst, nil, {
            UpperCritical = '256'
        })
    end)
end

function test_threshold_settings:test_sensor_instance_invalid_property_name()
    -- 覆盖属性名非法分支，触发 PropertyValueError
    local inst = make_sensor_instance()
    lu.assertErrorMsgContains('PropertyValueError', function()
        sensor_instance.set_threshold_sensor_property(inst, nil, {
            InvalidProperty = '80'
        })
    end)
end

return test_threshold_settings

