-- 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 lu = require 'luaunit'
local c_controller = require 'controller.controller_object'
local sml = require 'sml'
local c_storageconfig = require 'storageconfig.storageconfig_object'
local drive_collection = require 'drive.drive_collection'
local storage_bus = require 'storage_bus'
local volume_collection = require 'volume.volume_collection'
local common_def = require 'common_def'

TEST_Controller_Object = {}

function TEST_Controller_Object:test_get_ctrl_pd_list()
    local asset_sample = {
        Id = 1,
        tasks_pause = false,
        TypeId = 99,
        timeout_times = 0
    }
    local config = c_storageconfig.new({bus = 0, db = 1})
    config.power_on = false
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_pd_list = function(...)
        error(0x1002)
    end
    local ret = c_controller.get_ctrl_pd_list(asset_sample)
    lu.assertEquals(ret, nil)
end

function TEST_Controller_Object:test_check_pd_missing()
    local controller_obj = {
        Id = 1
    }
    local ret = false
    local origin_func = drive_collection.get_all_drives()
    drive_collection.get_all_drives = function()
        return {
            {
                Presence = 1,
                RefControllerId = 1,
                check_missing = function ()
                    ret = true
                end
            }
        }
    end
    c_controller.check_pd_missing(controller_obj)
    lu.assertEquals(ret, true)
    drive_collection.get_all_drives = origin_func
end

function TEST_Controller_Object:test_ctor_set_update_queue()
    local origin_get_instance = storage_bus.get_instance
    storage_bus.get_instance = function()
        return { bus = 0 }
    end

    local obj = {
        Id = 1,
        path = 'test1',
        Eid = 0,
        Phyaddr = 0
    }

    local controller = {
        super = {
            init = function() end
        }
    }

    -- 调用构造函数，不走 orm 的 new/init 逻辑
    c_controller.ctor(controller, obj)

    lu.assertNotNil(controller.update_queue)
    lu.assertEquals(type(controller.update_queue), 'function')

    storage_bus.get_instance = origin_get_instance
end

function TEST_Controller_Object:test_on_update_volume_array_use_update_queue()
    local config = c_storageconfig.get_instance()
    config.power_on = 0

    local origin_get_instance = storage_bus.get_instance
    storage_bus.get_instance = function()
        return { bus = 0 }
    end

    local obj = {
        Id = common_def.INVALID_U8,
        path = 'test2',
        Eid = 0,
        Phyaddr = 0
    }

    local controller = {
        super = {
            init = function() end
        }
    }

    c_controller.ctor(controller, obj)
    -- 避免 init 里调用真实实现
    controller.set_default_values = function() end
    controller.set_default_volume_manage_values = function() end
    controller.set_default_health_status = function() end

    local update_volume_list_called = 0
    local update_array_list_called = 0

    controller.update_volume_list = function(self)
        update_volume_list_called = update_volume_list_called + 1
    end

    controller.update_array_list = function(self)
        update_array_list_called = update_array_list_called + 1
    end

    c_controller.init(controller)
    controller.on_update_volume_array:emit()

    lu.assertEquals(update_volume_list_called, 1)
    lu.assertEquals(update_array_list_called, 1)

    storage_bus.get_instance = origin_get_instance
end

function TEST_Controller_Object:test_start_update_ld_list_task_use_update_queue()
    local config = c_storageconfig.get_instance()
    config.power_on = 1

    local origin_get_instance = storage_bus.get_instance
    storage_bus.get_instance = function()
        return { bus = 0 }
    end

    local obj = {
        Id = 1,
        path = 'test3',
        Eid = 0,
        Phyaddr = 0
    }

    local controller = {
        super = {
            init = function() end
        }
    }

    c_controller.ctor(controller, obj)
    controller.TypeId = 0

    local update_array_list_called = 0
    local update_volume_list_called = 0

    controller.update_array_list = function(self)
        update_array_list_called = update_array_list_called + 1
    end

    controller.update_volume_list = function(self)
        update_volume_list_called = update_volume_list_called + 1
    end

    controller.update_phy_info = function(self)
    end

    controller.new_task = function(self)
        return {
            loop = function(task_self, fn)
                fn({
                    stop = function()
                    end
                })
                return {
                    set_timeout_ms = function()
                    end
                }
            end
        }
    end

    c_controller.start_update_ld_list_task(controller)

    lu.assertEquals(update_array_list_called, 1)
    lu.assertEquals(update_volume_list_called, 1)

    storage_bus.get_instance = origin_get_instance
end

function TEST_Controller_Object:test_update_volume_list_with_valid_volume_list()
    local controller = {
        Id = 1,
        volume_list = {
            old = {
                key = 'old'
            }
        }
    }

    controller.get_ctrl_volume_list = function(self)
        return {
            {
                key = 'new'
            }
        }
    end

    controller.compare_volume_list = function(self, volume_list)
        -- 只验证删除路径是否生效
        return {}, { 'old' }
    end

    local origin_get_ctrl_init_state = sml.get_ctrl_init_state
    sml.get_ctrl_init_state = function(id)
        return 2
    end

    local origin_vc_get_instance = volume_collection.get_instance
    local add_called = 0
    local del_called = 0

    volume_collection.get_instance = function()
        return {
            on_add_volume = {
                emit = function(self, volume)
                    add_called = add_called + 1
                end
            },
            on_del_volume = {
                emit = function(self, volume)
                    del_called = del_called + 1
                end
            }
        }
    end

    c_controller.update_volume_list(controller)

    lu.assertEquals(del_called, 1)

    volume_collection.get_instance = origin_vc_get_instance
    sml.get_ctrl_init_state = origin_get_ctrl_init_state
end