-- Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
-- 
-- this file licensed under the 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 log = require 'mc.logging'
require 'skynet.manager'
local custom_msg = require 'messages.custom'
local base_msg = require 'messages.base'
local cooling_enums = require 'basic_cooling.define.cooling_enums'
local props = require 'basic_cooling.define.cooling_properties'
local error = require 'mc.error'
local safe_call = error.safe_call
local mdb = require 'mc.mdb'
local skynet = require 'skynet'
local mc_utils = require 'mc.utils'
require 'thermal_mgmt.json_types.CoolingPolicies'
require 'thermal_mgmt.json_types.CoolingRequirement'
require 'thermal_mgmt.json_types.CoolingPolicy'

local test_rpc = {}

local function busctl_get_props(bus, rpc_path, intf, prop_name)
    return bus:call('bmc.kepler.thermal_mgmt', rpc_path,
        'org.freedesktop.DBus.Properties', 'Get', 'ss', intf, prop_name):value()
end

local function busctl_set_props(bus, rpc_path, intf, prop_name, prop_v)
    bus:call('bmc.kepler.thermal_mgmt', rpc_path,
        'org.freedesktop.DBus.Properties', 'Set', 'ssv', intf, prop_name, prop_v)
end

local function get_object(bus, path, interface)
    local ok, obj = pcall(mdb.get_object, bus, path, interface)
    assert(ok)
    return obj
end

-- 获取必要的风扇代理对象
local function l_objs_init(bus)
    local ok
    local t_fan_1_obj, t_fan_2_obj
    local c_fan_1_obj, c_fan_2_obj, c_fan_3_obj, c_fan_4_obj
    local req_7_obj
    local cooling_policies_obj
    local c_policy_74_obj
    local c_requirement_74_obj, c_requirement_75_obj
    local t_fan_1_path = '/bmc/kepler/Systems/1/Thermal/Fans/Fan_1_0101'
    local t_fan_2_path = '/bmc/kepler/Systems/1/Thermal/Fans/Fan_2_0101'
    local c_fan_1_path = '/bmc/kepler/Systems/1/CoolingFan/CoolingFan_1_1_0101'
    local c_fan_2_path = '/bmc/kepler/Systems/1/CoolingFan/CoolingFan_1_2_0101'
    local c_fan_3_path = '/bmc/kepler/Systems/1/CoolingFan/CoolingFan_1_3_0101'
    local c_fan_4_path = '/bmc/kepler/Systems/1/CoolingFan/CoolingFan_1_4_0101'
    local cooling_policies_path = '/bmc/kepler/Chassis/1/ThermalSubsystem/CoolingPolicies'
    local c_policy_74_path = '/bmc/kepler/Systems/1/CoolingPolicy/CoolingPolicy_1_74_0101'
    local c_requirement_74_path = '/bmc/kepler/Systems/1/CoolingRequirement/CoolingRequirement_1_74_0101'
    local c_requirement_75_path = '/bmc/kepler/Systems/1/CoolingRequirement/CoolingRequirement_1_75_0101'

    local c_req_7_path = '/bmc/kepler/Systems/1/CoolingRequirement/CoolingRequirement_1_7_0101'

    t_fan_1_obj = get_object(bus, t_fan_1_path, 'bmc.kepler.Systems.Fan')

    t_fan_2_obj = get_object(bus, t_fan_2_path, 'bmc.kepler.Systems.Fan')

    c_fan_1_obj = get_object(bus, c_fan_1_path, 'bmc.kepler.Systems.CoolingFan')
    c_fan_2_obj = get_object(bus, c_fan_2_path, 'bmc.kepler.Systems.CoolingFan')
    c_fan_3_obj = get_object(bus, c_fan_3_path, 'bmc.kepler.Systems.CoolingFan')
    c_fan_4_obj = get_object(bus, c_fan_4_path, 'bmc.kepler.Systems.CoolingFan')
    req_7_obj = get_object(bus, c_req_7_path, 'bmc.kepler.Systems.CoolingRequirement')

    cooling_policies_obj = get_object(bus, cooling_policies_path, 'bmc.kepler.Chassis.CoolingPolicies')

    c_policy_74_obj = get_object(bus, c_policy_74_path, 'bmc.kepler.Systems.CoolingPolicy')

    c_requirement_74_obj = get_object(bus, c_requirement_74_path, 'bmc.kepler.Systems.CoolingRequirement')
    c_requirement_75_obj = get_object(bus, c_requirement_75_path, 'bmc.kepler.Systems.CoolingRequirement')

    return {
        ['t_fan_1'] = t_fan_1_obj,
        ['t_fan_2'] = t_fan_2_obj,
        ['c_fan_1'] = c_fan_1_obj,
        ['c_fan_2'] = c_fan_2_obj,
        ['c_fan_3'] = c_fan_3_obj,
        ['c_fan_4'] = c_fan_4_obj,
        ['req_7_obj'] = req_7_obj,
        ['cooling_policies_obj'] = cooling_policies_obj,
        ['req_74'] = c_requirement_74_obj,
        ['req_75'] = c_requirement_75_obj,
        ['policy_74'] = c_policy_74_obj
    }
end

local function test_get_specific_pwm(cooling_policies_obj, c_config_obj, ctx_new)
    local err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 1, "EnergySaving", 30
    )
    assert(not err)
    assert(rsp.ControlPWM ~= 0, 'ctrl_pwm1=' .. rsp.ControlPWM)

    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 1, "LowNoise", 30
    )
    assert(not err)
    assert(rsp.ControlPWM ~= 0, 'ctrl_pwm2=' .. rsp.ControlPWM)

    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 1, "HighPerformance", 30
    )
    assert(not err)
    assert(rsp.ControlPWM ~= 0, 'ctrl_pwm3=' .. rsp.ControlPWM)

    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 1, "Custom", 30
    )
    assert(not err)
    assert(rsp.ControlPWM ~= 0, 'ctrl_pwm4=' .. rsp.ControlPWM)

    -- 节能模式下走高转速曲线CoolingPolicy_1_73
    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 2, "EnergySaving", 24
    )
    assert(not err)
    assert(rsp.ControlPWM == 80, 'ctrl_pwm1=' .. rsp.ControlPWM)

    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 2, "EnergySaving", 25
    )
    assert(not err)
    assert(rsp.ControlPWM == 90, 'ctrl_pwm1=' .. rsp.ControlPWM)

    err, rsp = safe_call(
        cooling_policies_obj.GetSpecificPWM_PACKED, cooling_policies_obj, ctx_new, 'Air', 2, "EnergySaving", 30
    )
    assert(not err)
    assert(rsp.ControlPWM == 95, 'ctrl_pwm1=' .. rsp.ControlPWM)
end

local function set_env_temp_curve_exp_test(bus, c_config_obj, c_policy_1_obj, ctx_new)
    local c_policy_1_path = '/bmc/kepler/Systems/1/CoolingPolicy/CoolingPolicy_1_1_0101'
    local c_policy_1_intf = 'bmc.kepler.Systems.CoolingPolicy'
    local SpeedRangeLow = busctl_get_props(bus, c_policy_1_path, c_policy_1_intf, props.POLICY_SPEED_RANGE_LOW)

    -- 入参长度测试
    local err = safe_call(c_policy_1_obj.SetCustomCoolingPolicy_PACKED, c_policy_1_obj, ctx_new, {}, {1})
    assert(err.name == custom_msg.PropertyMemberQtyExceedLimitMessage.Name)
    err = safe_call(c_policy_1_obj.SetCustomCoolingPolicy_PACKED, c_policy_1_obj, ctx_new, {1}, {})
    assert(err.name == custom_msg.PropertyMemberQtyExceedLimitMessage.Name)
    local function gen_table(n, m)
        local t = {}
        for i = n, m do
            table.insert(t, i)
        end
        return t
    end
    -- 测试数组长度大于64
    err = safe_call(
            c_policy_1_obj.SetCustomCoolingPolicy_PACKED,c_policy_1_obj, ctx_new, gen_table(1, 65), SpeedRangeLow)
    assert(err.name == custom_msg.PropertyMemberQtyExceedLimitMessage.Name)
    -- 测试两个参数长度差值大于1
    err = safe_call(
            c_policy_1_obj.SetCustomCoolingPolicy_PACKED, c_policy_1_obj, ctx_new, gen_table(20, 25), gen_table(20, 27))
    assert(err.name == custom_msg.WrongValueQtyMessage.Name)

    -- 入参数组升序测试
    local tt = gen_table(20, 23)
    table.insert(tt, 1, tt[#tt])
    local st = gen_table(20, 25)
    err = safe_call(c_policy_1_obj.SetCustomCoolingPolicy_PACKED, c_policy_1_obj, ctx_new, tt, st)
    assert(err.name == custom_msg.InvalidTemperatureRangeMessage.Name)

    -- 函数正确执行测试
    err = safe_call(
        c_policy_1_obj.SetCustomCoolingPolicy_PACKED, c_policy_1_obj, ctx_new, gen_table(20, 22), gen_table(20, 23))
    assert(not err)
end

local function set_smart_cooling_mode_test(c_config_obj, ctx_new)
    local cur_smart_cooling_mode = c_config_obj.SmartCoolingMode
    local air_cooling_mode = {
        cooling_enums.smart_cooling_mode.COOLING_ENERGY_SAVING_MODE,
        cooling_enums.smart_cooling_mode.COOLING_LOW_NOISE_MODE,
        cooling_enums.smart_cooling_mode.COOLING_HIGH_PERFORMANCE_MODE,
        cooling_enums.smart_cooling_mode.COOLING_CUSTOM_MODE
    }
    for _, mode in pairs(air_cooling_mode) do
        c_config_obj:SetSmartCoolingMode_PACKED(ctx_new, mode)
        assert(c_config_obj.SmartCoolingMode == mode,
            "Cur: " .. c_config_obj.SmartCoolingMode .. ", Exceptation: mode")
    end

    local err = safe_call(c_config_obj.SetSmartCoolingMode_PACKED, c_config_obj, ctx_new,
        cooling_enums.smart_cooling_mode.COOLING_LIQUID_MODE)
    assert(err.name == base_msg.PropertyValueNotInListMessage.Name)

    c_config_obj:SetSmartCoolingMode_PACKED(ctx_new, cur_smart_cooling_mode)
end

local function set_fan_level_test(c_config_obj, ctx_new, l_objs)
    local err
    -- 设置为手动模式,超时时间100s
    err = safe_call(c_config_obj.SetCtrlMode_PACKED, c_config_obj, ctx_new, cooling_enums.modes.Manual, 100)
    assert(not err)
    -- fan_id不存在测试
    err = safe_call(c_config_obj.SetManualLevel_PACKED, c_config_obj, ctx_new, 254, 20)
    assert(err.name == custom_msg.PropertyValueOutOfRangeMessage.Name)

    err = safe_call(c_config_obj.SetManualLevel_PACKED, c_config_obj, ctx_new, 1, 101)
    assert(err.name == custom_msg.PropertyValueOutOfRangeMessage.Name)

    err = safe_call(c_config_obj.SetManualLevel_PACKED, c_config_obj, ctx_new, 0xff, 50)
    skynet.sleep(1000)
    assert(not err)
    assert(l_objs.c_fan_1.Level == 50, 'c_fan_1 level: ' .. tostring(l_objs.c_fan_1.Level))
    assert(l_objs.c_fan_2.Level == 50, 'c_fan_2 level: ' .. tostring(l_objs.c_fan_2.Level))
    assert(l_objs.c_fan_3.Level == 50, 'c_fan_3 level: ' .. tostring(l_objs.c_fan_3.Level))
    assert(l_objs.c_fan_4.Level == 50, 'c_fan_4 level: ' .. tostring(l_objs.c_fan_4.Level))
    assert(c_config_obj[props.CONF_MANUAL_LEVEL] == 50, 'Actual: ', c_config_obj[props.CONF_MANUAL_LEVEL])
    log:error("mode=%s, time=%s", c_config_obj[props.CTL_MODE], c_config_obj[props.TIME_OUT])
    assert(l_objs.t_fan_1.ExpectedPWM == 128, 'Actual hardware PWM: ' .. tostring(l_objs.t_fan_1.ExpectedPWM))
    assert(l_objs.t_fan_2.ExpectedPWM == 128, 'Actual hardware PWM: ' .. tostring(l_objs.t_fan_2.ExpectedPWM))

    err = safe_call(c_config_obj.SetManualLevel_PACKED, c_config_obj, ctx_new, 1, 60)
    assert(not err) -- 单个转速下发立即生效
    assert(l_objs.c_fan_1.Level == 60, 'c_fan_1 level: ' .. tostring(l_objs.c_fan_1.Level))
    assert(l_objs.c_fan_2.Level == 50, 'c_fan_2 level: ' .. tostring(l_objs.c_fan_2.Level))
    assert(l_objs.c_fan_3.Level == 50, 'c_fan_3 level: ' .. tostring(l_objs.c_fan_3.Level))
    assert(l_objs.c_fan_4.Level == 50, 'c_fan_4 level: ' .. tostring(l_objs.c_fan_4.Level))
    assert(l_objs.t_fan_1.ExpectedPWM == 153, 'Actual ' .. l_objs.t_fan_1.ExpectedPWM)
    assert(l_objs.t_fan_2.ExpectedPWM == 128, 'Actual ' .. l_objs.t_fan_2.ExpectedPWM)

    -- 恢复模式为自动
    err = safe_call(c_config_obj.SetCtrlMode_PACKED, c_config_obj, ctx_new, cooling_enums.modes.Auto, 30)
    assert(not err)
    assert(c_config_obj[props.CTL_MODE] == cooling_enums.modes.Auto)
end

-- 风扇控制模式为非自动和手动
local function test_set_unexpected_ctrlmode(c_config_obj, ctx_new)
    local err = safe_call(c_config_obj.SetCtrlMode_PACKED, c_config_obj, ctx_new, 'Aut', 30)
    assert(err.name == custom_msg.ValueOutOfRangeMessage.Name)
end

-- 设置介质测试
local function test_set_cooling_medium(bus, c_config_obj, ctx_new)
    local err = safe_call(c_config_obj.SetMedium_PACKED, c_config_obj, ctx_new, props.COOLING_LIQUID)
    assert(not err)
    assert(c_config_obj[props.COOLING_MEDIUM] == props.COOLING_LIQUID)

    err = safe_call(c_config_obj.SetMedium_PACKED, c_config_obj, ctx_new, props.COOLING_AIR)
    assert(not err)
    assert(c_config_obj[props.COOLING_MEDIUM] == props.COOLING_AIR)
end

-- 测试在非自定义模式下设置出风口自定义目标温度值
local function test_set_outlet_csutom_target(bus, c_config_obj, req_7_obj, ctx_new)
    local pre_custom_target = req_7_obj[props.CUSTOM_TARGET_TEMP_CELSIUS]
    local err = safe_call(req_7_obj.SetTargetTemperature_PACKED, req_7_obj, ctx_new, 60)
    assert(not err)

    skynet.sleep(600) -- 轮询中尝试切换目标值
    assert(c_config_obj[props.SMART_COOLING_MODE] ~= cooling_enums.smart_cooling_mode.COOLING_CUSTOM_MODE)
    assert(req_7_obj[props.CUSTOM_TARGET_TEMP_CELSIUS] == 60)
    -- 非自定义模式下不会修改目标值
    assert(req_7_obj[props.TARGET_TEMP_CELSIUS] ~= 60)

    err = safe_call(req_7_obj.SetTargetTemperature_PACKED, req_7_obj, ctx_new, pre_custom_target)
    assert(not err)
    assert(req_7_obj[props.CUSTOM_TARGET_TEMP_CELSIUS] == pre_custom_target)
end

local function tese_get_custom_target_temperatures(c_config_obj, ctx_new)
    local err = safe_call(c_config_obj.GetCustomTargetTemperatures_PACKED, c_config_obj, ctx_new)
    -- 验证方法调用不报错
    assert(not err)
end

local function tese_get_abnormal_policy_effective_status(c_config_obj, ctx_new)
    local err = safe_call(c_config_obj.GetAbnormalPolicyEffectiveStatus_PACKED, c_config_obj, ctx_new, 'Fan')
    -- 验证方法调用不报错
    assert(not err)
    err = safe_call(c_config_obj.GetAbnormalPolicyEffectiveStatus_PACKED, c_config_obj, ctx_new, 'Pump')
    assert(not err)
    err = safe_call(c_config_obj.GetAbnormalPolicyEffectiveStatus_PACKED, c_config_obj, ctx_new, 'Temperature')
    assert(not err)
    err = safe_call(c_config_obj.GetAbnormalPolicyEffectiveStatus_PACKED, c_config_obj, ctx_new, 'All')
    assert(not err)
end

-- 测试设置迟滞量
local function test_set_hysteresis(policy_74, ctx_new)
    local err = safe_call(policy_74.SetHysteresis_PACKED, policy_74, ctx_new, 2)
    assert(not err)
    assert(policy_74[props.HYSTERESIS] == 2)

    err = safe_call(policy_74.SetHysteresis_PACKED, policy_74, ctx_new, -1)
    assert(err)

    err = safe_call(policy_74.SetHysteresis_PACKED, policy_74, ctx_new, 6)
    assert(err)
end

-- 测试设置曲线
local function test_set_policy(policy_74, ctx_new)
    -- "TemperatureRangeLow": [-127, 25, 30, 35, 40],
    -- "TemperatureRangeHigh":  [25, 30, 35, 40, 127],
    -- "SpeedRangeLow":         [80, 90, 95, 98, 100],
    -- "SpeedRangeHigh":        [80, 90, 95, 98, 100]

    -- 设置与原来相比有转速下降了的曲线
    local err = safe_call(policy_74.SetCustomCoolingPolicy_PACKED, policy_74, ctx_new,
        {25, 30, 35, 40}, {80, 90, 92, 98, 100})
    assert(err)

    -- 设置与原来相比转速上升的曲线
    err = safe_call(policy_74.SetCustomCoolingPolicy_PACKED, policy_74, ctx_new,
        {25, 30, 35, 40}, {88, 90, 95, 98, 100})
    assert(not err, 'err_msg:%s' .. tostring(err))
    assert(table.concat(policy_74.SpeedRangeLow, ' ') == '88 90 95 98 100')
end

-- 设置目标温度
local function test_set_target_temp(req_74, ctx_new)
    -- CSR配置值45
    local err = safe_call(req_74.SetBasicCoolingTargetTemperature_PACKED, req_74, ctx_new, 44)
    assert(not err, 'err_msg:%s' .. tostring(err))
    assert(req_74[props.TARGET_TEMP_CELSIUS] == 44)

    err = safe_call(req_74.SetBasicCoolingTargetTemperature_PACKED, req_74, ctx_new, 46)
    assert(err)
end

-- 设置全速阈值
local function test_set_max_allowed_temperature(req_74, ctx_new)
    -- CSR配置值70
    local err = safe_call(req_74.SetMaxAllowedTemperature_PACKED, req_74, ctx_new, 69)
    assert(not err, 'err_msg:%s' .. tostring(err))
    assert(req_74[props.MAX_ALLOWED_TEMPERATURE_CELSIUS] == 69, 'actual: ' ..
        req_74[props.MAX_ALLOWED_TEMPERATURE_CELSIUS])

    err = safe_call(req_74.SetMaxAllowedTemperature_PACKED, req_74, ctx_new, 71)
    assert(err)
end

-- 设置温度失效转速
local function test_set_failed_value(req_74, ctx_new)
    -- CSR配置值80
    local err = safe_call(req_74.SetFailedValue_PACKED, req_74, ctx_new, 81)
    assert(not err, 'err_msg:%s' .. tostring(err))
    assert(req_74[props.FAILED_VALUE] == 81)

    err = safe_call(req_74.SetMaxAllowedTemperature_PACKED, req_74, ctx_new, 79)
    assert(err)
end

-- 设置SmartCooling数组
local function test_smart_cooling_target_temp(req_75, ctx_new)
    -- CSR配置值45, 42, 48
    local err = safe_call(req_75.SetSmartCoolingTargetTemperature_PACKED, req_75, ctx_new, {45, 41, 48})
    assert(not err, 'err_msg:%s' .. tostring(err))
    assert(mc_utils.table_compare(req_75[props.SMART_COOLING_TARTGET_TEMPERATURE_CELSIUS], {45, 41, 48}))

    err = safe_call(req_75.SetSmartCoolingTargetTemperature_PACKED, req_75, ctx_new, {45, 43, 48})
    assert(err)
end

function test_rpc.main(bus, c_config_obj, c_policy_1_obj, ctx_new)
    log:notice('================ test rpc start ================')
    local l_objs = l_objs_init(bus)
    test_get_specific_pwm(l_objs.cooling_policies_obj, c_config_obj, ctx_new)
    set_smart_cooling_mode_test(c_config_obj, ctx_new)
    set_env_temp_curve_exp_test(bus, c_config_obj, c_policy_1_obj, ctx_new)
    set_fan_level_test(c_config_obj, ctx_new, l_objs)
    test_set_unexpected_ctrlmode(c_config_obj, ctx_new)
    test_set_cooling_medium(bus, c_config_obj, ctx_new)
    test_set_outlet_csutom_target(bus, c_config_obj, l_objs.req_7_obj, ctx_new)
    -- 获取自定义目标温度点测试
    tese_get_custom_target_temperatures(c_config_obj, ctx_new)
    tese_get_abnormal_policy_effective_status(c_config_obj, ctx_new)

    test_set_target_temp(l_objs['req_74'], ctx_new)
    test_set_max_allowed_temperature(l_objs['req_74'], ctx_new)
    test_set_failed_value(l_objs['req_74'], ctx_new)
    test_smart_cooling_target_temp(l_objs['req_75'], ctx_new)
    test_set_hysteresis(l_objs['policy_74'], ctx_new)
    test_set_policy(l_objs['policy_74'], ctx_new)
    log:notice('================ test rpc complete ================')
end

return test_rpc