-- 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 lu = require 'luaunit'
local power_mgmt_app = require 'power_mgmt_app'
local c_psu_object = require 'device.psu'
local enums = require 'macros.power_mgmt_enums'
local power_mgmt_utils = require 'power_mgmt_utils'
local utils = require 'mc.utils'

TestPowerMgmtApp = {}

local function mock_cabinet_software_type()
    local old_get_instance = power_mgmt_utils.get_instance
    power_mgmt_utils.get_instance = function ()
        return {
            get_chassis_type = function ()
                return enums.SOFTWARE_TYPE.CABINET
            end
        }
    end
    return function ()
        power_mgmt_utils.get_instance = old_get_instance
    end
end

function TestPowerMgmtApp:test_init_debug_service()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local bus = ''
    local tmp = {
        power_debug_service_class = {
            new = function (b)
                return 1
            end
        },
        debug_service_enable = false
    }
    local ok = pcall(function ()
        return power_mgmt_app.init_debug_service(tmp, bus)
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(tmp.debug_service_enable, true)
end

function TestPowerMgmtApp:test_create_debug_service()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local tmp = {
        debug_service_enable = true,
        debug_service_list = {},
        power_mgmt_debug_service = {
            CreateOnePowerDebug = function ()
                return
            end
        }
    }
    local psu_object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function ()
        power_mgmt_app.create_debug_service(tmp, psu_object)
    end)
    lu.assertEquals(ok, true)
end

function TestPowerMgmtApp:test_create_debug_service_disabled()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local tmp = {
        debug_service_enable = false,
        debug_service_list = {}
    }
    local psu_object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function ()
        power_mgmt_app.create_debug_service(tmp, psu_object)
    end)
    lu.assertEquals(ok, true)
    -- 验证 debug_service_list 没有被修改
    lu.assertEquals(next(tmp.debug_service_list), nil)
end

function TestPowerMgmtApp:test_delete_debug_service()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)

    local mock_debug_obj = { ObjectName = 'OnePowerDebug_0_010109' }
    local remove_called = false

    -- Mock class_mgnt 模块
    local package_loaded = package.loaded
    local original_class_mgnt = package_loaded['mc.class_mgnt']
    local mock_class_mgnt_instance = {
        remove = function(self, obj)
            remove_called = true
            lu.assertEquals(obj, mock_debug_obj)
        end
    }
    package_loaded['mc.class_mgnt'] = function(class_name)
        lu.assertEquals(class_name, 'OnePower')
        return mock_class_mgnt_instance
    end

    -- 重新加载 power_mgmt_app 以使用新的 mock
    package_loaded['power_mgmt_app'] = nil
    power_mgmt_app = require 'power_mgmt_app'

    local tmp = {
        debug_service_enable = true,
        debug_service_list = {
            ['OnePowerDebug_0_010109'] = mock_debug_obj
        }
    }
    local psu_object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function ()
        power_mgmt_app.delete_debug_service(tmp, 'OnePower', psu_object)
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(remove_called, true)
    lu.assertEquals(tmp.debug_service_list['OnePowerDebug_0_010109'], nil)
    
    -- 恢复原始的 class_mgnt
    package_loaded['mc.class_mgnt'] = original_class_mgnt
    package_loaded['power_mgmt_app'] = nil
end

function TestPowerMgmtApp:test_delete_debug_service_disabled()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local tmp = {
        debug_service_enable = false,
        debug_service_list = {}
    }
    local psu_object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function ()
        power_mgmt_app.delete_debug_service(tmp, 'OnePower', psu_object)
    end)
    lu.assertEquals(ok, true)
end

function TestPowerMgmtApp:test_delete_debug_service_not_found()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local tmp = {
        debug_service_enable = true,
        debug_service_list = {}
    }
    local psu_object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function ()
        power_mgmt_app.delete_debug_service(tmp, 'OnePower', psu_object)
    end)
    lu.assertEquals(ok, true)
end

function TestPowerMgmtApp:test_register_debug_rpc_methods()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local tmp = {
        power_debug_service_class = {
            implement_methods = function ()
                return
            end
        },
        power_mgmt_debug_service = {
            implement_methods = function ()
                return
            end
        }
    }
    local ok = pcall(function ()
        power_mgmt_app.register_debug_rpc_methods(tmp)
    end)
    lu.assertEquals(ok, true)
end

function TestPowerMgmtApp:test_on_reboot_prepare()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local monitor_stop_status = false
    local tmp = {
        psu_service = {
            psm_monitor_stop = function ()
                monitor_stop_status = true
                return
            end
        }
    }
    local ok = pcall(function ()
        power_mgmt_app.on_reboot_prepare(tmp)
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(monitor_stop_status, true)
end

function TestPowerMgmtApp:test_on_reboot_cancel()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local monitor_start_status = false
    local tmp = {
        psu_service = {
            psm_monitor_start = function ()
                monitor_start_status = true
                return
            end
        }
    }
    local ok = pcall(function ()
        power_mgmt_app.on_reboot_cancel(tmp)
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(monitor_start_status, true)
end

function TestPowerMgmtApp:test_set_power_reset_type()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    power_mgmt_app.psu_service = {
        set_power_reset_type = function (...)
            return
        end
    }
    local ok = pcall(function ()
        power_mgmt_app:set_power_reset_type(nil, {SlotNumber = 1}, "ForceRestart")
    end)
    lu.assertEquals(ok, true)
end

local E_OK <const> = nil -- 函数执行成功返回nil
local E_FAILED <const> = '' -- 空错误信息
function TestPowerMgmtApp:test_set_power_capacitor_enable_1()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    power_mgmt_app.psu_service = {
        set_power_capacitor_enable = function (...)
            return E_OK
        end
    }
    local psu = {}
    psu.SlotNumber = 1
    local c_psu_object = require 'device.psu'
    lu.assertEquals(c_psu_object ~= nil, true)
    c_psu_object.collection.find = function (...)
        return psu
    end
    local ok = pcall(function ()
        power_mgmt_app:set_power_capacitor_enable(nil, {SlotNumber = 1}, "ForceOff")
    end)
    lu.assertEquals(ok, true)
    power_mgmt_app.psu_service = {
        set_power_capacitor_enable = function (...)
            return E_FAILED
        end
    }
    ok = pcall(function ()
        power_mgmt_app:set_power_capacitor_enable(nil, {SlotNumber = 1}, "ForceOff")
    end)
    lu.assertEquals(ok, false)
end

function TestPowerMgmtApp:test_on_delete_object()
    local mock_data = {
        psu_service = {
            delete_psu_slot_object = function()
                return true
            end
        }
    }
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    local ok = pcall(function()
        return power_mgmt_app.on_delete_object(mock_data, 'PsuSlot', '', '')
    end)
    lu.assertEquals(ok, true)
end

function TestPowerMgmtApp:test_on_delete_object_one_power()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)

    local delete_debug_service_called = false
    local delete_debug_service_class_name = nil
    local delete_debug_service_object = nil

    local mock_data = {
        debug_service_enable = true,
        debug_service_list = {},
        delete_debug_service = function(self, class_name, object)
            delete_debug_service_called = true
            delete_debug_service_class_name = class_name
            delete_debug_service_object = object
        end
    }
    local object = {
        ObjectName = 'OnePower_0_010109'
    }
    local ok = pcall(function()
        return power_mgmt_app.on_delete_object(mock_data, 'OnePower', object, '')
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(delete_debug_service_called, true)
    lu.assertEquals(delete_debug_service_class_name, 'OnePower')
    lu.assertEquals(delete_debug_service_object, object)
end

function TestPowerMgmtApp:test_reset_power_distribution_metrics()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    
    -- 保存原始的mc_utils.time函数
    local mc_utils = require 'mc.utils'
    local original_time = mc_utils.time
    local original_date_format = mc_utils.date_format
    
    -- 模拟当前时间
    local mock_time = { tv_sec = 1234567890, tv_usec = 0 }
    mc_utils.time = function() return mock_time end
    
    -- 模拟日期格式化
    local expected_time_str = '2009-02-13T23:31:30Z'
    mc_utils.date_format = function(sec, format, utc) return expected_time_str end
    
    -- 模拟机柜软件类型
    local restore = mock_cabinet_software_type()
    
    -- 测试用对象
    local test_obj = {
        EnergykWh = 100.5,
        EnergySensorResetTime = ''
    }
    
    -- 调用被测试函数
    power_mgmt_app:reset_power_distribution_metrics(nil, test_obj)
    
    -- 验证结果
    lu.assertEquals(test_obj.EnergykWh, 0)
    lu.assertEquals(test_obj.EnergySensorResetTime, expected_time_str)
    
    -- 测试当obj为nil时的情况（不应该出错）
    local ok = pcall(function()
        power_mgmt_app:reset_power_distribution_metrics(nil, nil)
    end)
    lu.assertEquals(ok, true)
    
    -- 恢复原始函数
    mc_utils.time = original_time
    mc_utils.date_format = original_date_format
    restore()
end

function TestPowerMgmtApp:test_set_power_distribution_transfer_control()
    local power_mgmt_app = require 'power_mgmt_app'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    
    -- 模拟c_psu_object.collection.fold方法
    local c_psu_object = require 'device.psu'
    lu.assertEquals(c_psu_object ~= nil, true)
    
    -- 模拟机柜软件类型
    local restore = mock_cabinet_software_type()
    
    -- 仅测试没有set_power_supply_circuit方法的PSU对象的情况
    c_psu_object.collection.fold = function(self, func)
        -- 模拟没有set_power_supply_circuit方法的PSU对象
        func(nil, {})
    end
    
    local obj = { ActiveMainsId = "0" }
    local ctx = {}
    
    local ok = pcall(function()
        power_mgmt_app:set_power_distribution_transfer_control(ctx, obj)
    end)
    
    lu.assertEquals(ok, true)
    
    -- 恢复原始函数
    restore()
end

function TestPowerMgmtApp:test_create_pdu_object()
    local power_mgmt_app = require 'power_mgmt_app'
    local base_service = require 'power_mgmt.service'
    lu.assertEquals(power_mgmt_app ~= nil, true)
    
    -- 模拟机柜软件类型
    local restore = mock_cabinet_software_type()
    
    -- 模拟power_distribution_mgmt和object_add_callback
    local object_add_callback_called = false
    local created_object
    power_mgmt_app.power_distribution_mgmt = {
        object_add_callback = function(self, object)
            object_add_callback_called = true
            -- object参数已经是创建好的对象，不需要再调用回调
            created_object = object
        end
    }
    
    -- 模拟base_service:CreatePowerDistributionId
    local original_create_power_distribution_id = base_service.CreatePowerDistributionId
    base_service.CreatePowerDistributionId = function(self, id, callback)
        -- 创建一个模拟对象
        local obj = {}
        -- 调用回调函数设置对象属性
        callback(obj)
        return obj  -- 返回创建的对象
    end
    
    -- 调用被测试函数
    power_mgmt_app:create_pdu_object()
    
    -- 验证结果
    lu.assertEquals(object_add_callback_called, true)
    lu.assertEquals(created_object ~= nil, true)
    lu.assertEquals(created_object.EquipmentType, "PowerShelf")
    lu.assertEquals(created_object.ObjectName, "PowerShelf1")
    
    -- 恢复原始函数
    power_mgmt_app.CreatePowerDistribution = nil
    power_mgmt_app.power_distribution_mgmt = nil
    base_service.CreatePowerDistributionId = original_create_power_distribution_id
    restore()
end

function TestPowerMgmtApp:test_change_db_journal_mode()
    utils.is_qemu = function()
        return true
    end
    local local_db = {exec = function()
        return true
    end}
    power_mgmt_app.local_db = local_db
    power_mgmt_app:change_db_journal_mode()
    
    lu.assertIsTrue(power_mgmt_app.local_db:exec('PRAGMA journal_mode=WAL; PRAGMA journal_size_limit=1048576;') ~= nil)

    utils.is_qemu = function()
        return false
    end
    power_mgmt_app:change_db_journal_mode()
    lu.assertIsTrue(power_mgmt_app.local_db:exec('PRAGMA journal_mode=WAL; PRAGMA journal_size_limit=1048576;') ~= nil)
end


