-- Copyright (c) 2025 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.
--- @class LogParser
--- @field parse_log_file function
--- @field parse_log_text function
local LogParser = {}

---
--- 是否包含在数组内, 如果table为空, 则返回false, 如果value为空, 则返回false
---
--- @param table table
--- @param value string
--- @return boolean
local function contains(table, value)
    for _, v in ipairs(table) do if v == value then return true end end
    return false
end

---
--- 解析单行数据
---
--- @param line string
--- @return string, string
local function parse_line(line)
    local key, value = line:match("^([^:]+):(.*)$")
    key = key and string.gsub(key, "^%s*(.-)%s*$", "%1") or nil
    value = value and string.gsub(value, "^%s*(.-)%s*$", "%1") or nil
    return key, value
end

-- 定义日志字段
local log_keys = {
    "timestamp", "observed_timestamp", "severity_num", "severity_text", "body",
    "resource", "attributes", "event_id", "event_name", "trace_id", "span_id",
    "trace_flags", "scope"
}

-- 定义资源字段
local resource_keys = {
    "service.name", "telemetry.sdk.version", "telemetry.sdk.name",
    "telemetry.sdk.language"
}

-- 定义scope字段
local scope_keys = {"name", "version", "schema_url", "attributes"}

---
--- 解析资源信息
---
--- @param lines table
--- @param start_idx number
--- @return table, number
local function parse_resource(lines, start_idx)
    local resource = {}
    local i = start_idx
    while i <= #lines do
        local line = lines[i]
        if line:match("^}") then break end
        local key, value = parse_line(line)
        if contains(resource_keys, key) then
            if key and value then resource[key] = value end
        else
            break
        end
        i = i + 1
    end
    return resource, i
end

---
--- 解析scope信息
---
--- @param lines table
--- @param start_idx number
--- @return table, number
local function parse_scope(lines, start_idx)
    local scope = {}
    local i = start_idx
    while i <= #lines do
        local line = lines[i]
        if line:match("^}") then
            break
        end
        local key, value = parse_line(line)
        if contains(scope_keys, key) then
            if key and value then scope[key] = value end
        else
            break
        end
        i = i + 1
    end
    return scope, i
end

---
--- 解析属性信息
---
--- @param lines table
--- @param start_idx number
--- @return table, number
local function parse_attributes(lines, start_idx)
    local attributes = {}
    local i = start_idx
    while i <= #lines do
        local line = lines[i]
        if line:match("^}") then break end
        local key, value = parse_line(line)
        if not contains(log_keys, key) then
            if key and value then attributes[key] = value end
        else
            break
        end
        i = i + 1
    end
    return attributes, i
end

local complex_parser = {
    resource = parse_resource,
    scope = parse_scope,
    attributes = parse_attributes
}

---
--- 解析文本
---
--- @param text string
--- @return table, string
function LogParser:parse_log_text(text)
    local lines = {}
    for line in text:gmatch("[^\r\n]+") do
        local content = string.gsub(line, "^%s*(.-)%s*$", "%1")
        -- 跳过空行
        if content ~= "" then table.insert(lines, content) end
    end

    local result = {}
    local i = 1
    while i <= #lines do
        local line = lines[i]
        if line:match("^{") then
            local log_entry = {}
            i = i + 1
            while i <= #lines do
                line = lines[i]
                if line:match("^}") then
                    break
                end

                local key, value = parse_line(line)
                if key then
                    if complex_parser[key] then
                        log_entry[key], i = complex_parser[key](lines, i + 1)
                    else
                        if value then
                            log_entry[key] = value
                        end
                        i = i + 1
                    end
                end
            end
            table.insert(result, log_entry)
        end
        i = i + 1
    end

    return result
end

---
--- 解析整个文件
---
--- @param filename string
--- @return table, string
function LogParser:parse_log_file(filename)
    local file = io.open(filename, "r")
    if not file then return nil, "无法打开文件: " .. filename end

    local content = file:read("*all")
    file:close()
    return LogParser:parse_log_text(content)
end

return LogParser
