-- 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 log = require 'mc.logging'
local utils = require 'mc.utils'
local upgrade_defs = require 'upgrade.upgrade_defs'
local fructl = require 'infrastructure.fructl'
local vos = require 'utils.vos'
local context = require 'mc.context'
local utils_core = require 'utils.core'
local client = require 'network_adapter.client'
local parser_cfg = require 'upgrade.parser_cfg'
local upgrade_flash = require 'upgrade.upgrade_flash'

local active_process = {}

-- 更新生效状态
local function update_active_status(firmware_id, firmware_type, status)
    log:notice('[Network Adapter Upgrade] Update active status: firmware_type = %s, status = %s', firmware_type, status)
    local param = {}
    param[#param + 1] = { Key = 'FirmwareId', Value = firmware_id }
    param[#param + 1] = { Key = 'FirmwareType', Value = firmware_type }
    param[#param + 1] = { Key = 'ActiveStatus', Value = status }
    client:FirmwareActiveFirmwareActiveUpdateActiveStatus(context.new(), param)
end

-- 查找缓存的升级文件
local function find_cached_upgrade_file(cache_dir)
    if not vos.get_file_accessible(cache_dir) then
        log:error('[Network Adapter Upgrade] cache upgrade directory not exist: %s', cache_dir)
        return nil
    end

    for _, file_name in pairs(utils_core.dir(cache_dir)) do
        if file_name:match(upgrade_defs.UPGRADE_NIC_FILE_NAME) then
            local file_path = string.format('%s%s', cache_dir, file_name)
            log:notice('[Network Adapter Upgrade] Found cached upgrade file: %s', file_path)
            return file_path
        end
    end

    log:error('[Network Adapter Upgrade] No cached upgrade file found in: %s', cache_dir)
    return nil
end

local function get_package_info(file_path)
    local ret, package_info
    for _ = 1, 10 do
        ret, package_info = pcall(function ()
            return client:UpdateServiceUpdateServiceParseFirmwarePackage(context.new(), file_path)
        end)
        if ret and package_info then
            break
        end
    end
    if not ret then
        log:error('parse package failed, error:%s', package_info)
        return
    end
    return package_info
end

-- 获取缓存目录中的Firmware文件列表
local function get_firmware_name(valid_path)
    local name_list = utils_core.dir(valid_path)
    for _, name in ipairs(name_list) do
        if name:match('Firmware') then
            return name
        end
    end
    return nil
end

-- 解压缓存的固件包
local function unzip_cached_firmware(file_path)
    -- 获取升级包信息
    local package_info = get_package_info(file_path)
    if not package_info or not package_info.FirmwareDirectory then
        log:error('[Network Adapter Upgrade] Failed to get package info from file: %s', file_path)
        return nil, nil, upgrade_defs.RET.ERR
    end
    local dir = package_info.FirmwareDirectory
    local firmware_name = get_firmware_name(dir)
    if not firmware_name then
        log:error('[Network Adapter Upgrade] Failed to locate firmware entry under directory: %s', dir)
        return nil, nil, upgrade_defs.RET.ERR
    end
    local file_path = string.format('%s%s', dir, firmware_name)
    log:notice('[Network Adapter Upgrade] Unzip firmware file: %s', file_path)
    return dir, file_path, upgrade_defs.RET.OK
end

-- 清理升级相关文件
local function cleanup_upgrade_files(hpm_path, dir)
    -- 删除缓存文件
    if vos.get_file_accessible(hpm_path) then
        utils.remove_file(hpm_path)
    end

    -- 删除解压目录
    if vos.get_file_accessible(dir) then
        utils.remove_file(dir)
    end
end

-- 执行生效升级流程
local function execute_active_upgrade(self, hpm_path)
    -- 解压缓存的固件
    local dir, file_path, ret_code = unzip_cached_firmware(hpm_path)
    if ret_code ~= upgrade_defs.RET.OK then
        log:error('[Network Adapter Upgrade] Failed to unzip cached firmware')
        return ret_code
    end

    local cfg_path = string.format('%s%s', dir, 'update.cfg')
    log:notice('[Network Adapter Upgrade] Get cfg path: %s', cfg_path)
    self.cfgs = parser_cfg.get_cfgs(cfg_path)
    if not next(self.cfgs) then
        log:error('[Network Adapter Upgrade] Failed to get cfgs')
        cleanup_upgrade_files(hpm_path, dir)
        return upgrade_defs.RET.ERR
    end

    -- 执行网卡固件升级
    local ok, upgrade_ret = pcall(function()
        return upgrade_flash.network_adapter_upgrade_flash(self, file_path)
    end)
    if not ok then
        log:error('[Network Adapter Upgrade] upgrade flash failed, ret = %s', upgrade_ret)
        upgrade_ret = upgrade_defs.RET.ERR
    end

    -- 清理升级文件
    cleanup_upgrade_files(hpm_path, dir)
    return upgrade_ret
end

-- 网卡生效处理
function active_process.network_adapter_active_process(self, system_id, firmware_type)
    log:notice('[Network Adapter Upgrade] Active process start')
    self.is_network_adapter_activing = true

    -- 更新生效状态为Apply
    update_active_status(firmware_type, firmware_type, 'Apply')

    -- 查找缓存的升级文件
    local hpm_path = find_cached_upgrade_file(upgrade_defs.UPGRADE_NIC_DIR)
    if not hpm_path then
        log:error('[Network Adapter Upgrade] No cached upgrade file found')
        self.is_network_adapter_activing = false
        return upgrade_defs.RET.ERR
    end

    -- 加上电锁
    fructl.set_poweron_lock_until_success(self.bus, system_id, true, upgrade_defs.LOCK_FOREVER, 'Nic')

    -- 执行生效升级
    local upgrade_ret = execute_active_upgrade(self, hpm_path)
    if upgrade_ret ~= upgrade_defs.RET.OK then
        log:error('[Network Adapter Upgrade] Failed to execute active upgrade')
    end

    -- 解除上电锁
    fructl.set_poweron_lock_until_success(self.bus, system_id, false, upgrade_defs.LOCK_FOREVER, 'Nic')

    self.is_network_adapter_activing = false
    return upgrade_ret
end

return active_process
