-- Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. 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 class = require 'mc.class'
local log = require 'mc.logging'
local singleton = require 'mc.singleton'
local cooling_rpc = require 'basic_cooling.cooling_intf.cooling_rpc'
local air_config = require 'basic_cooling.cooling_config.air_config'
local fans_config = require 'basic_cooling.cooling_config.fans_config'
local cooling_requirements = require 'basic_cooling.cooling_requirememts'
local cooling_policys = require 'basic_cooling.cooling_policys'
local cooling_enums = require 'basic_cooling.define.cooling_enums'
local props = require 'basic_cooling.define.cooling_properties'

local requirement_prop_method_map = {
    ['SmartCoolingTargetTemperatureCelsius'] = 'SetSmartCoolingTargetTemperature',
    ['CustomTargetTemperatureCelsius'] = 'SetTargetTemperature',
    ['TargetTemperatureCelsius'] = 'SetBasicCoolingTargetTemperature',
    ['MaxAllowedTemperatureCelsius'] = 'SetMaxAllowedTemperature',
    ['FailedValue'] = 'SetFailedValue'
}

local policy_prop_method_map = {
    ['Hysteresis'] = 'SetHysteresis'
}

local interface_config = class()

function interface_config:ctor()
    self.air_config_instance = air_config:get_instance()
    self.fans_config_instance = fans_config.get_instance()
    self.cooling_rpc_instance = cooling_rpc.get_instance()
    self.cooling_requirements_instance = cooling_requirements.get_instance()
    self.cooling_policys_instance = cooling_policys.get_instance()
end

function interface_config:get_fan_ctrl_mode()
    return self.fans_config_instance:get_ctrl_mode()
end

function interface_config:set_fan_ctrl_mode(ctx, mode, time)
    local ok, rsp = pcall(
        self.cooling_rpc_instance.SetCtrlMode, self.cooling_rpc_instance, nil, ctx, mode, time
    )
    if not ok then
        log:error('Set fan ctrl mode failed, err_msg: %s', rsp)
        return false
    end
    return true
end

function interface_config:get_fan_manual_level()
    return self.fans_config_instance:get_manual_level()
end

function interface_config:set_fan_maunal_level(ctx, manual_level)
    local ok, rsp = pcall(
        self.cooling_rpc_instance.SetManualLevel, self.cooling_rpc_instance, nil, ctx, 0xff, manual_level
    )
    if not ok then
        log:error('Set fan manual level failed, err_msg: %s', rsp)
        return false
    end
    return true
end

function interface_config:get_smart_cooling_mode()
    return self.fans_config_instance:get_smart_cooling_mode()
end

function interface_config:is_smart_cooling_enabled()
    return self.fans_config_instance:is_smart_cooling_enabled()
end

function interface_config:set_smart_cooling_mode(ctx, mode)
    if not self:is_smart_cooling_enabled() then
        log:error('Smart cooling mode is disabled')
        return false
    end
    local medium = self.fans_config_instance:get_medium()
    if not medium then
        log:error('Get cooling medium failed')
        return false
    end
    if not cooling_enums.medium_mode_mapping[medium] or not cooling_enums.medium_mode_mapping[medium][mode] then
        log:error('Invalid medium: %s, mode: %s', medium, mode)
        return false
    end
    local ok, rsp = pcall(
        self.cooling_rpc_instance.SetSmartCoolingMode, self.cooling_rpc_instance, nil, ctx, mode
    )
    if not ok then
        log:error('Set smart cooling mode failed, err_msg: %s', rsp)
        return false
    end
    return true
end

function interface_config:set_custom_target_temperature(ctx, temp_type, value)
    local ok, rsp
    local cooling_requirement_objs = self.cooling_requirements_instance:get_objs()
    local range = {}
    for _, obj in pairs(cooling_requirement_objs) do
        if obj[props.TEMPERATURE_TYPE] ~= temp_type then
            goto continue
        end
        range = obj[props.TARGET_TEMP_RANGE_CELSIUS]
        ok, rsp = pcall(self.cooling_requirements_instance.SetTargetTemperature, self.cooling_requirements_instance,
                        obj, ctx, value)
        if not ok then
            log:error('Set custom target temperature for Requirement (%s) failed, err_msg: %s',
                obj[props.REQUIREMENT_ID], rsp)
            return false, range
        else
            -- 只要存在一个自定义类型的调速被设置成功则为导入成功
            return true, range
        end
        ::continue::
    end
    return false, range
end

-- 获取自定义进风口调速曲线
function interface_config:get_custom_inlet_policy()
    return self.cooling_policys_instance:get_custom_inlet_policy()
end

function interface_config:set_custom_inlet_policy(ctx, temp_array, speed_array)
    local custom_inlet_policys = self.cooling_policys_instance:get_custom_inlet_policys()
    if not next(custom_inlet_policys) then
        log:error('Custom inlet policy is not exist')
        return false
    end
    local ok, rsp
    for _, obj in pairs(custom_inlet_policys) do
        ok, rsp = pcall(self.cooling_policys_instance.SetCustomCoolingPolicy, self.cooling_policys_instance,
            obj, ctx, temp_array, speed_array)
    end
    if not ok then
        log:error('Set custom inlet policy failed, err_msg: %s', rsp)
        return false
    end
    return true
end

function interface_config:get_cooling_requirement_obj_by_id(req_id)
    local cooling_requirement_objs = self.cooling_requirements_instance:get_objs()
    for _, obj in pairs(cooling_requirement_objs) do
        if obj[props.REQUIREMENT_ID] == req_id then
            return obj
        end
    end
    return nil
end

function interface_config:set_cooling_requirement_prop(ctx, obj, prop_name, set_value)
    if not requirement_prop_method_map[prop_name] then
        log:error('Could not find the method to set the property(%s)', prop_name)
        return false
    end
    local ok, rsp = pcall(
        obj[requirement_prop_method_map[prop_name]], obj ,ctx, set_value
    )
    if not ok then
        log:error('Set property %s of CoolingRequirement(RequirementId: %s) failed, err_msg: %s',
            prop_name, obj[props.REQUIREMENT_ID], rsp)
        return false
    end
    return true
end

function interface_config:get_custom_target_temperatures(ctx)
    local ok, rsp = pcall(
        self.cooling_rpc_instance.GetCustomTargetTemperatures, self.cooling_rpc_instance, nil, ctx
    )
    if not ok then
        log:error('Get custom target temperature failed, err_msg: %s', rsp)
        return {}
    end
    return rsp
end

function interface_config:get_custom_policy()
    return self.cooling_policys_instance:get_custom_policy()
end

function interface_config:get_cooling_requirement_objs()
    local objs = {}
    for _, obj in pairs(self.cooling_requirements_instance:get_objs()) do
        table.insert(objs, obj)
    end
    return objs
end

function interface_config:get_cooling_policy_objs()
    local objs = {}
    for _, obj in pairs(self.cooling_policys_instance:get_objs()) do
        table.insert(objs, obj)
    end
    return objs
end

function interface_config:get_policy_by_id(policy_idx)
    return self.cooling_policys_instance:get_policy_by_id(policy_idx)
end

function interface_config:set_cooling_policy_prop(ctx, obj, prop_name, set_value)
    if not policy_prop_method_map[prop_name] then
        log:error('Could not find the method to set the property(%s)', prop_name)
        return false
    end
    local ok, rsp = pcall(
        obj[policy_prop_method_map[prop_name]], obj, ctx, set_value
    )
    if not ok then
        log:error('Set property %s of CoolingPolicy(PolicyIdx: %s) failed, err_msg: %s',
            prop_name, obj[props.POLICY_IDX], rsp)
        return false
    end
    return true
end

function interface_config:set_init_level_in_startup(ctx, value)
    local air_config_obj = self.air_config_instance:get_obj()
    if not air_config_obj then
        log:error('Get air cooling config object failed')
        return false
    end
    air_config_obj.InitialSpeedPercent = value
    return true
end

function interface_config:get_init_level_in_startup()
    local air_config_obj = self.air_config_instance:get_obj()
    if not air_config_obj then
        log:error('Get air cooling config object failed')
        return nil
    end
    return air_config_obj.InitialSpeedPercent
end

return singleton(interface_config)