using System.Globalization;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Remora.Commands.Parsers;
using Remora.Results;
namespace TeamOctolings.Octobot.Parsers;
///
/// Parses s.
///
[PublicAPI]
public partial class TimeSpanParser : AbstractTypeParser
{
private static readonly Regex Pattern = ParseRegex();
///
/// Parses a from the .
///
///
/// The parsed , or if parsing failed.
///
public static Result TryParse(string timeSpanString)
{
if (timeSpanString.StartsWith('-'))
{
return new ArgumentInvalidError(nameof(timeSpanString), "TimeSpans cannot be negative.");
}
if (TimeSpan.TryParse(timeSpanString, DateTimeFormatInfo.InvariantInfo, out var parsedTimeSpan))
{
return parsedTimeSpan;
}
var matches = ParseRegex().Matches(timeSpanString);
return matches.Count > 0
? ParseFromRegex(matches)
: new ArgumentInvalidError(nameof(timeSpanString), "The regex did not produce any matches.");
}
private static Result ParseFromRegex(MatchCollection matches)
{
var timeSpan = TimeSpan.Zero;
foreach (var groups in matches.Select(match => match.Groups
.Cast()
.Where(g => g.Success)
.Skip(1)
.Select(g => (g.Name, g.Value))))
{
foreach ((var key, var groupValue) in groups)
{
if (!int.TryParse(groupValue, out var parsedIntegerValue))
{
return new ArgumentInvalidError(nameof(groupValue), "The input value was not an integer.");
}
var now = DateTimeOffset.UtcNow;
timeSpan += key switch
{
"Years" => now.AddYears(parsedIntegerValue) - now,
"Months" => now.AddMonths(parsedIntegerValue) - now,
"Weeks" => TimeSpan.FromDays(parsedIntegerValue * 7),
"Days" => TimeSpan.FromDays(parsedIntegerValue),
"Hours" => TimeSpan.FromHours(parsedIntegerValue),
"Minutes" => TimeSpan.FromMinutes(parsedIntegerValue),
"Seconds" => TimeSpan.FromSeconds(parsedIntegerValue),
_ => throw new ArgumentOutOfRangeException(key)
};
}
}
return timeSpan;
}
[GeneratedRegex("(?\\d+(?=y|л|г))|(?\\d+(?=mo|мес))|(?\\d+(?=w|н|нед))|(?\\d+(?=d|д|дн))|(?\\d+(?=h|ч))|(?\\d+(?=m|min|мин|м))|(?\\d+(?=s|sec|с|сек))")]
private static partial Regex ParseRegex();
}