local DateTime = require("@lune/datetime")

local now = DateTime.now()
local nowIso = now:toIsoDate()

-- Make sure we have separator characters, T to separate date & time, + or Z to separate timezone

local dateTimeSplitIdx = string.find(nowIso, "T")
local timezoneSplitIdx = string.find(nowIso, "+")
local timezoneZeroedIdx = string.find(nowIso, "Z")

assert(dateTimeSplitIdx ~= nil, "Missing date & time separator 'T' in iso 8601 string")
assert(
	timezoneSplitIdx ~= nil or timezoneZeroedIdx ~= nil,
	"Missing timezone separator '+' or 'Z' in iso date string"
)

-- Split date (before T) by dashes, split time (after T, before + or Z)
-- by colons, we should then get 3 substrings for each of date & time

local dateParts = string.split(string.sub(nowIso, 1, dateTimeSplitIdx - 1), "-")
local timeParts = string.split(
	string.sub(
		nowIso,
		dateTimeSplitIdx + 1,
		((timezoneSplitIdx or timezoneZeroedIdx) :: number) - 1
	),
	":"
)

assert(#dateParts == 3, "Date partial of iso 8601 should consist of 3 substrings, separated by '-'")
assert(#timeParts == 3, "Time partial of iso 8601 should consist of 3 substrings, separated by ':'")

-- date should be in format YYYY:MM::DD
-- time should be in format HH:MM:SS with optional fraction for seconds

assert(string.match(dateParts[1], "^%d%d%d%d$"), "Date partial should have 4 digits for year")
assert(string.match(dateParts[2], "^%d%d$"), "Date partial should have 2 digits for month")
assert(string.match(dateParts[3], "^%d%d$"), "Date partial should have 2 digits for day")

assert(string.match(timeParts[1], "^%d%d$"), "Time partial should have 2 digits for hour")
assert(string.match(timeParts[2], "^%d%d$"), "Time partial should have 2 digits for minute")
assert(
	string.match(timeParts[3], "^%d%d%.?%d*$") and tonumber(timeParts[3]) ~= nil,
	"Time partial should have minimum 2 digits with optional fraction for seconds"
)

-- Timezone specifier is either 'Z' for zeroed out timezone (no offset),
-- in which case we don't need to check anything other than it being the
-- last character, or it can be a timezone offset in the format HH::MM

if timezoneZeroedIdx ~= nil then
	-- No timezone offset
	assert(
		timezoneZeroedIdx == #nowIso,
		"Timezone specifier 'Z' must be at the last character in iso 8601 string"
	)
elseif timezoneSplitIdx ~= nil then
	-- Timezone offset
	local timezoneParts = string.split(string.sub(nowIso, timezoneSplitIdx + 1), ":")
	assert(#timezoneParts == 2, "Timezone partial should consist of 2 substings, separated by ':'")
	assert(
		string.match(timezoneParts[1], "^%d%d$"),
		"Timezone partial should have 2 digits for hour"
	)
	assert(
		string.match(timezoneParts[2], "^%d%d$"),
		"Timezone partial should have 2 digits for minute"
	)
else
	error("unreachable")
end
