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

local custom_msg = require 'messages.custom'
local log = require 'mc.logging'
local os = require 'os'
local DATE_LENGTH <const> = 19
local TIMESTAMP_LENGTH <const> = 5
local ONE_HOUR_SECONDS <const> = 3600
local m = {}

local function parse_timezone_to_sec(timezone)
    local sign, hour, min = timezone:match("([+-])(%d%d)(%d%d)")
    local sign_val = sign == "+" and 1 or -1
    local hour_val = tonumber(hour)
    local min_val = tonumber(min)

    return sign_val * (hour_val * 3600 + min_val * 60)
end

function m.parse_date_to_timestamp(date, new_timezone)
    local year, month, day, hour, min, sec = date:match("^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)$")
    local date_time_table = {
        year = tonumber(year),
        month = tonumber(month),
        day = tonumber(day),
        hour = tonumber(hour),
        min = tonumber(min),
        sec = tonumber(sec)
    }
    local timestamp = os.time(date_time_table)
    if not timestamp then
        log:error('Parse date[%s] to timestamp failed.', date)
        error(custom_msg.InvalidValue(date, 'DateTime'))
    end

    if os.date("*t").isdst then
        timestamp = timestamp - ONE_HOUR_SECONDS
    end

    local old_timezone = os.date("%z")
    local sec_diffrence = parse_timezone_to_sec(string.gsub(new_timezone, ":", "")) - parse_timezone_to_sec(old_timezone)
    local time_table = os.date("*t", timestamp - sec_diffrence)
    if time_table.isdst then 
        return tostring(timestamp - sec_diffrence + ONE_HOUR_SECONDS)
    end
    return tostring(timestamp - sec_diffrence)
end

function m.get_timestamp(date_time)
    local date = string.sub(date_time, 1, DATE_LENGTH)
    local timezone = string.sub(date_time, #date_time - TIMESTAMP_LENGTH)
    local timestamp = m.parse_date_to_timestamp(date, timezone)
    return timestamp
end

function m.convert_datetime(date)
    if type(date) == "number" then
        return os.date("!%Y-%m-%dT%H:%M:%SZ", date)
    end
    if type(date) ~= "string" or date == "" then
        return nil
    end
    local monthMap = {
        Jan = "01", Feb = "02", Mar = "03", Apr = "04",
        May = "05", Jun = "06", Jul = "07", Aug = "08",
        Sep = "09", Oct = "10", Nov = "11", Dec = "12"
    }
    local hour, min, sec, month_str, day, year = date:match("(%d+):(%d+):(%d+)%s+(%a+)%s+(%d+)%s+(%d+)")
    local month = monthMap[month_str]
    if not(hour and min and sec and month and day and year)then
        return nil
    end
    local time = os.date("!%Y-%m-%dT%H:%M:%SZ", os.time({
        year = tonumber(year),
        month = tonumber(month),
        day = tonumber(day),
        hour = tonumber(hour),
        min = tonumber(min),
        sec = tonumber(sec)
    }))

    return time
end

function m.datetime_format_convert(name, date)
    if name ~= 'Bios' then
        return m.convert_datetime(date) 
    end
    local month, day, year = string.match(date, '^(%d%d)/(%d%d)/(%d%d%d%d)$')
    if not month or not day or not year then
        return nil
    else
        return string.format('%d-%02d-%02d', year, month, day) .. 'T00:00:00Z'
    end
end

return m