-- 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 cooling_enums = require 'basic_cooling.define.cooling_enums'
local utils = require 'basic_cooling.cooling_utils'
require "thermal_mgmt.json_types.LiquidCoolingConfig"
local props = require 'basic_cooling.define.cooling_properties'
local custom_msg = require 'messages.custom'
local privilege = require 'mc.privilege'
local Singleton = require 'mc.singleton'
local cooling_pumps = require 'basic_cooling.cooling_device.cooling_pumps'
local cooling_config_base = require 'basic_cooling.cooling_config.base'

local pumps_config = class(cooling_config_base)

function pumps_config:ctor(service)
    self.service = service
    self.obj = nil
    self.cooling_pumps = cooling_pumps.get_instance()
    self.manual_mode_status_table = {
        last_timeout = nil, -- 上次更新的timeout
        real_timeout = nil, -- 用于业务逻辑计算的超时时间
        expir_time = nil,   -- timeout结束的时间
        pre_manual_level_tab = nil
    }
end

function pumps_config:set_obj(object)
    self:register()
    self.obj = object
end

function pumps_config:register()
    self.service:ImplLiquidCoolingConfigLiquidCoolingConfigSetManualLevel(function(obj, ctx, ...)
        return self:SetManualLevel(obj, ctx, ...)
    end)
    self.service:ImplLiquidCoolingConfigLiquidCoolingConfigSetCtrlMode(function(obj, ctx, ...)
        return self:SetCtrlMode(obj, ctx, ...)
    end)
end

function pumps_config:get_manual_mode_status_table()
    return self.manual_mode_status_table
end

function pumps_config:pump_ctrl_supported()
    if not self.obj then
        return false
    end
    return true
end

-- 设置泵的控制模式
function pumps_config:set_pump_ctrl_mode(mode, manual_time)
    if not self:pump_ctrl_supported() then -- 泵的配置对象未分发
        return false
    end
    if mode ~= cooling_enums.modes.Auto and 
        mode ~= cooling_enums.modes.Manual and 
        mode ~= cooling_enums.modes.Mixed then
        log:error('Ctrl mode(%s) is not supported', mode)
        return false
    end
    self.obj.CtrlMode = mode
    if mode == cooling_enums.modes.Manual then
        self.obj.TimeOut = manual_time
        -- 此处置为nil原因为设置新的超时时间后续需重新倒计时
        self.manual_mode_status_table.real_timeout = nil
    end
    self.cooling_pumps:set_all_cooling_device_manual_level(self.obj.ManualLevel)

    return true
end

-- 设置手动转速
function pumps_config:set_manual_level(value)
    if not self:pump_ctrl_supported() then
        return false
    end
    self.obj[props.CONF_MANUAL_LEVEL] = value
    self.cooling_pumps:set_all_cooling_device_manual_level(value)
    return true
end

function pumps_config:SetManualLevel(obj, ctx, pump_id, level)
    local pump_objs = self.cooling_pumps:get_objs()
    if pump_id ~= 0xff and not pump_objs[pump_id] then
        log:error('The pump(%s) is not exist', pump_id)
        utils.op(ctx, 'Set pump(%s) level to (%s) failed', pump_id, level)
        error(custom_msg.PropertyValueOutOfRange(pump_id, '%UnitId'))
    end
    if level < obj[props.LEVEL_RANGE][1] or level > obj[props.LEVEL_RANGE][2] then
        log:error("Level(%s) of pump is out of range, the correct range is %s to %s", level,
            obj[props.LEVEL_RANGE][1], obj[props.LEVEL_RANGE][2])
        utils.op(ctx, 'Set pump(%s) level to (%s) failed', pump_id, level)
        error(custom_msg.PropertyValueOutOfRange(level, '%Level'))
    end
    local ok
    if pump_id == 0xff then
        ok = self:set_manual_level(level)
        if not ok then
            log:error('Set pump level to (%d) failed', level)
            utils.op(ctx, "Set pump level to (%d) failed", level)
        else
            utils.op(ctx, "Set pump level to (%d) successfully", level)
        end
    else
        ok = self.cooling_pumps:set_single_cooling_device_manual_level(pump_id, level)
        if not ok then
            log:error("Set pump(%d) level to (%d) failed", pump_id, level)
            utils.op(ctx, "Set pump(%d) level to (%d) failed", pump_id, level)
        else
            utils.op(ctx, "Set pump(%d) level to (%d) successfully", pump_id, level)
        end
    end
end

-- 设置为自动模式的时候,不能设置手动模式超时时间,Conflict抛出在北向
function pumps_config:SetCtrlMode(obj, ctx, mode, timeout)
    -- 手动模式最大超时时间
    local MAX_PUMP_TIMEOUT <const> = 100000000
    
    if mode ~= cooling_enums.modes.Manual and 
        mode ~= cooling_enums.modes.Auto and 
        mode ~= cooling_enums.modes.Mixed then
        log:error('CtrlMode(%s) of pump is out of range', mode)
        utils.op(ctx, "Failed to set pump control mode to %s", mode)
        error(custom_msg.ValueOutOfRange('%CtrlMode'))
    end
    if timeout == 0 then
        timeout = MAX_PUMP_TIMEOUT
    elseif timeout > MAX_PUMP_TIMEOUT then
        log:error('Timeout(%s) of pump is out of range', timeout)
        utils.op(ctx, "Failed to set pump control mode to %s", mode)
        error(custom_msg.PropertyValueOutOfRange(timeout, '%Timeout'))
    end

    obj['CtrlMode'] = mode
    if mode == cooling_enums.modes.Manual then
        obj['TimeOut'] = timeout
        local cur_manual_level = self:get_manual_level()
        self.cooling_pumps:set_all_cooling_device_manual_level(cur_manual_level) -- 将当前config里面的手动模式转速属性设置给每个泵
        utils.op(ctx, "Set pump mode to (manual) and its expiry time to (%u) seconds successfully", timeout)
    elseif mode == cooling_enums.modes.Auto then
        utils.op(ctx, "Set pump mode to (auto) successfully")
    else
        utils.op(ctx, "Set pump mode to (mixed) successfully")
    end
end

-- 获取当前的泵板个数
function pumps_config:get_max_pump_num()
    if not self.obj then
        return nil
    end
    return self.obj[props.MAX_PUMP_NUM]
end

function pumps_config:set_active_algorithm(value)
    if not self.obj then
        return
    end
    if self.obj[props.ACTIVE_ALGORITHM] ~= value then
        self.obj[props.ACTIVE_ALGORITHM] = value
    end
end

return Singleton(pumps_config)