-- Copyright (c) 2024 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 singleton = require 'mc.singleton'
local log = require 'mc.logging'
local client = require 'general_hardware.client'
local utils = require 'dpu_service.utils'
local parser_cfg = require 'mcu.upgrade.parser_cfg'

local upgrade_subject = {}
upgrade_subject.__index = upgrade_subject

local DUP_MCU_TYPE = 'DPUMcu'
local HPC_VDR_TYPE = 'HPCVrd'

local function is_dpu_firmware(cfg_path)
    if not utils.get_firmware_uid(cfg_path, 'Firmware1', 'UID') then
        log:debug("This is not a dpu mcu, can not get UID")
        return false
    end
    return true
end

-- 判断特殊升级固件
local function update_firmware_type(firmware_type, cfg_path)
    if firmware_type == 'Mcu' and is_dpu_firmware(cfg_path) then
        return DUP_MCU_TYPE
    end
    if firmware_type == 'Vrd' and parser_cfg.is_hpc_vrd_pkg(cfg_path) then
        return HPC_VDR_TYPE
    end
    return firmware_type
end

function upgrade_subject:register_upgrade_observer(observer, firmware_type)
    log:notice('register upgrade observer firmware_type:%s', firmware_type)
    if self.upgrade_observers[firmware_type] then
        log:error('Already exists the same upgrade firmware_type:[%s]', firmware_type)
        return
    end
    self.upgrade_observers[firmware_type] = observer
end

function upgrade_subject:register_active_observer(observer, firmware_type)
    log:notice('register active observer firmware_type:%s', firmware_type)
    if self.active_observers[firmware_type] then
        log:error('Already exists the same active firmware_type:[%s]', firmware_type)
        return
    end
    self.active_observers[firmware_type] = observer
end

function upgrade_subject:on_upgrade_prepare(context, system_id, firmware_type, cfg_path, hpm_path, parameters)
    self.current_firmware_type = update_firmware_type(firmware_type, cfg_path)
    log:notice("[on_upgrade_prepare] firmware_type:%s cur_firmware_type:%s", firmware_type, self.current_firmware_type)

    local observer_service = self.upgrade_observers[self.current_firmware_type]
    if not observer_service then
        log:error('[on_upgrade_prepare] does not exists the observer, firmware_type:%s', self.current_firmware_type)
        return
    end

    log:notice("[on_upgrade_prepare] start upgrade %s", firmware_type)
    local ok, err = pcall(function ()
        return observer_service:on_upgrade_prepare(context, system_id, firmware_type, cfg_path, hpm_path, parameters)
    end)
    if not ok then
        log:error("upgrade prepare failed, error:%s", err)
    end
    log:notice("[on_upgrade_prepare] end upgrade %s", firmware_type)
end

function upgrade_subject:on_upgrade_process(context, system_id, firmware_type, file_path)
    local observer_service = self.upgrade_observers[self.current_firmware_type]
    if not observer_service then
        log:error('[on_upgrade_process] does not exists the observer, firmware_type:%s', self.current_firmware_type)
        return
    end

    log:notice("[on_upgrade_process] start upgrade %s", firmware_type)
    local ok, err = pcall(function ()
        return observer_service:on_upgrade_process(context, system_id, firmware_type, file_path)
    end)
    if not ok then
        log:error("upgrade process failed, error:%s", err)
    end
    log:notice("[on_upgrade_process] end upgrade %s", firmware_type)
end

function upgrade_subject:on_upgrade_finish(context, system_id, firmware_type)
    local observer_service = self.upgrade_observers[self.current_firmware_type]
    if not observer_service then
        log:error('[on_upgrade_finish] does not exists the observer, firmware_type:%s', self.current_firmware_type)
        return
    end

    log:notice("[on_upgrade_finish] start upgrade %s", firmware_type)
    local ok, err = pcall(function ()
        return observer_service:on_upgrade_finish(context, system_id, firmware_type)
    end)
    if not ok then
        log:error("upgrade finish failed, error:%s", err)
    end
    log:notice("[on_upgrade_finish] end upgrade %s", firmware_type)
end

function upgrade_subject:on_active_process(context, system_id, firmware_type)
    local observer_service = self.active_observers[firmware_type]
    if not observer_service then
        log:error('[on_active_process] does not exists the observer, firmware_type:%s', firmware_type)
        return
    end

    log:notice("[on_active_process] start upgrade %s", firmware_type)
    local ok, err = pcall(function ()
        return observer_service:on_active_process(context, system_id, firmware_type)
    end)
    if not ok then
        log:error("active process failed, error:%s", err)
    end
    log:notice("[on_active_process] end upgrade %s", firmware_type)
end

function upgrade_subject.new()
    return setmetatable({}, upgrade_subject)
end

function upgrade_subject:init()
    self.upgrade_observers = {}
    self.active_observers = {}
    self.current_firmware_type = ''

    -- 监听升级信号
    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)
end

return singleton(upgrade_subject)