-- Copyright (c) 2025 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 class = require 'mc.class'
local skynet = require 'skynet'
local log = require 'mc.logging'
local base_messages = require 'messages.base'
local curl = require 'lcurl.core'
local cjson = require 'cjson'
local worker = require 'worker.core'
local http = require 'http'

local m = class()
local regex_receiver_service_mdb_path = '/bmc/kepler/ObservabilityService/Receivers/(%d)'
local pending_count = 0
local pending_req = {}
local MAX_CONCURRENT_REQUEST_NUM<const> = 10 --最多同时处理10个请求

local test_worker = [[
    local log = require 'mc.logging'
    local cjson = require 'cjson'
    local otel_traces = require 'otel.trace'
    local otel_logs = require 'otel.logs'

    log:set_log_module_name('observability')
    local logger = otel_logs.create_otel_logger('test_logs')
    logger:log(9, "Test log record")
    logger:flush()

    local tracer = otel_traces.get_tracer('test_traces', '', '')
    local span = tracer:start_span('test_span', {component = "observability"}, {kind = "Server", specified_ratio = 1})
    span:add_event('start test')
    span:finish()

    g_result = cjson.encode({
        RetCode = 0
    })
]]

function m:ctor(db, module_name)
    self.db = db
    self.module_name = module_name

    local ret = curl.global_init()
    if ret ~= 0 then
        log:error('curl global init failed, err:%s', ret)
    end
end

local function easy_perform_worker()
    pending_count = pending_count + 1
    if pending_count > MAX_CONCURRENT_REQUEST_NUM then
        pending_req[#pending_req + 1] = coroutine.running()
        skynet.wait()
    end
    local ok, ret = pcall(function()
        local w = worker.new(1)
        w:start(test_worker)

        local timeout_count = 800
        while not w:is_complete() do
            timeout_count = timeout_count - 1
            if timeout_count == 0 then
                log:error('easy perform time out')
                w:stop()
                return {RetCode = -1}
            end

            skynet.sleep(10)
        end

        local ret = cjson.decode(w:get_global('g_result'))
        w:stop()
        return ret
    end)
    if not ok then
        log:error("submit observability test message failed, reason: %s", ret)
        ret = {RetCode = -1}
    end
    pending_count = pending_count - 1
    local co = table.remove(pending_req, 1)
    if co then
        skynet.wakeup(co)
    end
    return ret
end

function m:test_submit_data(object, ctx)
    local receiver_id = string.match(object.path, regex_receiver_service_mdb_path)
    if receiver_id == nil then
        log:error("Get observability receiver id failed")
        log:operation(ctx:get_initiator(), self.module_name, 'Test observability receiver failed')
        error(base_messages.ServiceDisabled('Observability'))
    end

    local observability_obj = self.db:select(self.db.ObservabilityService):first()
    local receiver_obj = self.db:select(self.db.Receivers):where(self.db.Receivers.ReceiverId:eq(receiver_id)):first()
    local op_log = 'Test observability receiver' .. (receiver_id + 1) .. ' failed'

    if observability_obj == nil or receiver_obj == nil then
        log:error("Get observability config failed")
        log:operation(ctx:get_initiator(), self.module_name, op_log)
        error(base_messages.ServiceDisabled('Observability'))
    end

    if observability_obj.Enabled == false or receiver_obj.Enabled == false or receiver_obj.Address == '' then
        log:error('Observability is not enabled or receiver %s address is empty, test failed', receiver_id + 1)
        log:operation(ctx:get_initiator(), self.module_name, op_log)
        error(base_messages.ServiceDisabled('Observability'))
    end

    local ret = easy_perform_worker()
    local ret_code = ret and ret.RetCode

    if ret_code == 0 then
        op_log = 'Test observability receiver' .. (receiver_id + 1) .. ' successfully'
    end

    log:operation(ctx:get_initiator(), self.module_name, op_log)
end

return m