-- Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
-- 
-- this file licensed under the 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 log = require 'mc.logging'
local mcu_upgrade_object = require 'mcu.upgrade.upgrade_object'
local RETIMER_CONSTANTS = require 'retimer.retimer_constants'
local MCU_ENUMS = require 'mcu.enum.mcu_enums'
local mcu_upgrade_service = require 'mcu.upgrade.upgrade_service.upgrade_service_mcu'
local class = require 'mc.class'
local cmn = require 'common'
local fructl = require 'mcu.upgrade.fructl_handler'

local M = {}
local RET_ERR = -1
local RET_OK  = 0
local UPGRADE_DELAY_EFFECTIVE<const> = 30 * 60  -- 升级完成 启动生效到生效完成之间的等待时间30min
M.chip_type = RETIMER_CONSTANTS.CHIP_TYPE.TYPE_JBOG_RETIMER

local UPGRADE_STATUS<const> = {
    UNSTART = 0x00,
    STARTING = 0x01,
    SUCCESS = 0x02,
    FAIL = 0x04
}
local FC_PCIE_SW_UPG_RETIMER_FAIL = "SVR-0053003"

local upgrade_object = class(mcu_upgrade_object)

function upgrade_object:wait_retimer_upgrade_result(timeout_sec, upgrade_process_cb)
    local time = 0

    local obj = self:get_ref_mcu()
    if not obj then
        return RET_ERR
    end

    local status
    while time < timeout_sec do
        status = obj.interface:query_retimer_upgrade_status()
        if status == UPGRADE_STATUS.FAIL then
            log:error("[%s]upgrade status failed. status is %s", self.id, status)
            return RET_ERR
        end
        if status == UPGRADE_STATUS.SUCCESS then
            break
        end
        local proportion = obj.interface:query_retimer_upgrade_proportion()
        if upgrade_process_cb then
            upgrade_process_cb((proportion or 0) / 100)
        end

        log:debug('[%s]retimer proportion: %s', self.id, proportion)
        cmn.skynet.sleep(1000)
        time = time + 10
    end

    if upgrade_process_cb then
        upgrade_process_cb(1)
    end
    -- 响应超时应该返回升级失败，触发重试
    return time == timeout_sec and RET_ERR or RET_OK
end

-- JBOG Retimer芯片升级流程通过MCU提供的SMC命令字进行升级
local function upgrade_task(retimer, bus, upgrade_details, func)
    local mcu_obj
    for _, obj in pairs(mcu_upgrade_service.get_instance().mcu_collection) do
        if retimer:get_position() == obj:get_position() then
            mcu_obj = obj
            break
        end
    end

    if not mcu_obj then
        log:error("get mcu obj by retimer position: %s failed", retimer:get_position())
        log:maintenance(log.MLOG_WARN, FC_PCIE_SW_UPG_RETIMER_FAIL,
                        'Upgrade Retimer get mcu obj by retimer position: %s failed',
                        retimer:get_position())
        return RET_ERR
    end
    log:maintenance(log.MLOG_INFO, log.FC__PUBLIC_OK, 'Upgrade Retimer(%s) started.', retimer.name)

    local mcu_powers_state = fructl.get_power_status(bus, upgrade_details.system_id)
    local upgrade_obj = upgrade_object.new(mcu_obj, mcu_obj:get_system_id(), mcu_powers_state)
    upgrade_obj.interface_type =  mcu_obj.mcu.Protocol
    upgrade_obj.system_id =  mcu_obj:get_system_id()
    upgrade_obj:set_ref_mcu(mcu_obj)
    local type = MCU_ENUMS.SUB_COMPONENT_TYPE.T_MCU
    for _, comp in pairs(mcu_obj.mcu.SubCompList) do
        log:notice("Retimer upgrade: comp.Type=%s, type=%s", comp.Type, type)
        if comp.Type == type then
            upgrade_obj:set_ref_subcomp(comp)
        end
    end

    local ret = upgrade_obj:upgrade_process(upgrade_details, retimer, function (percentage)
        func.process(percentage * 0.4) -- 往MCU传包过程占该固件的40%
    end)
    if ret ~= RET_OK then
        return RET_ERR
    end

    func.concurrent_run(function()
        local ret = upgrade_obj:wait_retimer_upgrade_result(UPGRADE_DELAY_EFFECTIVE, function (percentage)
            func.process(0.4 + percentage * 0.6) -- MCU往retimer传包过程占该固件的60%
        end)
        if ret ~= RET_OK then
            log:error('[%s]upgrade effect failed. ret = %s', retimer.name, ret)
            log:maintenance(log.MLOG_WARN, FC_PCIE_SW_UPG_RETIMER_FAIL, 'Upgrade Retimer(%s) failed, ret=%s',
                            retimer.name, ret)
            return ret
        end
        log:notice('[%s]upgrade effect successfully.', retimer.name)
        log:maintenance(log.MLOG_INFO, log.FC__PUBLIC_OK,
                        'Upgrade Retimer(%s) successfully, reset the OS to activate it',
                        retimer.name)
        return RET_OK
    end)

    return RET_OK
end

function M.upgrade_prepare_func(upgrade_service, dir)
    return true
end

function M.upgrade_single_retimer_func(retimer, _, _, bus, upgrade_details, func)
    local ok, ret = pcall(upgrade_task, retimer, bus, upgrade_details, func)
    if not ok or ret ~= RET_OK then
        log:error("upgrade_single_retimer_func failed: %s", ret)
        return false
    end
    return true
end

function M.upgrade_single_retimer_finish_func(upgrade_service, retimer)
    return true
end

function M.upgrade_finish_func(upgrade_service)
    return true
end

M.wait_retimer_upgrade_result = upgrade_object.wait_retimer_upgrade_result

return M
