-- Copyright (c) 2024-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 lu = require 'luaunit'
local json = require 'cjson'
local engine

TEST_config_engine = {}

function TEST_config_engine.setUp()
    package.loaded['config_mgmt.engine'] = nil
    engine = require 'config_mgmt.engine'
end

function TEST_config_engine.test_init()
    engine.init()
    local result = engine.export({}, nil)
    local decoded = json.decode(result)
    lu.assertNotNil(decoded.ConfigData.NetworkAdapterPreload)
    lu.assertIsTable(decoded.ConfigData.NetworkAdapterPreload)
end

function TEST_config_engine.test_register_dealer_already_registered()
    local mock1 = { import = function() end, export = function() return { { id = 1 } } end }
    local mock2 = { import = function() end, export = function() return { { id = 2 } } end }
    engine.register_dealer('DupClass', mock1)
    engine.register_dealer('DupClass', mock2)
    local result = engine.export({}, nil)
    local decoded = json.decode(result)
    lu.assertEquals(decoded.ConfigData.DupClass[1].id, 1, 'should keep first dealer, not overwrite')
end

function TEST_config_engine.test_import_no_config_data()
    engine.import({}, json.encode({ ConfigData = nil }), nil)
    engine.import({}, json.encode({}), nil)
end

function TEST_config_engine.test_import_invalid_json()
    lu.assertError(function()
        engine.import({}, 'invalid json', nil)
    end)
end

function TEST_config_engine.test_import_with_dealer()
    local import_called = false
    local mock_dealer = {
        import = function(_, ctx, obj)
            import_called = true
            lu.assertEquals(obj.NodeId.Value, 'node1')
        end,
        export = function() return {} end
    }
    engine.register_dealer('NetworkAdapterPreload', mock_dealer)

    local config_str = json.encode({
        ConfigData = {
            NetworkAdapterPreload = {
                { NodeId = { Value = 'node1' }, PortCount = { Value = 4, Import = true } }
            }
        }
    })
    engine.import({}, config_str, nil)
    lu.assertTrue(import_called)
end

function TEST_config_engine.test_import_empty_array()
    local import_called = false
    local mock_dealer = {
        import = function() import_called = true end,
        export = function() return {} end
    }
    engine.register_dealer('EmptyClass', mock_dealer)

    local config_str = json.encode({
        ConfigData = {
            EmptyClass = {}
        }
    })
    engine.import({}, config_str, nil)
    lu.assertFalse(import_called)
end

function TEST_config_engine.test_export_no_dealer()
    local config_str = json.encode({ ConfigData = {} })
    engine.import({}, config_str, nil)
    local result = engine.export({}, nil)
    lu.assertNotNil(result)
    local decoded = json.decode(result)
    lu.assertNotNil(decoded.ConfigData)
end

function TEST_config_engine.test_export_with_dealer()
    local mock_dealer = {
        import = function() end,
        export = function()
            return { { NodeId = 'n1', PortCount = 4 } }
        end
    }
    engine.register_dealer('TestExport', mock_dealer)

    local result = engine.export({}, nil)
    local decoded = json.decode(result)
    lu.assertEquals(#decoded.ConfigData.TestExport, 1)
    lu.assertEquals(decoded.ConfigData.TestExport[1].NodeId, 'n1')
    lu.assertEquals(decoded.ConfigData.TestExport[1].PortCount, 4)
end

function TEST_config_engine.test_import_unregistered_class()
    local config_str = json.encode({
        ConfigData = {
            UnknownClass = { { id = 1 } }
        }
    })
    lu.assertError(function()
        engine.import({}, config_str, nil)
    end)
end
