-- 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 ipmi = require 'manufacture.ipmi.cmds.GetDftResult'
local factory = require 'factory'
local bs = require 'mc.bitstring'
local context = require 'mc.context'
local mc_ipmi = require 'ipmi'
local log = require 'mc.logging'

local cc = mc_ipmi.types.Cc

local ipmi_handler = {}

local rsp_code = bs.new("<<result, dft_id, slot_id:32, dev_num, item_name:32/binary, description/string>>")

local END_MASK = 0x80

local status_table = {
    ["Complete"] = 0x00,
    ["Testing"] = 0x80,
    ["Unstart"] = 0x81
}

local result_table = {
    ["Succeed"] = 0,
    ["Failed"] = 1,
    ["Non"] = 0xFF
}

local function concat_rsp(obj, resp)
    local rsp = rsp_code:pack({result = result_table[resp.Status],
                            dft_id = obj.Id,
                            slot_id = obj.Slot,
                            dev_num = obj.DeviceNum,
                            item_name = obj.ItemName,
                            description = resp.Description})
    return rsp
end

local function response_error(code)
    return ipmi.GetDftResultRsp.new(code, END_MASK, "")
end

-- 根据offset返回结果
local function response_success(req, obj, rsp_info)
    local read_offset = req.ReadOffset
    local read_length = req.ReadLength
    local total_length = #rsp_info
    local end_of_list = 0

    local rsp
    if read_offset + read_length < total_length then
        end_of_list = end_of_list & (~END_MASK)
        rsp = string.sub(rsp_info, read_offset + 1, read_offset + read_length)
    else
        end_of_list = end_of_list | END_MASK
        rsp = string.sub(rsp_info, read_offset + 1)
    end
    return ipmi.GetDftResultRsp.new(status_table[obj.Status], end_of_list, rsp)
end

local req_tail_code = bs.new("<<slot_id:32, dev_num>>")

function ipmi_handler.get_test_item_info_by_dftid(req, HostId)
    local manufacture_service = factory.get_obj("manufacture_service")
    local tail = req_tail_code:unpack(req.Tail)
    if not tail then
        return nil
    end
    local obj = manufacture_service:get_obj_by_dftid(req.Command, tail.slot_id, tail.dev_num, HostId)
    if not obj then
        return nil
    end
    return obj
end

function ipmi_handler.get_obj_by_req(req, HostId)
    if not req.Tail or req.Tail ~= "" then
        return ipmi_handler.get_test_item_info_by_dftid(req, HostId)
    end
    local manufacture_service = factory.get_obj("manufacture_service")
    -- 检查类型是否存在
    if not manufacture_service:check_type_exist(req.Type, HostId) then
        return nil
    end
    -- 通过下标找对应对象
    return manufacture_service:get_obj_form_type_list_by_count(req.Type, req.Command, HostId)
end

function ipmi_handler.get_test_result(req, ctx)
    log:debug(" get dft result")
    local obj = ipmi_handler.get_obj_by_req(req, ctx.HostId or 0)
    if not obj then
        return response_error(cc.UnspecifiedError)
    end
    local ok, resp = obj.pcall:GetResult_PACKED(context.new())
    if not ok then
        return response_error(cc.UnspecifiedError)
    end
    if obj.Status ~= "Complete" then
        return response_error(status_table[obj.Status])
    end
    local ret, rsp_info = pcall(concat_rsp, obj, resp)
    if not ret then
        return response_error(cc.ParmOutOfRange)
    end
    log:notice("dft test get result: dft_id=%s slot=%s device_num=%s itemname=%s test_res=%s",
        obj.Id, obj.Slot, obj.DeviceNum, obj.ItemName, resp.Status)
    return response_success(req, obj, rsp_info)
end

return ipmi_handler