-- 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: 从imu读取文件
local class = require 'mc.class'
local tasks = require 'mc.orm.tasks'
local utils = require 'mc.utils'
local file_util = require 'infrastructure.file_util'
local crc32 = require 'libmgmt_protocol.bios.infrastructure.crc32'
local utils_vos = require 'utils.vos'
local imu_communicate = require 'domain.transport.imu_communicate'
local bios_factory = require 'factory.bios_factory'
local skynet = require 'skynet'
local utils_core = require 'utils.core'

local ComponentInfo = class()
local BIOS_STARTUP_POST_STAGE_FINISH<const> = 0xFE
local SYNC_INTERVAL<const> = 3500

function ComponentInfo:init_info(system_id)
    -- 本地校验信息
    self.local_verify_info = {
        len = 0,
        version = '',
        crc32 = 0
    }
    -- bios校验信息
    self.remote_verify_info = {
        len = 0,
        version = '',
        crc32 = 0
    }
    self.data = ''
    self.system_id = system_id
end

function ComponentInfo:clear_info()
    self.local_verify_info['len'] = 0
    self.local_verify_info['version'] = ''
    self.local_verify_info['crc32'] = 0

    self.remote_verify_info['len'] = 0
    self.remote_verify_info['version'] = ''
    self.remote_verify_info['crc32'] = 0

    self.data = ''
end

function ComponentInfo:sync_verify_info()
    local imu_cmd = imu_communicate.get_instance()
    local ok, verify_info = pcall(imu_cmd.get_verification_info, imu_cmd, self.type, self.system_id)
    if not ok then
        return
    end
    self.remote_verify_info.len = verify_info.FileLen
    self.remote_verify_info.version = verify_info.Version
    self.remote_verify_info.crc32 = verify_info.Crc32
end

function ComponentInfo:is_data_change()
    self:sync_verify_info()
    if self.local_verify_info.len ~= self.remote_verify_info.len or
        self.local_verify_info.version ~= self.remote_verify_info.version or
        self.local_verify_info.crc32 ~= self.remote_verify_info.crc32 then
        return true
    end
    return false
end

local function cal_crc(data)
    if not data then
        return 0
    end
    local ok, crc = pcall(function()
        return crc32(data, 0, true)
    end)
    if not ok then
        return 0
    end
    return crc
end

function ComponentInfo:update_data(data)
    self.data = data
    self.local_verify_info.version = self.remote_verify_info.version
    self.local_verify_info.crc32 = cal_crc(data)
    self.local_verify_info.len = #data
end

function ComponentInfo:init_data()
    local data = file_util.get_file_data(self.file_path)
    if not data then
        return
    end
    self:update_data(data)
    self.data = data
end

function ComponentInfo:is_need_update()
    -- 文件不存在或者判断与上次的长度是否一致，需要请求版本信息
    if not utils_vos.get_file_accessible(self.file_path) or
        utils_vos.get_file_length(self.file_path) ~= self.local_verify_info.len or
        self:is_data_change() then
        return true
    end
    return false
end

function ComponentInfo:request_and_update()
    local imu_cmd = imu_communicate.get_instance()
    local ok, data = pcall(imu_cmd.get_info, imu_cmd, self.type, self.system_id)
    if not ok or not data then
        return
    end
    ok = file_util.write_file_data(self.file_path, data)
    if not ok then
        return
    end
    utils_core.chmod_s(self.file_path, utils.S_IRUSR | utils.S_IWUSR)
    self:update_data(data)
    self:update_cfg_version()
end

-- 更新资源树上的版本号
function ComponentInfo:update_cfg_version()
end

function ComponentInfo:is_support()
    local imu_cmd = imu_communicate.get_instance()
    local ok, _ = pcall(imu_cmd.get_verification_info, imu_cmd, self.type, self.system_id)
    if ok then
        return true
    end
    return false
end

function ComponentInfo:clear_file()
    utils.remove_file(self.file_path)
    self:clear_info()
end

function ComponentInfo:run()
    local cfg = bios_factory.get_service('bios_service')
    local startup_state = cfg:get_prop('SystemStartupState', self.system_id)
    -- os未启动无需请求imu
    if startup_state ~= BIOS_STARTUP_POST_STAGE_FINISH then
        self:clear_file()
        return
    end
    if not self:is_support() then
        self:clear_file()
        return
    end
    -- 判断是否有变化：1、有变化请求 2、没变化不请求
    if self:is_need_update() then
        self:request_and_update()
    end
end

function ComponentInfo:start_task()
    self:init_data()
    self.task = tasks.get_instance():new_task(self.task_name)
        :set_timeout_ms(SYNC_INTERVAL):loop(function()
        self:run()
    end)
end

function ComponentInfo:get_data()
    return self.data
end

function ComponentInfo:fetch_info()
    pcall(function()
        for _ = 1, 5 do
            self:run()
            skynet.sleep(500)
        end
    end)
end

return ComponentInfo