-- 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 mc_utils = require 'mc.utils'

local m = {}
local IPV4_PATH<const> = '/bmc/kepler/Managers/1/EthernetInterfaces/Ipv4'
local IPV4_INTERFACE<const> = 'bmc.kepler.Managers.EthernetInterfaces.Ipv4'
local ETHERNET_PATH<const> = '/bmc/kepler/Managers/1/EthernetInterfaces'
local ETHERNET_INTERFACE<const> = 'bmc.kepler.Managers.EthernetInterfaces'
local MGMT_PORT_INTERFACE<const> =
    'bmc.kepler.Managers.EthernetInterfaces.MgmtPort'
local DEDICATED_TYPE<const> = 'Dedicated'

-- 获取NCSI网口端口号
local function get_eth_host_port()
    local eth_obj = mdb.get_object(bus, ETHERNET_PATH, ETHERNET_INTERFACE)
    local active_port = mdb.get_object(bus, ETHERNET_PATH .. '/' .. eth_obj.PortId, MGMT_PORT_INTERFACE)
    -- 如果当前是专用口，固定返回2，和v2保持一致
    if active_port.Type == DEDICATED_TYPE then
        return 2
    end
    -- NCSI口返回端口号
    return active_port.DevicePortId + 1 -- 返回时需加1，snmp回显时会减掉1
end

function m.get_network_rsp()
    local ipv4_obj = mdb.get_object(bus, IPV4_PATH, IPV4_INTERFACE)
    local ipv4_addr = ipv4_obj.IpAddr
    local submask = ipv4_obj.SubnetMask
    local default_gateway = ipv4_obj.DefaultGateway
    local ip_source = ipv4_obj.IpMode == 'Static' and 1 or 2
    local eth_obj = mdb.get_object(bus, ETHERNET_PATH, ETHERNET_INTERFACE)
    local mac = eth_obj.Mac
    local port = mdb.get_object(bus, ETHERNET_PATH .. '/' .. eth_obj.PortId,
                                MGMT_PORT_INTERFACE)
    local eth_mode = 0
    local eth_mode_table = {LOM = 2, Dedicated = 1, ExternalPCIe = 4}
    if eth_obj.NetMode == 'Automatic' then
        eth_mode = 3
    else
        if eth_mode_table[port.Type] ~= nil then
            eth_mode = eth_mode_table[port.Type]
        end
    end
    local vlan_id = ''
    if not eth_obj.VLANEnable then
        vlan_id = 'off'
    else
        vlan_id = tostring(eth_obj.VLANId)
    end
    local eth_info = string.format('%s,%s,%s', ipv4_addr, submask,
                                   default_gateway)
    local ipv4_enable = eth_obj.IpVersion == 'IPv6' and 1 or 2
    local info = {
        ethNum = 0,
        ethIPAddress = ipv4_addr,
        ethNetmask = submask,
        ethDefaultGateway = default_gateway,
        ethIPSource = ip_source,
        ethMACAddress = mac,
        ethType = port.Type == DEDICATED_TYPE and 1 or 2, -- 1表示mgmt，2表示share
        ethHostPort = get_eth_host_port(),
        ethEnable = 2,
        ethMode = eth_mode,
        vlanID = vlan_id,
        ethInfo = eth_info,
        ethIPv4Enable = ipv4_enable
    }
    info['@Instance'] = {info.ethNum + 1}

    return {info}
end

local function get_port_id_by_type(type)
    local port_id = nil
    local ports = mdb.get_sub_objects(bus, ETHERNET_PATH, MGMT_PORT_INTERFACE)
    for _, value in pairs(ports) do
        -- 默认切到port1和v2保持一致
        if value.Type == type and value.DevicePortId == 1 then
            return value.Id
        end
    end
    return port_id
end

function m.get_net_mode(eth_mode)
    local eth_obj = mdb.get_object(bus, ETHERNET_PATH, ETHERNET_INTERFACE)
    -- 3表示自适应模式
    if eth_mode == 3 then
        -- 如果当前为自适应模式不作处理
        if eth_obj.NetMode == 'Automatic' then return {SetFlag = false} end
        return {
            SetFlag = true,
            NetMode = 'Automatic',
            PortId = eth_obj.PortId,
            VLANEnable = eth_obj.VLANEnable,
            VLANId = eth_obj.VLANId
        }
    end
    local port = mdb.get_object(bus, ETHERNET_PATH .. '/' .. eth_obj.PortId,
                                MGMT_PORT_INTERFACE)
    local port_id = nil
    if eth_mode == 2 and port.Type ~= 'LOM ' then
        port_id = get_port_id_by_type('LOM')
    elseif eth_mode == 1 and port.Type ~= 'Dedicated' then
        port_id = 1
    elseif eth_mode == 4 and port.Type ~= 'ExternalPCIe' then
        port_id = get_port_id_by_type('ExternalPCIe')
    end
    if port_id == nil then port_id = eth_obj.PortId end
    return {
        SetFlag = true,
        NetMode = 'Fixed',
        PortId = port_id,
        VLANEnable = eth_obj.VLANEnable,
        VLANId = eth_obj.VLANId
    }
end

function m.get_ipv4_info(eth_info)
    local info = mc_utils.split(eth_info, ',')
    return {IpAddr = info[1], SubnetMask = info[2], DefaultGateway = info[3]}
end

function m.get_ip_version(ipv4_enable)
    local ip_version = mdb.get_object(bus, ETHERNET_PATH, ETHERNET_INTERFACE)
                           .IpVersion
    if ip_version == 'IPv4' and ipv4_enable == 1 then
        error(custom_messages.OperationNotAllowed())
    end
    if ip_version == 'IPv6' and ipv4_enable == 2 then return 'IPv4AndIPv6' end
    if ip_version == 'IPv4AndIPv6' and ipv4_enable == 1 then return 'IPv6' end
    return ip_version
end

-- 根据传入的NCSI端口号获取要切换的网口
function m.get_port_id_by_host_port(host_port)
    local eth_obj = mdb.get_object(bus, ETHERNET_PATH, ETHERNET_INTERFACE)
    local active_port = mdb.get_object(bus, ETHERNET_PATH  .. '/' .. eth_obj.PortId, MGMT_PORT_INTERFACE)
    local active_port_type = active_port.Type
    local port_id = nil
    local ports = mdb.get_sub_objects(bus, ETHERNET_PATH, MGMT_PORT_INTERFACE)
    for _, value in pairs(ports) do
        if value.Type == active_port_type and value.DevicePortId == host_port - 1 then
            port_id = value.Id
        end
    end
    if port_id == nil then
        custom_messages.PortNotExist(active_port_type, host_port - 1)
    end
    return port_id
end

return m
