-- Copyright (c) 2026 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.

-- Description: 硬盘升级处理

local skynet = require 'skynet'
local log = require 'mc.logging'
local context = require 'mc.context'
local utils = require 'mc.utils'
local class = require 'mc.class'
local singleton = require 'mc.singleton'
local client = require 'storage.client'
local parser_cfg = require 'upgrade.parser_cfg'
local upgrade_defs = require 'upgrade.upgrade_defs'
local c_drive = require 'drive.drive_object'
local c_drive_collection = require 'drive.drive_collection'
local c_storageconfig = require 'storageconfig.storageconfig_object'
local common_def = require 'common_def'
local method_misc = require 'method_misc'
local sml = require 'sml'
local bus_monitor_service = require 'bus_monitor_service'
local fructrl_handle = require 'upgrade.fructrl_handle'

local drive_upgrade = class()

-- 检查是否是硬盘固件类型
local function is_drive_firmware(firmware_type)
    return firmware_type == upgrade_defs.FIRMWARE_TYPE_DRIVE
end

-- 筛选符合条件的目标硬盘(Model匹配且为自研RAID卡管理)
local function get_upgrade_target_drives(models)
    if not models or #models == 0 then
        return {}
    end

    local target_drives = {}
    c_drive.collection:fold(function(acc, obj, key)
        -- 检查硬盘在位
        if obj.Presence ~= 1 then
            return
        end

        -- 检查Model是否在支持列表中
        local model_matched = false
        for _, model in ipairs(models) do
            if obj.Model == model then
                model_matched = true
                break
            end
        end

        if not model_matched then
            return
        end

        -- 检查是否为华为自研RAID卡管理(通过method_misc:test_controller_vendor判断)
        if method_misc:test_controller_vendor(obj.RefControllerTypeId, common_def.VENDER_HUAWEI) then
            log:notice('[Drive Upgrade] add target drive: Name=%s, Model=%s, RefControllerTypeId=%s',
                obj.Name, obj.Model, obj.RefControllerTypeId)
            table.insert(target_drives, obj)
        end
    end, {})

    log:notice('[Drive Upgrade] get upgrade target drives, count = %s', #target_drives)
    return target_drives
end

-- 从 Redfish URI 严格解析出硬盘 Id（整型）：URI 必须为 <前缀><数字>，如 /redfish/v1/Chassis/1/Drives/HDDPlaneDisk1 -> 1
-- @return drive_id number or nil（格式不符或非数字结尾）
local function parse_drive_id_from_redfish_uri(uri)
    if type(uri) ~= 'string' or uri == '' then
        return nil
    end
    local id_str = uri:match('^' .. upgrade_defs.REDFISH_DRIVE_URI_PREFIX .. '(%d+)$')
    if not id_str then
        return nil
    end
    return tonumber(id_str)
end

-- 根据 Redfish URI 查找硬盘对象：先严格解析出 drive_id，再通过 drive_collection:get_drive_by_drive_id(drive_id) 获取
local function get_drive_by_redfish_uri(uri)
    local drive_id = parse_drive_id_from_redfish_uri(uri)
    if not drive_id then
        return nil
    end
    return c_drive_collection:get_drive_by_drive_id(drive_id)
end

-- 指定硬盘升级：校验 targets_str（逗号分隔的 Redfish URI 字符串）中的硬盘是否满足 在位 && 自研RAID卡管理 && Model
-- @param targets_str 字符串，例如 "/redfish/v1/Chassis/1/Drives/HDDPlaneDisk1,/redfish/v1/Chassis/1/Drives/HDDPlaneDisk2"
-- @return target_drives, err_msg；若 err_msg 非空表示校验失败；若 targets_str 为空则返回 nil, nil（沿用全量目标）
local function get_and_validate_target_drives_from_parameters(targets_str, models)
    if not models or #models == 0 then
        return nil, 'no model in cfg'
    end

    local target_drives = {}
    for uri in string.gmatch(targets_str, '([^,]+)') do
        if not parse_drive_id_from_redfish_uri(uri) then
            log:error('[Drive Upgrade] specified drive URI format invalid: %s', uri)
            return nil, 'invalid URI format: ' .. uri
        end
        local drive = get_drive_by_redfish_uri(uri)
        if not drive then
            log:error('[Drive Upgrade] specified drive not found: %s', uri)
            return nil, 'drive not found: ' .. uri
        end
        if drive.Presence ~= 1 then
            log:error('[Drive Upgrade] specified drive not present: %s (Name=%s)', uri, drive.Name)
            return nil, 'drive not present: ' .. uri
        end
        if not method_misc:test_controller_vendor(drive.RefControllerTypeId, common_def.VENDER_HUAWEI) then
            log:error('[Drive Upgrade] specified drive not under self-developed RAID: %s (Name=%s)', uri, drive.Name)
            return nil, 'not self-developed RAID: ' .. uri
        end
        local model_matched = false
        for _, m in ipairs(models) do
            if drive.Model == m then
                model_matched = true
                break
            end
        end
        if not model_matched then
            log:error('[Drive Upgrade] specified drive model not match: %s, Model=%s', uri, drive.Model or '')
            return nil, 'model not match: ' .. uri
        end
        log:notice('[Drive Upgrade] add specified target drive: URI=%s, Name=%s, Model=%s', uri, drive.Name, drive.Model)
        table.insert(target_drives, drive)
    end

    if #target_drives == 0 then
        log:error('[Drive Upgrade] no valid drive in parameters.Targets')
        return nil, 'no valid targets'
    end
    return target_drives, nil
end

-- 检查OS上电状态
-- @param operation: 操作类型描述（如"drive upgrade"或"drive activation"）
-- @return: upgrade_defs.RET.OK表示OS上电，upgrade_defs.RET.ERR表示OS未上电
local function check_os_power_state(operation)
    local smbios_status = c_storageconfig.get_instance().smbios_status
    local power_state = c_storageconfig.get_instance().power_state
    if smbios_status ~= upgrade_defs.SMBIOS_WRITE_FINISH or power_state ~= 'ON' then
        log:error('[Drive Upgrade] OS not ready for %s: smbios_status = %s, power_state = %s',
            operation, smbios_status, power_state)
        return upgrade_defs.RET.ERR
    end
    return upgrade_defs.RET.OK
end

-- 检查升级前置条件
local function check_upgrade_preconditions(self)
    -- 检查是否已经在升级中
    if self.is_drive_upgrading then
        log:error('[Drive Upgrade] drive firmware is upgrading')
        return upgrade_defs.RET.IN_UPGRADING
    end

    -- 检查是否有在位的硬盘
    local present_drives = c_drive_collection:get_presence_on_drives()
    if not present_drives or not next(present_drives) then
        log:error('[Drive Upgrade] no present drive found')
        return upgrade_defs.RET.ERR
    end

    -- 检查OS上电状态(硬盘升级依赖OS上电与RAID卡通信)
    if check_os_power_state('drive upgrade') ~= upgrade_defs.RET.OK then
        return upgrade_defs.RET.ERR
    end
    -- 在这里加下电锁，防止在升级过程中OS下电，超时时间10min
    if not fructrl_handle.set_power_off_lock_until_success(true, 600, upgrade_defs.POWER_OFF_LOCK_REASON) then
        log:error('[Drive Upgrade] set power off lock failed')
        return upgrade_defs.RET.ERR
    end
    return upgrade_defs.RET.OK
end

-- 清理升级资源
local function clear_drive_upgrade_resource(self)
    self.target_drives = {}
    self.cfgs = {}
    self.is_drive_upgrading = false
    self.upgraded_drives_success = {}
    -- 硬盘升级依赖系统上电，任意失败返回的场景解锁下电锁
    fructrl_handle.set_power_off_lock_until_success(false, 10, upgrade_defs.POWER_OFF_LOCK_REASON)
end

-- 清理待生效硬盘列表（从数据库和内存清除）
local function clear_pending_active_drives(self)
    local ok, err = pcall(function()
        self.reset_local_db.UpgradedDrivesPendingActive:truncate()
    end)
    if not ok then
        log:error('[Drive Upgrade] clear pending active drives failed err: %s', err)
    end
    self.upgraded_drives_success = {}
end

-- 根据整体区间和当前步数更新进度：
-- start_percent: 区间起始百分比，如20
-- end_percent: 区间结束百分比，如90
-- current_step: 当前已完成的步数，从1开始
-- total_steps: 总步数，如目标硬盘总数
local function update_progress_range(system_id, firmware_type, parameters,
    start_percent, end_percent, current_step, total_steps)
    if not total_steps or total_steps <= 0 then
        return
    end

    if current_step < 0 then
        current_step = 0
    elseif current_step > total_steps then
        current_step = total_steps
    end

    local range = end_percent - start_percent
    local percent = start_percent + range * current_step / total_steps
    percent = math.floor(percent + 0.5)

    client:UpdateServiceUpdateServiceUpdateUpgradeStatus(context.new(), system_id, firmware_type,
        0, percent, 'Running', parameters)
end

-- 准备阶段实际处理逻辑
local function drive_upgrade_prepare(self, cfg_path)
    -- 解析update.cfg获取支持升级的硬盘型号列表
    local cfgs = parser_cfg.get_cfgs(cfg_path)
    
    -- 删除不符合条件的配置项（只保留硬盘固件配置）
    local drive_firmware_count = 0
    for firmware_name, firmware_cfg in pairs(cfgs) do
        if firmware_cfg.component_id ~= upgrade_defs.DRIVE_COMPONENT_ID or
           firmware_cfg.component_idex ~= upgrade_defs.DRIVE_COMPONENT_IDEX then
            cfgs[firmware_name] = nil
        else
            drive_firmware_count = drive_firmware_count + 1
        end
    end

    self.cfgs = cfgs

    log:notice('[Drive Upgrade] prepare phase success, total drive firmware count = %s', drive_firmware_count)
    return upgrade_defs.RET.OK
end

-- 升级准备阶段
function drive_upgrade:on_upgrade_prepare(_, system_id, firmware_type, cfg_path, hpm_path, parameters)
    -- 只处理硬盘固件类型
    if not is_drive_firmware(firmware_type) then
        return
    end

    log:notice('[Drive Upgrade] prepare phase: system_id = %s, firmware_type = %s', system_id, firmware_type)

    -- 检查前置条件
    local ret = check_upgrade_preconditions(self)
    if ret ~= upgrade_defs.RET.OK then
        client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '',
            ret, parameters)
        return
    end

    -- 立即设置升级标志，防止并发调用
    self.is_drive_upgrading = true

    -- 设置cfg_path文件权限为secbox用户
    local ok, rsp = client:PFileFileChown(context.new(), nil, cfg_path, upgrade_defs.SECBOX_UID, upgrade_defs.SECBOX_GID)
    if not ok then
        log:error('[Drive Upgrade] chown cfg file failed, error %s', rsp)
        clear_drive_upgrade_resource(self)
        client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '',
            upgrade_defs.RET.ERR, parameters)
        return
    end

    -- 设置hpm_path文件权限为secbox用户
    ok, rsp = client:PFileFileChown(context.new(), nil, hpm_path, upgrade_defs.SECBOX_UID, upgrade_defs.SECBOX_GID)
    if not ok then
        log:error('[Drive Upgrade] chown hpm file failed, error %s', rsp)
        clear_drive_upgrade_resource(self)
        client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '',
            upgrade_defs.RET.ERR, parameters)
        return
    end

    -- 异步执行准备逻辑
    skynet.fork_once(function ()
        local ret_ok, ret_code = pcall(function ()
            return drive_upgrade_prepare(self, cfg_path)
        end)
        if not ret_ok then
            log:error('[Drive Upgrade] call drive upgrade prepare failed, err: %s', ret_code)
            clear_drive_upgrade_resource(self)
            ret_code = upgrade_defs.RET.ERR
        end

        if ret_code ~= upgrade_defs.RET.OK then
            clear_drive_upgrade_resource(self)
            log:error('[Drive Upgrade] upgrade prepare failed, ret_code = %s', ret_code)
        end
        -- 支持多firmware标志
        if parameters and parameters.FirmwareMode == upgrade_defs.FIRMWARE_MODE_MULTIPLE then
            parameters.MultipleSupported = upgrade_defs.MULTIPLE_SUPPORTED
        end
        client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '',
            ret_code, parameters)
    end)
end

-- 升级单个硬盘
local function upgrade_single_drive(self, drive, firmware_dir)
    if drive.Presence ~= 1 then
        log:running(log.RLOG_ERROR, 'Upgrade %s Firmware failed: drive not present', drive.Name)
        return
    end

    log:notice('[Drive Upgrade] %s start upgrade', drive.Name)
    local firmware_path = firmware_dir .. 'drive_img.bin'
    local ok, ret = pcall(sml.pd_upgrade_firmware, drive.RefControllerId, drive.device_id, firmware_path)
    if not ok or ret ~= common_def.RET_OK then
        log:error('[Drive Upgrade] upgrade drive firmware failed, drive: %s, error: %s', drive.Name, ret)
        log:running(log.RLOG_ERROR, 'Upgrade %s Firmware failed', drive.Name)
        return
    else
        log:notice('[Drive Upgrade] upgrade drive firmware success, drive: %s', drive.Name)
        log:running(log.RLOG_INFO, 'Upgrade %s Firmware successfully', drive.Name)
        -- 升级成功，插入到已升级成功列表
        table.insert(self.upgraded_drives_success, drive.Name)
    end
end

-- 升级执行阶段实际处理逻辑
local function drive_upgrade_process(self, system_id, firmware_type, file_path, parameters)
    -- 解析出升级目录和文件名
    local dir, firmware_name = parser_cfg.parse_dir(file_path)
    -- 解析出文件路径对应的cfg配置文件
    local cfg = self.cfgs[firmware_name]
    if not cfg then
        log:error('[Drive Upgrade] No cfg found for firmware: %s', firmware_name)
        return upgrade_defs.RET.ERR
    end
    -- 先判断是否指定硬盘：parameters.Targets 为逗号分隔的字符串且非空则为指定硬盘升级，否则走全量匹配
    if parameters and parameters.Targets and type(parameters.Targets) == 'string' and parameters.Targets ~= '' then
        local specified, err = get_and_validate_target_drives_from_parameters(parameters.Targets, cfg.model)
        if not specified then
            log:error('[Drive Upgrade] specified targets validation failed: %s', err or '')
            self.target_drives = {}  -- 任一指定硬盘不满足则不存在 target_drives
            return upgrade_defs.RET.ERR
        end
        self.target_drives = specified
    else
        self.target_drives = get_upgrade_target_drives(cfg.model)
    end
    if #self.target_drives == 0 then
        log:error('[Drive Upgrade] No drive matches firmware model during process stage')
        return upgrade_defs.RET.ERR
    end
    -- 上报初始进度20%
    client:UpdateServiceUpdateServiceUpdateUpgradeStatus(context.new(), system_id, firmware_type,
        0, 20, 'Running', parameters)
    -- 解压固件，最大解压限制100M
    utils.secure_tar_unzip(file_path, dir, 0x6400000, 1024)
    log:notice('[Drive Upgrade] process phase: upgrade %s drives', #self.target_drives)
    local total_drives = #self.target_drives
    for index, drive in ipairs(self.target_drives) do
        log:notice('[Drive Upgrade] upgrading drive: %s (Model=%s)', drive.Name, drive.Model)
        -- 检查OS上电状态(硬盘升级依赖OS上电与RAID卡通信)
        if check_os_power_state('drive upgrade') ~= upgrade_defs.RET.OK then
            return upgrade_defs.RET.ERR
        end
        upgrade_single_drive(self, drive, dir)
        -- 在[20, 90]区间内按硬盘个数平滑更新进度
        update_progress_range(system_id, firmware_type, parameters, 20, 90, index, total_drives)
    end
    -- 所有目标硬盘都成功升级才返回成功
    return (self.upgraded_drives_success and #self.upgraded_drives_success == #self.target_drives)
        and upgrade_defs.RET.OK or upgrade_defs.RET.ERR
end

-- 升级执行阶段
function drive_upgrade:on_upgrade_process(_, system_id, firmware_type, file_path, parameters)
    -- 只处理硬盘固件类型
    if not is_drive_firmware(firmware_type) then
        return
    end

    log:notice('[Drive Upgrade] process phase: system_id = %s, type = %s, file = %s',
        system_id, firmware_type, file_path)

    if not next(self.cfgs) then
        clear_drive_upgrade_resource(self)
        log:error('[Drive Upgrade] upgrade process failed, there is no cfgs, firmware_type:%s', firmware_type)
        client:UpdateServiceUpdateServiceProcessReply(context.new(), system_id, firmware_type, upgrade_defs.RET.ERR,
            parameters)
        return
    end

    -- 设置file_path文件权限为secbox用户
    local ok, rsp = client:PFileFileChown(context.new(), nil, file_path, upgrade_defs.SECBOX_UID, upgrade_defs.SECBOX_GID)
    if not ok then
        log:error('[Drive Upgrade] chown file failed, error %s', rsp)
        clear_drive_upgrade_resource(self)
        client:UpdateServiceUpdateServiceProcessReply(context.new(), system_id, firmware_type,
            upgrade_defs.RET.ERR, parameters)
        return
    end

    -- 异步执行升级逻辑
    skynet.fork(function ()
        local ret_ok, ret_code = pcall(function ()
            return drive_upgrade_process(self, system_id, firmware_type, file_path, parameters)
        end)
        if not ret_ok then
            log:error('[Drive Upgrade] call drive upgrade process failed, err: %s', ret_code)
            clear_drive_upgrade_resource(self)
            ret_code = upgrade_defs.RET.ERR
        end

        if ret_code ~= upgrade_defs.RET.OK then
            clear_drive_upgrade_resource(self)
            log:error('[Drive Upgrade] upgrade process failed, ret_code = %s', ret_code)
        end

        client:UpdateServiceUpdateServiceProcessReply(context.new(), system_id, firmware_type,
            ret_code, parameters)
    end)
end

-- 升级完成阶段实际处理逻辑
local function drive_upgrade_finish(self, system_id, firmware_type, parameters)
    log:notice('[Drive Upgrade] finish phase: register active action')
    if not self.upgraded_drives_success or #self.upgraded_drives_success == 0 then
        log:error('[Drive Upgrade] no upgraded drives success')
        return upgrade_defs.RET.ERR
    end
    -- 检查OS上电状态(如果os下电则不需要注册生效对象)
    if check_os_power_state('drive register acitve') ~= upgrade_defs.RET.OK then
        return upgrade_defs.RET.ERR
    end
    -- 注册生效对象（多个硬盘共用一个生效对象）
    -- FirmwareType=Drive, ActiveCondition=ResetTargetDevice
    local active_action = {}
    active_action[#active_action + 1] = {Key = 'FirmwareId', Value = upgrade_defs.FIRMWARE_TYPE_DRIVE}
    active_action[#active_action + 1] = {Key = 'FirmwareType', Value = firmware_type}
    active_action[#active_action + 1] = {Key = 'ActiveCondition', Value = 'ResetTargetDevice'}
    active_action[#active_action + 1] = {Key = 'ActiveMode', Value = 'None'}
    active_action[#active_action + 1] = {Key = 'ActiveStatus', Value = 'Idle'}

    local ok, err = client:PFirmwareActiveFirmwareActiveRegisterActiveAction(context.new(), active_action)
    if not ok then
        log:error('[Drive Upgrade] RegisterActiveAction failed, err: %s', err)
        return upgrade_defs.RET.ERR
    end
    -- 复位持久化已升级成功待生效的硬盘表到local_db，由于掉电情况硬盘固件已生效无需再生效
    local local_db_handle = self.reset_local_db
    local tbl = local_db_handle.UpgradedDrivesPendingActive
    for _, drive_name in ipairs(self.upgraded_drives_success) do
        local record = local_db_handle:select(tbl):where({DriveName = drive_name}):first()
        if not record then
            local ok, err = pcall(function()
                local new_record = local_db_handle.UpgradedDrivesPendingActive({DriveName = drive_name})
                new_record:save()
            end)
            if not ok then
                log:error('[Drive Upgrade] save drive %s to database failed: %s', drive_name, err)
            end
        end
    end

    log:notice('[Drive Upgrade] finish phase: registered active action successfully')
    return upgrade_defs.RET.OK
end

-- 升级完成阶段
function drive_upgrade:on_upgrade_finish(_, system_id, firmware_type, parameters)
    -- 只处理硬盘固件类型
    if not is_drive_firmware(firmware_type) then
        return
    end

    log:notice('[Drive Upgrade] finish phase: system_id = %s, type = %s', system_id, firmware_type)

    skynet.fork(function ()
        local ret_ok, ret_code = pcall(function ()
            return drive_upgrade_finish(self, system_id, firmware_type, parameters)
        end)
        if not ret_ok then
            log:error('[Drive Upgrade] call drive upgrade finish failed, err: %s', ret_code)
            ret_code = upgrade_defs.RET.ERR
        end

        if ret_code ~= upgrade_defs.RET.OK then
            log:error('[Drive Upgrade] upgrade finish failed, ret_code = %s', ret_code)
        end
        -- finish阶段成功与否都需要清除升级资源准备下一次升级了
        clear_drive_upgrade_resource(self)
        client:UpdateServiceUpdateServiceFinishReply(context.new(), system_id, firmware_type,
            ret_code, parameters)
    end)
end

local function update_active_status(status)
    log:notice('[Drive Upgrade]update active status:%s', status)
    local param = {}
    param[#param+1] = {Key = 'FirmwareId', Value = upgrade_defs.FIRMWARE_TYPE_DRIVE}
    param[#param+1] = {Key = 'FirmwareType', Value = upgrade_defs.FIRMWARE_TYPE_DRIVE}
    param[#param+1] = {Key = 'ActiveStatus', Value = status}
    local ok, err = client:PFirmwareActiveFirmwareActiveUpdateActiveStatus(context.new(), param)

    if not ok then
        log:error('[Drive Upgrade] update active status failed, err: %s', err)
    end
end

-- 生效阶段实际处理逻辑
local function drive_active_process(self, system_id, firmware_type)
    log:notice('[Drive Upgrade] active phase: execute firmware activation')


    -- 从数据库读取已升级成功的硬盘列表（支持BMC重启后恢复）
    local local_db_handle = self.reset_local_db
    local tbl = local_db_handle.UpgradedDrivesPendingActive
    local records = local_db_handle:select(tbl):all()

    if not records or #records == 0 then
        log:error('[Drive Upgrade] active phase: no pending active drives found in database')
        return upgrade_defs.RET.ERR
    end

    log:notice('[Drive Upgrade] active phase: activating %s drives', #records)
    update_active_status(upgrade_defs.ACTIVE_STATUS_APPLY)
    local active_success_count = 0
    local drive_name
    -- 遍历数据库中的待生效硬盘列表
    for _, record in ipairs(records) do
        -- 检查OS上电状态(硬盘生效依赖OS上电与RAID卡通信)
        if check_os_power_state('drive activation') ~= upgrade_defs.RET.OK then
            return upgrade_defs.RET.ERR
        end
        drive_name = record.DriveName
        -- 根据硬盘名称获取硬盘对象
        local drive = c_drive_collection:get_drive(drive_name)
        if not drive then
            log:error('[Drive Upgrade] active phase: drive %s not found in collection', drive_name)
            log:running(log.RLOG_ERROR, 'Active %s Firmware failed: drive not found', drive_name)
        elseif drive.Presence ~= 1 then
            log:error('[Drive Upgrade] active phase: drive %s not present', drive_name)
            log:running(log.RLOG_ERROR, 'Active %s Firmware failed: drive not present', drive_name)
        else
            -- 硬盘在位，执行生效操作
            log:notice('[Drive Upgrade] active phase: activating drive %s (ctrl=%s, did=%s)',
                drive_name, drive.RefControllerId, drive.device_id)

            local ok, ret = pcall(sml.pd_active_firmware, drive.RefControllerId, drive.device_id)
            if not ok or ret ~= common_def.RET_OK then
                log:error('[Drive Upgrade] active phase: activate drive %s failed, error: %s', drive_name, ret)
                log:running(log.RLOG_ERROR, 'Active %s Firmware failed', drive_name)
            else
                log:notice('[Drive Upgrade] active phase: activate drive %s success', drive_name)
                log:running(log.RLOG_INFO, 'Active %s Firmware successfully', drive_name)
                active_success_count = active_success_count + 1
            end
        end
    end

    -- 判断生效结果
    local all_success = (active_success_count == #records)
    -- 无论成功与否，清空数据库中的待生效记录（返回固件固件后固件管理会删除生效对象）
    clear_pending_active_drives(self)
    if all_success then
        log:notice('[Drive Upgrade] active phase: all drives activation success')
        return upgrade_defs.RET.OK
    else
        log:error('[Drive Upgrade] active phase: some drives activation failed: %s/%s',
            #records - active_success_count, #records)
        return upgrade_defs.RET.ERR
    end
end

-- 生效阶段
function drive_upgrade:on_active_process(_, system_id, firmware_type)
    -- 只处理硬盘固件类型
    if not is_drive_firmware(firmware_type) then
        return
    end

    log:notice('[Drive Upgrade] active phase: system_id = %s, type = %s', system_id, firmware_type)

    skynet.fork(function ()
        local ret_ok, ret_code = pcall(function ()
            return drive_active_process(self, system_id, firmware_type)
        end)
        -- 生效失败才调用ProcessReply返回错误码，成功则更新状态为Ready
        if not ret_ok or ret_code ~= upgrade_defs.RET.OK then
            log:error('[Drive Upgrade] call drive active process failed, err: %s', ret_code)
            client:FirmwareActiveFirmwareActiveActiveProcessReply(context.new(), system_id, firmware_type,
                ret_code)
            return
        end
        update_active_status(upgrade_defs.ACTIVE_STATUS_READY)
        client:FirmwareActiveFirmwareActiveActiveProcessReply(context.new(), system_id, firmware_type,
            ret_code)
    end)
end

-- 构造函数:初始化成员变量
function drive_upgrade:ctor(bus, db, reset_local_db)
    self.bus = bus
    self.db = db
    self.reset_local_db = reset_local_db
    self.target_drives = {}
    self.cfgs = {}
    self.is_drive_upgrading = false
    self.upgraded_drives_success = {}  -- 已升级成功的硬盘表(需持久化)
end

-- 初始化：订阅固件管理升级信号
function drive_upgrade:init()
    log:notice('[Drive Upgrade] initializing drive upgrade service')

    -- 监听升级信号
    client:SubscribeUpdateServiceUpdateServiceUpgradePrepareSignal(function (...)
        self:on_upgrade_prepare(...)
    end)
    client:SubscribeUpdateServiceUpdateServiceUpgradeProcessSignal(function (...)
        self:on_upgrade_process(...)
    end)
    client:SubscribeUpdateServiceUpdateServiceUpgradeFinishSignal(function (...)
        self:on_upgrade_finish(...)
    end)

    -- 监听生效信号
    client:SubscribeFirmwareActiveFirmwareActiveActiveProcessSignal(function (...)
        self:on_active_process(...)
    end)

    -- 监听OS下电事件,在下电时主动清理生效对象
    bus_monitor_service.get_instance().on_smbios_status_changed:on(function(status)
        if status ~= upgrade_defs.SMBIOS_WRITE_FINISH then
            clear_pending_active_drives(self)
            local ok, ret = client:PFirmwareActiveFirmwareActiveDeleteActiveAction(context.new(), {upgrade_defs.FIRMWARE_TYPE_DRIVE})
            log:notice('[Drive Upgrade] delete active action result: %s, err: %s', ok, ret)
        end
    end)
    log:notice('[Drive Upgrade] drive upgrade service initialized')
end

return singleton(drive_upgrade)