-- 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 c_object = require 'mc.orm.object'
local log = require 'mc.logging'
local client = require 'thermal_mgmt.client'
local c_fan_object = require 'fan_object'

local thermal_configuration_manager = c_object('ThermalConfiguration')

function thermal_configuration_manager:ctor()
    self.object_collection = {}
end

-- 正则匹配风扇板槽位号
local function match_fan_board_slot(fan_position)
    local fan_board_slot = string.match(fan_position, "^CLU(%d+)$")
    if fan_board_slot then
        return tonumber(fan_board_slot) -- 将匹配到的数字转换为整数返回
    else
        return nil -- 如果不符合条件，则返回nil
    end
end

function thermal_configuration_manager:check_standby()
    return self.StandbyFan == 1
end

local function alloc_slot(fan_objects, start_slot)
    for _, fan_object in pairs(fan_objects) do
        -- 拦截fan_object ctor阶段拿到的persist_fan_id为-1场景
        if fan_object.persist_fan_id == -1 then
            log:warn("The value of persist_fan_id of the %s is invalid", fan_object.ObjectName)
            goto continue
        end

        -- 已经重分配过FanId则不再分配
        if fan_object.FanId ~= fan_object.persist_fan_id then
            goto continue
        end

        fan_object.Slot = start_slot + fan_object.persist_fan_id - 1
        fan_object.FanId = fan_object.Slot
        log:notice('set %s slot to %u', fan_object.ObjectName, fan_object.Slot)

        ::continue::
    end
end

function thermal_configuration_manager:realloc_fan_slot(position)
    if self.object_collection[position].fans and self.object_collection[position].fan_board and
        self.FanStartSlot[self.object_collection[position].fan_board.Slot] then
        -- 如果fan_board和fan都已经分发, 则重分配fan_id
        log:notice('realloc_fan_slot   %s', position)
        self:next_tick(function ()
            alloc_slot(self.object_collection[position].fans,
                self.FanStartSlot[self.object_collection[position].fan_board.Slot])
        end)
    end
end

function thermal_configuration_manager:collect_fan_objects(position)
    log:notice('collect_fan_objects   %s', position)
    if not self.object_collection[position] then
        self.object_collection[position] = {}
    end
    self.object_collection[position].fans = c_fan_object.collection:fetch_by_position(position)
    if self:check_standby() then
        for _, fan_object in pairs(self.object_collection[position].fans) do
            fan_object.standbyfan = true
        end
    end

    for _, fan_object in pairs(self.object_collection[position].fans) do
        local fan_board_slot = match_fan_board_slot(fan_object.Position)
        -- 匹配失败直接退出
        if not fan_board_slot then
            break
        end
        if not self.object_collection[position] then
            self.object_collection[position] = {}
        end
        self.object_collection[position].fan_board = {}
        self.object_collection[position].fan_board.Slot = fan_board_slot
        log:notice('The slot number of the fan board in position %s is %s', position, fan_board_slot)
        break
    end

    self:realloc_fan_slot(position)
end

function thermal_configuration_manager:collect_fan_board_objects(object, position)
    log:notice('collect_fan_board_objects   %s', position)
    if not self.object_collection[position] then
        self.object_collection[position] = {}
    end
    self.object_collection[position].fan_board = object
    self:realloc_fan_slot(position)
end

function thermal_configuration_manager:start()
    client:ForeachBoardObjects(function (obj)
        -- 存在先于thermal_configuration加载的fan_board
        if obj.BoardType == 'FanBoard' then
            log:notice('fan_board position: %s', obj.extra_params.Position)
            self.object_collection[obj.extra_params.Position] = { fan_board = obj }
        end
    end)

    -- 存在先于thermal_configuration加载的fan
    local fan_position_collection = {}
    c_fan_object.collection:fold(function (_, obj)
        fan_position_collection[obj:get_position()] = true
    end)
    for position, _ in pairs(fan_position_collection) do
        self:collect_fan_objects(position)
    end
end

function thermal_configuration_manager:init()
    self:connect_signal(self.on_add_object_complete, function()
        log:notice('[thermal_mgmt_app] on_add_object_complete thermal_configuration, FanStartSlot:' ..
            string.rep(' %s', #self.FanStartSlot), table.unpack(self.FanStartSlot))
        self:next_tick(self.start, self)
    end)
    thermal_configuration_manager.super.init(self)
end

return thermal_configuration_manager
