-- 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 skynet = require 'skynet'
local utils = require 'mc.utils'
local log = require 'mc.logging'
local context = require 'mc.context'
local fw_mgmt_client = require 'general_hardware.client'
local upgrade_subject = require 'upgrade_subject.upgrade_subject'
local cpld_test_upgrade = require 'cpld_test_upgrade'
local ini_parser = require 'mc.v2_persistence'
local cfg = require 'unit_manager.class.logic_fw.upgrade.fw_cfgs'

local UPGRADE_MAX_COMPNENT_NUM <const> = 32

local cpld_test_signal = {}

function cpld_test_signal.get_cfg_list(path)
    if not path then
        log:error("get nil cfg path")
        return {}
    end
    log:info("get cfg path[%s]", path)
    local data = ini_parser.load_file(path)
    if (not data.Basic) or (not data.Basic.Version) then
        log:error('Get Basic Version failed')
        return {}
    end
    local update_file_num = tonumber(data.Firmware.FileNum)
    if update_file_num == 0 or update_file_num > UPGRADE_MAX_COMPNENT_NUM then
        log:error('Update file num is invalid')
        return {}
    end
    local cfg_list = {}
    local group_name = nil
    local cfg_fw = nil
    for i = 2, update_file_num do -- 第1个Firmware指的就是配置文件，所以从2开始
        group_name = string.format("Firmware%d", (i - 1))
        log:info("get %s", group_name)
        cfg_fw = cfg.new(data[group_name], group_name)
        cfg_fw.before_action = data[group_name].BeforeAction or nil
        cfg_fw.after_action = data[group_name].AfterAction or nil
        cfg_fw.uid_action = data[group_name].ActionUid or nil
        table.insert(cfg_list, cfg_fw)
    end
    return cfg_list
end

function cpld_test_signal.init(logic_fw)
    cpld_test_signal.fw_list = logic_fw
    cpld_test_signal.upg_cfg_list = {}
    cpld_test_signal.upgrade_flag = false
    skynet.fork_once(function()
        for i = 1, 3 do
            if upgrade_subject.get_instance().upgrade_observers then
                upgrade_subject.get_instance():register_upgrade_observer(cpld_test_signal, 'cpld_test')
                break
            end
            skynet.sleep(500)
        end
    end)
    return cpld_test_signal
end

function cpld_test_signal:on_upgrade_prepare(ctx, system_id, firmware_type, cfg_path, _, parameters)
    log:notice("[cpld]Start the system[%s] %s upgrade prepare phase", system_id, firmware_type)
    fw_mgmt_client:UpdateServiceUpdateServiceUpdateUpgradeStatus(context.new(),
        system_id, firmware_type, 0, 20, 'Running', parameters)

    local ok, rsp = fw_mgmt_client:PFileFileChown(context.new(), nil, cfg_path, 104, 104) --设置配置文件属主为secbox
    if not ok then
        log:error('[cpld] chown cfg file failed, error %s', rsp)
        fw_mgmt_client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '', -1,
            parameters)
        return
    end

    skynet.fork(function()
        ok, rsp = pcall(cpld_test_upgrade.prepare_upgrade, cpld_test_signal, system_id, firmware_type, cfg_path,
            parameters)
        if not ok then
            log:error('[cpld] prepare upgrade failed, error: %s', rsp)
            fw_mgmt_client:UpdateServiceUpdateServicePrepareReply(context.new(), system_id, firmware_type, '', -1,
                parameters)
        end
    end)
end

function cpld_test_signal:on_upgrade_process(ctx, system_id, firmware_type, cfg_path, parameters)
    log:notice("[cpld]Start the system[%s] %s upgrade process phase", system_id, firmware_type)
    local ok, rsp = fw_mgmt_client:PFileFileChown(context.new(), nil, cfg_path, 104, 104)
    if not ok then
        log:error('[cpld] chownfile failed, error %s', rsp)
        fw_mgmt_client:UpdateServiceUpdateServiceProcessReply(context.new(), system_id, firmware_type, -1,
            parameters)
        return
    end
    fw_mgmt_client:UpdateServiceUpdateServiceUpdateUpgradeStatus(context.new(),
        system_id, firmware_type, 0, 40, 'Running', parameters)
    skynet.fork(function()
        ok, rsp = pcall(cpld_test_upgrade.process_upgrade, cpld_test_signal, system_id, firmware_type, cfg_path,
            parameters)
        if not ok then
            log:error('[cpld] process upgrade failed, error: %s', rsp)
            fw_mgmt_client:UpdateServiceUpdateServiceProcessReply(context.new(), system_id, firmware_type, -1,
                parameters)
        end
    end)
end

function cpld_test_signal:on_upgrade_finish(ctx, system_id, firmware_type, parameters)
    log:notice("[cpld]Start the system[%s] %s upgrade finish phase", system_id, firmware_type)
    fw_mgmt_client:UpdateServiceUpdateServiceUpdateUpgradeStatus(context.new(),
        system_id, firmware_type, 0, 90, 'Running', parameters)

    local ok, err = pcall(function()
        cpld_test_upgrade.finish_stage(fw_mgmt_client, cpld_test_signal, system_id, firmware_type, parameters)
    end)
    if not ok then
        log:error('[cpld] finish upgrade failed, error: %s', err)
        fw_mgmt_client:UpdateServiceUpdateServiceFinishReply(context.new(), system_id, firmware_type, -1,
            parameters)
    end
end

return cpld_test_signal
