-- 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 context = require('mc.context')
local OBJECT_PROPERTIES_INTERFACE <const> = 'bmc.kepler.Object.Properties'
-- FruCtrl 所在服务
local FRUCTRL_MDB_SERVICE <const> = 'bmc.kepler.fructrl'
-- PowerAction 资源树接口
local POWERACTION_MDB_INTF <const> = 'bmc.kepler.Systems.PowerAction'
local m = {}
local log = require('mc.logging')
local cjson = require('cjson')

-- 返回值为数字类型
local function get_sysid(path)
    local sysid = -1
    local err, rsp = bus:pcall(
        FRUCTRL_MDB_SERVICE,
        path,
        OBJECT_PROPERTIES_INTERFACE,
        'GetAllWithContext',
        'a{ss}s',
        context.get_context() or context.new(),
        OBJECT_PROPERTIES_INTERFACE
    )
    if not err then
        local identifier = rsp.ObjectIdentifier and rsp.ObjectIdentifier:value()
        if identifier then
            sysid = identifier[1]
        end
    end
    return sysid
end

local function cleartimeoutFlag_action(ctx, obj, objs, sysid, is_multihost)
    objs[#objs + 1] = {}
    objs[#objs].sysid = sysid
    obj.PowerOnTimeoutFlag = 0
    objs[#objs].flag = obj.PowerOnTimeoutFlag == 0
    if is_multihost then
        log:operation(
            ctx:get_initiator(),
            'fructrl',
            string.format('[System%s] Clear power on lock %s', sysid, objs[#objs].flag and 'successfully' or 'failed')
        )
    else
        log:operation(
            ctx:get_initiator(),
            'fructrl',
            string.format('Clear power on lock %s', objs[#objs].flag and 'successfully' or 'failed')
        )
    end
end

function m.getclear_timeoutFlag(input)
    local ctx = context.get_context()
    local objs = {}
    local poweractionlist
    local poweractionobj
    local sysid
    local is_multihost = mdb.get_object(bus, '/bmc/kepler/Managers/1/Multihost', 'bmc.kepler.Managers.Multihost').HostType
        == 'Multihost'
    if #input ~= 0 then
        local sysid = input[1]
        -- input[1]代表 -s 传的参数
        poweractionobj = mdb.get_object(bus, '/bmc/kepler/Systems/' .. sysid .. '/PowerAction', POWERACTION_MDB_INTF)
        sysid = tonumber(sysid)
        cleartimeoutFlag_action(ctx, poweractionobj, objs, sysid, is_multihost)
    else
        poweractionlist = mdb.get_sub_objects(bus, '/bmc/kepler/Systems', POWERACTION_MDB_INTF, 2)
        for _, v in pairs(poweractionlist) do
            sysid = get_sysid(v.path)
            cleartimeoutFlag_action(ctx, v, objs, sysid, is_multihost)
        end
        table.sort(objs, function(a, b)
            return a.sysid < b.sysid
        end)
    end
    return objs
end

function m.get_authorization()
    local status, input = libroutemapper_utils.get_line_without_echo(
        'Input your username and password using the format "username:password":'
    )
    if status ~= 0 or string.match(input, '(.*)%s*:%s*(.*)') == nil then
        return { -1, nil }
    end
    return { 0, input }
end

local function adjust_headers(headers, client_ip)
    local request_headers = curl.slist_init()
    for title, content in pairs(headers) do
        request_headers = curl.slist_append(request_headers, title .. ':' .. content)
    end
    local ip = string.match(client_ip, '(.*):.*')
    request_headers = curl.slist_append(request_headers, 'x-real-ip:' .. ip)
    return request_headers
end

function m.call_redfish(input, uri, method, req_body, req_header, client_ip)
    local request_body, request_header, rsp_body
    local curl_uri = 'http://127.0.0.1:30080' .. uri
    if req_body == 'null' then
        request_body = nil
    else
        local ok1, res1 = pcall(cjson.decode, req_body)
        if not ok1 then
            log:error(res1)
            return { -1, nil }
        else
            request_body = req_body
        end
    end
    if req_header == 'null' then
        request_header = {}
    else
        local ok2, res2 = pcall(cjson.decode, req_header)
        if not ok2 then
            log:error(res2)
            return { -2, nil }
        else
            request_header = res2
        end
    end
    local curl_handle = curl.easy_init()
    if curl_handle == nil then
        log:error('get curl handler failed')
        return { -3, nil }
    end
    curl.easy_setopt_customerquest(curl_handle, method)
    curl.easy_setopt_url(curl_handle, curl_uri)
    curl.easy_setopt_userpwd(curl_handle, input[2])
    curl.easy_setopt_httpheader(curl_handle, adjust_headers(request_header, client_ip))
    if request_body then
        curl.easy_setopt_postfields(curl_handle, request_body)
    end
    curl.easy_setopt_writefunction(curl_handle, function(body)
        rsp_body = body
    end)
    local ret_code = curl.easy_perform(curl_handle)
    if ret_code == 0 then
        curl.easy_cleanup(curl_handle)
        return { 0, rsp_body }
    else
        local err = curl.easy_strerror(ret_code)
        curl.easy_cleanup(curl_handle)
        return { -4, err }
    end
end

return m