-- 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 skynet = require 'skynet'
local log = require 'mc.logging'
local class = require 'mc.class'
local client = require 'network_adapter.client'
local ncsi_core = require 'ncsi.ncsi_core'

local VLAN_ONLY<const> = 0x1

local c_lldp = class()

function c_lldp:ctor(db)
    self.db = db
    self.is_process = false
end

function c_lldp:init()
    client:SubscribeLldpConfigLLDPOverNCSIStateChanged(function(ctx, state)
        log:debug('Recevied lldp over ncsi state(%s) change signal', state)
        self:process_lldp_over_ncsi_state(state)
    end)
end

function c_lldp:process_lldp_over_ncsi_state(state)
    if self.is_process then
        log:debug('lldp over ncsi state change is processing')
        return
    end
    skynet.fork_once(function()
        self.is_process = true
        pcall(function()
            self:set_lldp_state(state)
            if not state then
                -- 关闭lldp时，恢复ncsi vlan使能状态
                self:recover_vlan_enable_state()
            end
        end)
        self.is_process = false
        log:debug('lldp over ncsi state change end')
    end)
end

function c_lldp:set_lldp_state(state)
    local ok
    local eth_id = self.db:select(self.db.NcsiNCInfo):first().EthId
    local eth_name = 'eth' .. eth_id
    local ports = self.db:select(self.db.NcsiNCPortInfo):all()
    for _, port in pairs(ports) do
        log:debug('Set lldp state to port%d. LinkStatus = %s, PortAvailable = %s', port.PortId,
            port.LinkStatus, port.PortAvailable)
        if port.LinkStatus == 'Connected' and port.PortAvailable then
            ok = ncsi_core.ncsi_set_lldp_status(eth_name, port.PackageId, port.ChannelId,
                state and 1 or 0) -- 1 : enable , 0: disable
            log:debug('Set lldp over ncsi state %s', ok and 'success' or 'failed')
        end
    end
end

function c_lldp:recover_vlan_enable_state()
    local db = self.db
    local nc_info = db:select(db.NcsiNCInfo):first()
    if not nc_info then
        log:error('Get nc info error')
        return
    end
    local active_port_id = nc_info.ActivePort
    local port = db:select(db.NcsiNCPortInfo):where({PortId = active_port_id}):first()
    if not port then
        log:debug('Can not find active port.')
        return
    end
    local eth_name = 'eth' .. nc_info.EthId
    if nc_info.VlanState or nc_info.MultiVlanState then
        ncsi_core.ncsi_enable_vlan_req(port.PackageId, port.ChannelId, eth_name, VLAN_ONLY)
    else
        ncsi_core.ncsi_disable_vlan_req(port.PackageId, port.ChannelId, eth_name)
    end
end

return c_lldp
