-- 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 log = require 'mc.logging'
local mdb = require 'mc.mdb'
local c_object_manage = require 'mc.orm.object_manage'
local client = require 'network_adapter.client'
local card_manage = require 'device.class.nic_mgmt.card.card_manage'

local card_init = {}

local PMU_PATH<const> = '/bmc/kepler/Systems/1/Pmu'
local PMU_INTERFACE<const> = 'bmc.kepler.Systems.Pmu'

-- 获取网口集合
local function get_network_ports(orm_obj)
    local ports = orm_obj.children
    table.sort(ports, function(a, b)
        return a.PortID < b.PortID
    end)
    orm_obj.ports_count = #ports
    return ports
end

-- 更新资产UUID
local function update_asset_uuid_proc(ports, orm_obj)
    card_manage.update_asset_uuid_info(orm_obj)
    for _, port in pairs(ports) do
        port.mac_change:on(function ()
            card_manage.update_asset_uuid_info(orm_obj)
        end)
    end
end

local function update_net_dev_func_capabilities(ports, orm_obj)
    local func_type = 0
    for _, port in pairs(ports) do
        func_type = func_type | (port.NetDevFuncType or 0)
    end
    orm_obj.NetDevFuncCapabilities = func_type
end

local function sync_nic_op_temp(ports, orm_obj)
    if not string.find(orm_obj.Name, 'NIC') then
        return
    end

    if not ports or #ports == 0 or not ports[1]:get_optical_module() then
        return
    end

    client:OnPmuPropertiesChanged(function (values, _, _)
        if values.SFPMaxTemperature then
            for _, port in ipairs(ports) do
                port:get_optical_module().TemperatureCelsius = values.SFPMaxTemperature:value()
            end
        end
    end)

    local bus = c_object_manage.get_instance().bus
    local ok, obj = pcall(mdb.get_object, bus, PMU_PATH, PMU_INTERFACE)
    if not ok or not obj then
        return
    end
    for _, port in ipairs(ports) do
        port:get_optical_module().TemperatureCelsius = obj.SFPMaxTemperature
    end
end

-- 对象分发完成后，主动获取bios状态
local function set_attention_on_complete(orm_obj)
    if not orm_obj.HotPluggable then
        return
    end
    local bios_obj = client:GetBiosBiosObject()
    card_manage.set_attention_on_bios(orm_obj, bios_obj.SystemStartupState)
end

local function update_net_port_bdf(ports, orm_obj)
    if orm_obj.SpecialPcieCard then
        orm_obj:next_tick(function ()
            card_manage.update_1822_port_bdf(ports, orm_obj)
        end)
        return
    end
    orm_obj:next_tick(function ()
        card_manage.update_port_bdf(ports, orm_obj)
    end)
end

local function update_port_mac_action(mac_info, port)
    local MAC_ADDR_DEFAULT<const> = '00:00:00:00:00:00'
    local INVALID_DATA_STRING<const> = 'N/A'

    if port.WorkloadType ~= 1 then
        return
    end

    for _, mac in ipairs(mac_info) do
        if port.PortID == mac[1] then
            port.MACAddress = mac[3]
        end
    end

    if port.PermanentMACAddress == MAC_ADDR_DEFAULT or
        port.PermanentMACAddress == INVALID_DATA_STRING then
        port.PermanentMACAddress = port.MACAddress
    end
end

local function update_port_mac(ports, orm_obj)
    if STOP_INIT then
        -- ut不进行这里，否则会死循环
        return
    end

    while true do
        for _, port in pairs(ports) do
            update_port_mac_action(orm_obj.PfMacInfo, port)
        end
        orm_obj:sleep_ms(20000) -- 等待20秒钟
    end
end

local function start(orm_obj)
    log:notice("card orm obj start, name:%s, type=%s", orm_obj.NodeId, orm_obj.Type)
    -- 获取网口集合
    local ports = get_network_ports(orm_obj)

    -- 更新资产UUID
    update_asset_uuid_proc(ports, orm_obj)

    -- 更新网卡能力
    update_net_dev_func_capabilities(ports, orm_obj)

    -- NIC卡需要从pmu同步光模块
    orm_obj:next_tick(sync_nic_op_temp, ports, orm_obj)

    -- 支持热插拔的卡主动获取bios状态
    orm_obj:next_tick(set_attention_on_complete, orm_obj)

    -- 更新网口BDF
    update_net_port_bdf(ports, orm_obj)

    -- 获取四元组信息
    orm_obj:next_tick(function ()
        card_manage.update_quater_info(orm_obj)
    end)

    -- 获取六口卡的后2口的mac地址
    orm_obj:next_tick(update_port_mac, ports, orm_obj)

    -- 初始化NPU处理
    card_manage.init_npu_proc(orm_obj)
end

function card_init.init(orm_obj)
    log:notice('card orm obj init start, NodeId is %s', orm_obj.NodeId)
    card_manage.init_asset_data_info(orm_obj)
    card_manage.register_listen_callback(orm_obj)
    card_manage.init_id(orm_obj)
    orm_obj.na_object_name = orm_obj.path:match('([^/]+)$')
    start(orm_obj)
    log:notice('card orm obj init success, NodeId is %s', orm_obj.NodeId)
end

return card_init