-- 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.

local vos = require 'utils.vos'
local file_sec = require 'utils.file'
local utils_core = require 'utils.core'
local c_tasks = require 'mc.orm.tasks'
local log = require 'mc.logging'
local utils = require 'mc.utils'
local signal = require 'mc.signal'
local client = require 'network_adapter.client'

local LOG_TASK_DELAY_TIME<const> = (3 * 60 * 60 * 1000)
local PCIE_CARD_LOG_BASE_DIR<const> = '/data/var/log/bmc/pciecard/' -- 日志存放路径
local OPTICAL_MODULE_LOG_BASE_DIR<const> = '/data/var/log/bmc/optical_module/' -- 光模块日志存放路径
local NPU_PORT_INFO_BASE_PATH<const> = '/var/log/compute/NpuIO/'
local log_collector = {}

function log_collector.monitor_pmu_status()
    client:OnPmuPropertiesChanged(function(values, _, _)
        if values.Status and values.Status:value() == 1 then
            log_collector.log_dump_reset_pmu_sig:emit()
        end
    end)
end

function log_collector.monitor_smbios_status()
    client:OnSmBiosPropertiesChanged(function(values, _, _)
        if not values.SmBiosStatus then
            return
        end

        if values.SmBiosStatus:value() == 3 then
            log_collector.log_dump_reset_smbios_sig:emit()
        end
    end)
end

function log_collector.init()
    log_collector.pcie_card_log_base_dir = PCIE_CARD_LOG_BASE_DIR
    log_collector.optical_module_info_dir = OPTICAL_MODULE_LOG_BASE_DIR
    log_collector.npu_port_info_base_path = NPU_PORT_INFO_BASE_PATH
    log_collector.log_dump_reset_pmu_sig = signal.new()
    log_collector.log_dump_reset_smbios_sig = signal.new()
    log_collector.log_dump_reset_bmc_sig = signal.new()
    log_collector.monitor_pmu_status()
    log_collector.monitor_smbios_status()

    -- BMC启动时默认等待一段时间后启动日志收集, 但如果超时之前出现其他立即触发收集的场景，则不用再收集
    c_tasks.timeout_ms(LOG_TASK_DELAY_TIME, function()
        log_collector.log_dump_reset_bmc_sig:emit()
    end)
end

function log_collector.log_dump_cb(path)
    -- 目录不存在则返回
    if not utils_core.is_dir(path) then
        log:error('the path doesn\'t exist')
        return
    end

    -- 把已收集下来的日志拷贝到一键收集命令传递过来的路径下
    local ret = file_sec.check_realpath_before_open_s(path)
    if ret ~= 0 then
        log:error('the path is illegal, err:%s', ret)
        return
    end
    if vos.get_file_accessible(log_collector.npu_port_info_base_path) then
        vos.check_before_system_s('/bin/cp', '-r', log_collector.npu_port_info_base_path, path)
    end
    if vos.get_file_accessible(log_collector.pcie_card_log_base_dir) then
        vos.check_before_system_s('/bin/cp', '-r', log_collector.pcie_card_log_base_dir, path)
    end
    if vos.get_file_accessible(log_collector.optical_module_info_dir) then
        vos.check_before_system_s('/bin/cp', '-r', log_collector.optical_module_info_dir, path)
    end
    log:info('finish to dump pcie card log')
end

function log_collector.get_smbus_log_dir(mds_obj)
    local device_name = mds_obj.DeviceLocator
    if not device_name then
        log:error('device_name doesn\'t exist')
        return nil
    end
    local pciecard_name = mds_obj.Name
    if not pciecard_name then
        log:error('pciecard_name doesn\'t exist')
        return nil
    end

    -- 去除字符串中的空格
    device_name = string.gsub(device_name, ' ', '')
    pciecard_name = string.gsub(pciecard_name, ' ', '')

    return log_collector.pcie_card_log_base_dir .. 'smbus_' .. device_name .. '_' .. pciecard_name .. '/'
end

function log_collector.get_ncsi_log_dir(mds_obj)
    local device_name = mds_obj.DeviceLocator
    if not device_name then
        log:error('device_name doesn\'t exist')
        return nil
    end
    local pciecard_name = mds_obj.Name
    if not pciecard_name then
        log:error('pciecard_name doesn\'t exist')
        return nil
    end

    -- 去除字符串中的空格
    device_name = string.gsub(device_name, ' ', '')
    pciecard_name = string.gsub(pciecard_name, ' ', '')

    return log_collector.pcie_card_log_base_dir .. 'ncsi_' .. device_name .. '_' .. pciecard_name .. '/'
end

function log_collector.create_dir(log_dir)
    -- 目录已经存在则返回
    if utils_core.is_dir(log_dir) then
        return true
    end
    -- 目录权限控制在0750
    if not utils.mkdir_with_parents(log_dir, utils.S_IRWXU | utils.S_IRGRP | utils.S_IXGRP) then
        log:error('create directory fail')
        return false
    end
    return true
end

function log_collector.get_time()
    local sec = os.time()
    local time = os.date('%Y%m%d%H%M%S', sec)
    return time
end

function log_collector.delete_old_log_file(log_dir, curr_log_files)
    local file_find
    if not utils_core.is_dir(log_dir) then
        return
    end

    for _, file in pairs(utils_core.dir(log_dir)) do
        file_find = false
        for _, curr_file in pairs(curr_log_files) do
            if curr_file == file then
                file_find = true
                break
            end
        end
        if not file_find then
            utils.remove_file(log_dir .. file)
        end
    end
end

function log_collector.dump_string_to_log(dir, file_name, input_str)
    local ret = file_sec.check_realpath_before_open_s(dir)
    if not ret then
        log:error("the dir is illegal")
        return
    end
    if not vos.get_file_accessible(dir) then
        log_collector.create_dir(dir)
    end
    local file_path = string.format("%s/%s", dir, file_name)
    local file, err = file_sec.open_s(file_path, "w+")
    if not file then
        log:error("open %s failed, err: %s", file_path, err)
        return
    end
    utils.close(file, pcall(file.write, file, input_str), "write dump string failed")
    utils_core.chmod_s(file_path, utils.S_IRUSR | utils.S_IWUSR | utils.S_IRGRP)
end

return log_collector
