-- 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 log = require 'mc.logging'
local c_psu_object = require 'device.psu'
local class = require 'mc.class'
local singleton = require 'mc.singleton'
local skynet = require 'skynet'
local power_mgmt_utils = require 'power_mgmt_utils'
local enums = require 'macros.power_mgmt_enums'

local E_OK <const> = nil -- 函数执行成功返回nil
local E_FAILED <const> = '' -- 空错误信息

local circuit_mgmt = class()

function circuit_mgmt:ctor()
    self.circuit_objs = {}
end

function circuit_mgmt:object_add_callback(class_name, object, position)
    if self.circuit_objs[object.Id] then
        log:error('Add Circuit object failed, duplicate Id: %s', object.Id)
        return
    end
    self.circuit_objs[object.Id] = object
    log:notice('Add Circuit object successfully, Id: %s, CircuitType: %s', object.Id, object.CircuitType)
end


function circuit_mgmt:update_mains_circuit_info(obj, circuit_a_status, circuit_a_type, circuit_a_voltage)
    if circuit_a_status then
        obj.InputVoltageStatus = circuit_a_status
    end
    if circuit_a_type then
        -- 输入为交流显示ThreePhase5Wire
        obj.PhaseWiringType = circuit_a_type == 0 and "ThreePhase5Wire" or ""
    end
    if circuit_a_voltage and circuit_a_type then
        -- 输入为直流且输入电压小于等于288v刷新为DC240V
        if circuit_a_type ~= 0 and circuit_a_voltage <= 288 then
            obj.NominalVoltage = "DC240V"
        else
            obj.NominalVoltage = ""
        end
    end
end

function circuit_mgmt:update_branch_circuit_info(obj, circuit_b_status, circuit_b_type, circuit_b_voltage)
    if circuit_b_status then
        obj.InputVoltageStatus = circuit_b_status
    end
    if circuit_b_type then
        -- 输入为交流显示ThreePhase5Wire
        obj.PhaseWiringType = circuit_b_type == 0 and "ThreePhase5Wire" or ""
    end
    if circuit_b_voltage and circuit_b_type then
        -- 输入为直流且输入电压小于等于288v刷新为DC240V
        if circuit_b_type ~= 0 and circuit_b_voltage <= 288 then
            obj.NominalVoltage = "DC240V"
        else
            obj.NominalVoltage = ""
        end
    end
end

function circuit_mgmt:update_circuit_info()
    local software_type = power_mgmt_utils.get_instance():get_chassis_type()
    if software_type ~= enums.SOFTWARE_TYPE.CABINET then
        log:notice('software_type is %s, not support update circuit info', software_type)
        return
    end

    log:notice('update_circuit_info task is start.')
    local circuit_a_status, circuit_b_status, circuit_a_type, circuit_b_type, circuit_a_voltage,
        circuit_b_voltage, ret, resp
    while true do
        skynet.sleep(6000)
        c_psu_object.collection:fold(function(_, obj)
            if not circuit_a_type then
                ret, resp = obj:get_main_circuit_input_voltage_type()
                -- A路输入电压类型获取成功，且电压类型不为3（未知）
                if ret == E_OK and resp ~= 3 then
                    circuit_a_type = resp
                end
            end
            if not circuit_b_type then
                ret, resp = obj:get_backup_circuit_input_voltage_type()
                -- B路输入电压类型获取成功，且电压类型不为3（未知）
                if ret == E_OK and resp ~= 3 then
                    circuit_b_type = resp
                end
            end
            if not circuit_a_voltage then
                ret, resp = obj:get_main_circuit_input_voltage()
                if ret == E_OK then
                    circuit_a_voltage = resp
                end
            end
            if not circuit_b_voltage then
                ret, resp = obj:get_backup_circuit_input_voltage()
                if ret == E_OK then
                    circuit_b_voltage = resp
                end
            end
            -- 获取A路输入电压状态时判断是否为255（未知）
            if not circuit_a_status and obj.MainCircuitVINStatus ~= 255 then
                circuit_a_status = obj.MainCircuitVINStatus
            end
            -- 获取B路输入电压状态时判断是否为255（未知）
            if not circuit_b_status and obj.BackupCircuitVINStatus ~= 255 then
                circuit_b_status = obj.BackupCircuitVINStatus
            end
        end)
        for _, obj in pairs(self.circuit_objs) do
            if obj.CircuitType == 'Mains' then
                self:update_mains_circuit_info(obj, circuit_a_status, circuit_a_type, circuit_a_voltage)
            elseif obj.CircuitType == 'Branch' then
                self:update_branch_circuit_info(obj, circuit_b_status, circuit_b_type, circuit_a_voltage)
            end
        end
        circuit_a_status, circuit_b_status, circuit_a_type, circuit_b_type, circuit_a_voltage, circuit_b_voltage = nil,
            nil, nil, nil, nil, nil
    end
end

function circuit_mgmt:init()
    skynet.fork(
        function()
            self:update_circuit_info()
        end
    )
end

return singleton(circuit_mgmt)