-- 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 m = {}

local cjson = require 'cjson'
local log = require 'mc.logging'
local mdb_service = require 'mc.mdb.mdb_service'
local FAN_INTERFACE<const> = 'bmc.kepler.Systems.Fan'

-- 获取进风口的自定义曲线数据
function m.get_temperature(custom_inlet_policy_obj)
    local res = cjson.json_object_new_object()
    local env_temp_range = cjson.json_object_new_array()
    res['TemperatureRangeCelsius'] = cjson.null
    res['FanSpeedPercents'] = cjson.null
    res['MinFanSpeedPercents'] = cjson.null
    res['MaxFanSpeedPercents'] = cjson.null
    -- next方式判断是否存在自定义进风口曲线
    if next(custom_inlet_policy_obj) ~= nil then
        -- 第1位的温度数字为温度极小值不显示
        for idx = 2, #custom_inlet_policy_obj.TemperatureRangeLow do
            env_temp_range[#env_temp_range + 1] = custom_inlet_policy_obj.TemperatureRangeLow[idx]
        end
        res['TemperatureRangeCelsius'] = env_temp_range
        res['FanSpeedPercents'] = cjson.json_object_from_table(custom_inlet_policy_obj.SpeedRangeLow)
        res['MinFanSpeedPercents'] = custom_inlet_policy_obj.FanSpeedRangePercents[1]
        res['MaxFanSpeedPercents'] = custom_inlet_policy_obj.FanSpeedRangePercents[2]
    end
    return res
end

function m.get_target(data)
    local tmp_data = cjson.json_object_to_table(data)
    local ret = {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}}
    for _, obj in ipairs(tmp_data) do
        ret[obj.TemperatureType].CustomTargetTemperatureCelsius =
            obj.TargetTemperatureCelsius == 0 and cjson.null or obj.TargetTemperatureCelsius
        ret[obj.TemperatureType].MinTargetTemperatureCelsius =
            obj.MinTargetTemperatureCelsius == 0 and cjson.null or obj.MinTargetTemperatureCelsius
        ret[obj.TemperatureType].MaxTargetTemperatureCelsius =
            obj.MaxTargetTemperatureCelsius == 0 and cjson.null or obj.MaxTargetTemperatureCelsius
    end
    return ret
end

function m.delete_first_member(env_temps)
    local env_temp_range = {}
    for idx = 2, #env_temps do
        env_temp_range[#env_temp_range + 1] = env_temps[idx]
    end
    return env_temp_range
end

local function invalid_value_transform(threshold)
    local res = {}
    for _, item in ipairs(threshold) do
        local data = item == 255 and cjson.null or item
        table.insert(res, data)
    end
    return res
end

function m.get_temperatures_info(temperatures_info)
    local res = cjson.json_object_new_array()
    for _, temp_info in pairs(temperatures_info) do
        local data = cjson.json_object_new_object()
        data['Name'] = temp_info.Name
        data['ReadingValue'] = ((temp_info.Status == '' and temp_info.ReadingValue == 255) or
            temp_info.ReadingValue == 32768 or temp_info.ReadingValue == 16384) and cjson.null or temp_info.ReadingValue
        data['Status'] = temp_info.Status == '' and cjson.null or temp_info.Status
        data['CoordinateX'] = temp_info.CoordinateX
        data['CoordinateY'] = temp_info.CoordinateY
        data['UpperThreshold'] = cjson.json_object_from_table(
            invalid_value_transform({string.byte(temp_info.UpperThreshold, 1, #temp_info.UpperThreshold)}))
        data['LowerThreshold'] = cjson.json_object_from_table(
            invalid_value_transform({string.byte(temp_info.LowerThreshold, 1, #temp_info.LowerThreshold)}))
        res[#res + 1] = data
    end
    return res
end

-- 设置MPC开关时若没有资源树路径应当报错
function m.mpc_is_supported()
    local ok, rsp = pcall(mdb_service.is_valid_path, bus, '/bmc/kepler/Systems/1/MPCConfig')
    if not ok or not rsp.Result then
        log:error('The MPC resource tree path does not exist, err(%s)', rsp.message)
        local args = 'ModelPredictiveControlEnabled'
        local err = custom_messages.PropertyModificationNotSupported(args)
        err.RelatedProperties = {'#/' .. args}
        error(err)
    end
    return true
end

function m.get_speed(front_speed, rear_speed)
    local front_rpm = front_speed
    local rear_rpm = rear_speed
    if front_rpm ~= 0 then
        return front_rpm
    elseif rear_rpm ~= 0 then
        return rear_rpm
    end
    return 0
end

function m.get_speed_ratio(obj_info)
    local front_rpm = obj_info.FrontSpeed
    local rear_rpm = obj_info.RearSpeed
    local front_max = obj_info.FrontMaxSpeed
    local rear_max = obj_info.RearMaxSpeed
    if front_rpm ~= 0 and front_max ~= 0 then
        return math.floor(front_rpm * 100 / front_max)
    elseif rear_rpm ~= 0 and rear_max ~= 0 then
        return math.floor(rear_rpm * 100 / rear_max)
    end
    return 0
end

function m.get_single_speed_ratio(speed, max_speed)
    local front_rpm = speed
    local front_max = max_speed
    if front_rpm ~= 0 and front_max ~= 0 then
        return math.floor(front_rpm * 100 / front_max)
    end
    return 0
end

function m.get_single_expected_speed_ratio(exp_pwm, max_pwm)
    if exp_pwm ~= 0 and max_pwm ~= 0 then
        return math.floor((exp_pwm * 100 / max_pwm) + 0.5)
    end
    return 0
end

function m.get_sort_fans_info(input)
    local table_input = cjson.json_object_to_table(input)
    local fan_objs = {}
    for _, path in pairs(table_input) do
        local temp_obj = mdb.get_object(bus, path, FAN_INTERFACE)
        local fan_obj = {}
        local twins_obj = {}
        if temp_obj.IsTwins then
            -- 先添加前转子对象
            fan_obj.Name = 'Fan' .. temp_obj.FanId .. ' Front'
            fan_obj.Model = temp_obj.Model
            fan_obj.Speed = temp_obj.FrontSpeed * temp_obj.Coefficient
            fan_obj.SpeedRatio = m.get_single_speed_ratio(temp_obj.FrontSpeed, temp_obj.FrontMaxSpeed)
            fan_obj.PartNumber = temp_obj.PartNumber
            fan_obj.Presence = temp_obj.FrontPresence
            fan_obj.FanId = temp_obj.FanId
            fan_obj.ExpectedSpeedRatio =
                m.get_single_expected_speed_ratio(temp_obj.ExpectedPWM, temp_obj.MaxSupportedPWM)
            fan_obj.DutyCycle = temp_obj.PWMPercentage
            table.insert(twins_obj, fan_obj)
            -- 再添加后转子对象
            fan_obj = {}
            fan_obj.Name = 'Fan' .. temp_obj.FanId .. ' Rear'
            fan_obj.Model = temp_obj.Model
            fan_obj.Speed = temp_obj.RearSpeed * temp_obj.Coefficient
            fan_obj.SpeedRatio = m.get_single_speed_ratio(temp_obj.RearSpeed, temp_obj.RearMaxSpeed)
            fan_obj.PartNumber = temp_obj.PartNumber
            fan_obj.Presence = temp_obj.RearPresence
            fan_obj.FanId = temp_obj.FanId
            fan_obj.ExpectedSpeedRatio =
                m.get_single_expected_speed_ratio(temp_obj.ExpectedPWM, temp_obj.MaxSupportedPWM)
            fan_obj.DutyCycle = temp_obj.PWMPercentage
            table.insert(twins_obj, fan_obj)
            -- 保证接口响应不变更，需嵌套保存数据
            table.insert(fan_objs, twins_obj)
        else
            fan_obj.Name = 'Fan' .. temp_obj.FanId
            fan_obj.Model = temp_obj.Model
            fan_obj.Speed = m.get_speed(temp_obj.FrontSpeed, temp_obj.RearSpeed)
            fan_obj.SpeedRatio = m.get_speed_ratio(temp_obj)
            fan_obj.PartNumber = temp_obj.PartNumber
            fan_obj.Presence = temp_obj.RearPresence
            fan_obj.FanId = temp_obj.FanId
            fan_obj.ExpectedSpeedRatio =
                m.get_single_expected_speed_ratio(temp_obj.ExpectedPWM, temp_obj.MaxSupportedPWM)
            fan_obj.DutyCycle = temp_obj.PWMPercentage
            table.insert(twins_obj, fan_obj)
            -- 保证接口响应不变更，需嵌套保存数据
            table.insert(fan_objs, twins_obj)
        end
    end
    table.sort(fan_objs, function(a, b)
        return a[1].FanId < b[1].FanId
    end)
    return cjson.json_object_from_table(fan_objs)
end

return m
