-- Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. 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 bs = require 'mc.bitstring'
local log = require 'mc.logging'
local ncsi_standard = require 'protocol_open.protocol.ncsi_standard'

local ncsi_mellanox = class(ncsi_standard)
local nsci_oem_request_packet_type<const> = 0x50
local nsci_oem_response_packet_type<const> = 0xD0
local mellanox_manufacture_id<const> = 0x8119

local response_bs<const> = bs.new([[<<
    response_code:16/big,
    reason_code:16/big,
    manufacture_id:32/big,
    cmd_mellanox:8,
    mellanox_cmd_id:8,
    parameter:8,
    data/string
>>]])

local request_bs<const> = bs.new([[<<
    manufacture_id:32/big,
    cmd_mellanox:8,
    mellanox_cmd_id:8,
    parameter:8,
    extra_cmd:8
>>]])

local request_params_template<const> = {
    channel_id = true,
    package_id = true,
    cmd_mellanox = true,
    mellanox_cmd_id = true,
    parameter = true,
    extra_cmd = true,
    data = true
}

function ncsi_mellanox:construct_request_data(ctx, request)
    ctx.manufacture_id = mellanox_manufacture_id
    ctx.cmd_mellanox = request.cmd_mellanox
    ctx.mellanox_cmd_id = request.mellanox_cmd_id
    ctx.parameter = request.parameter or 0
    ctx.extra_cmd = request.extra_cmd or 0

    local data = request_bs:pack({
        manufacture_id = ctx.manufacture_id,
        cmd_mellanox = ctx.cmd_mellanox,
        mellanox_cmd_id = ctx.mellanox_cmd_id,
        parameter = ctx.parameter,
        extra_cmd = ctx.extra_cmd
    })

    return ncsi_mellanox.super.construct_request_data(self, ctx, {
        packet_type = nsci_oem_request_packet_type,
        expect_rsp_packet_type = nsci_oem_response_packet_type,
        channel_id = request.channel_id,
        package_id = request.package_id,
        data = data .. (request.data or '')
    })
end

function ncsi_mellanox:unpack_response_data(ctx, rsp_bin)
    local rsp = response_bs:unpack(rsp_bin, true)

    if not rsp then
        log:debug('[protocol %s]: empty data received for ncsi_huawei response', self.name)
        return nil
    end

    if rsp.response_code ~= 0 then
        log:debug('[protocol %s]: unsuccessful request with response code: %s, reason code: %s',
            self.name, rsp.response_code, rsp.reason_code)
        return nil
    end

    if not rsp.manufacture_id or rsp.manufacture_id ~= mellanox_manufacture_id then
        log:debug('[protocol %s]: invalid response data with wrong manufacture_id: %s', self.name,
            rsp.manufacture_id)
        return nil
    end

    if not rsp.cmd_mellanox or rsp.cmd_mellanox ~= ctx.cmd_mellanox or not rsp.mellanox_cmd_id or
        rsp.mellanox_cmd_id ~= ctx.mellanox_cmd_id or not rsp.parameter or rsp.parameter ~=
        ctx.parameter then
        log:debug(
            '[protocol %s]: invalid response data with cmd: cmd_mellanox: %s, mellanox_cmd_id: %s, parameter: %s',
            self.name, rsp.cmd_mellanox, rsp.mellanox_cmd_id, rsp.parameter)
        return nil
    end

    return rsp.data
end

function ncsi_mellanox:ctor()
    self.name = 'ncsi_mellanox'
    self.request_params_template = request_params_template
end

return ncsi_mellanox
