-- 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 log = require 'mc.logging'
local service = require 'observability.service'
local c_initiator = require 'mc.initiator'
local context = require 'mc.context'
local m_control = require 'public.control'

local module  = {}

module.initiator = c_initiator.new('N/A', 'N/A', 'N/A')

local observability_service_mdb_intf = 'bmc.kepler.ObservabilityService'
local module_name = 'observability'

local function set_config(db, name, value)
    local ok, err = pcall(function()
        db:update(db.ObservabilityService):value({[name] = value}):exec()
    end)
    if not ok then
        log:error('save property %s to db failed, reason: %s', name, err)
        return ok
    end
    log:notice('set observability server property(name=%s) successfully', tostring(name))
    return ok
end

local function after_change_enabled(obj, db, name, value, sender)
    local ok = set_config(db, name, value)
    local enabled_log = value and 'Enable' or 'Disable'
    local result = ok and 'successfully' or 'failed'
    local op_log = enabled_log .. ' observability ' .. result
    local initiator = (context.get_context() or context.new('N/A', 'N/A', '127.0.0.1')):get_initiator()
    log:operation(initiator, module_name, op_log)
end

local function after_change_TLSMode(obj, db, name, value, sender)
    local ok = set_config(db, name, value)
    local result = ok and 'successfully' or 'failed'
    local op_log = 'Set observability TLSMode to ' .. value .. ' ' .. result
    local initiator = (context.get_context() or context.new('N/A', 'N/A', '127.0.0.1')):get_initiator()
    log:operation(initiator, module_name, op_log)
end

local function after_change_server_identity(obj, db, name, value, sender)
    local ok = set_config(db, name, value)
    local result = ok and 'successfully' or 'failed'
    local op_log = 'Set observability server identity to ' .. value .. ' ' .. result
    local initiator = (context.get_context() or context.new('N/A', 'N/A', '127.0.0.1')):get_initiator()
    log:operation(initiator, module_name, op_log)
end

local after_change = {
    ['Enabled'] = function (...)
        after_change_enabled(...)
    end,
    ['TLSMode'] = function (...)
        after_change_TLSMode(...)
    end,
    ['ServerIdentity'] = function (...)
        after_change_server_identity(...)
    end
}

local function observability_config_changed_handle(obj, db, name, value, sender)
    if not after_change[name] then
        return
    end
    return after_change[name](obj, db, name, value, sender)
end

function module:register_observability_service(db, bus)
    self.db = db
    self.bus = bus

    local ok, obj = pcall(function() return self.db:select(self.db.ObservabilityService):first() end)
    if not ok then
        log:error('get observability database failed, reason: %s', obj)
        return
    end
    local observability_service = service:CreateObservabilityService()
    local observability_service_obj = observability_service:get_mdb_object(observability_service_mdb_intf)
    observability_service_obj.Enabled = obj.Enabled
    observability_service_obj.TLSMode = obj.TLSMode
    observability_service_obj.ServerIdentity = obj.ServerIdentity
    observability_service_obj.property_changed:on(function(name, value, sender)
        self.control:set_state_flag()
        return observability_config_changed_handle(observability_service_obj, db, name, value, sender)
    end
    )
end

function module:init(db, bus)
    self.control = m_control.get_instance()
    self:register_observability_service(db, bus)
end

return module
