using System.Text.RegularExpressions;
using GmRelay.Shared.Domain;

namespace GmRelay.Bot.Features.Sessions.RescheduleSession;

internal sealed record RescheduleVotingInput(
    IReadOnlyList<DateTimeOffset> Options,
    DateTimeOffset Deadline)
{
    private static readonly Regex DateTimePattern = new(
        @"(?<date>\d{1,2}\.\d{2}\.\d{4})\s+(?<time>\d{1,2}:\d{2})",
        RegexOptions.CultureInvariant);

    public static bool TryParse(
        string text,
        DateTimeOffset nowUtc,
        out RescheduleVotingInput input,
        out string error)
    {
        input = new RescheduleVotingInput([], default);
        error = string.Empty;

        var options = new List<DateTimeOffset>();
        DateTimeOffset? deadline = null;

        foreach (var rawLine in text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        {
            var line = rawLine.Trim();
            var match = DateTimePattern.Match(line);
            if (!match.Success)
                continue;

            var value = $"{match.Groups["date"].Value} {match.Groups["time"].Value}";
            if (!MoscowTime.TryParseMoscow(value, out var parsed))
                continue;

            if (IsDeadlineLine(line))
            {
                deadline = parsed;
            }
            else
            {
                options.Add(parsed);
            }
        }

        if (options.Count is < 2 or > 3)
        {
            error = "Укажите от 2 до 3 вариантов времени.";
            return false;
        }

        if (options.Distinct().Count() != options.Count)
        {
            error = "Варианты времени не должны повторяться.";
            return false;
        }

        if (deadline is null)
        {
            error = "Укажите дедлайн голосования строкой «Дедлайн: ДД.ММ.ГГГГ ЧЧ:ММ».";
            return false;
        }

        if (options.Any(option => option <= nowUtc))
        {
            error = "Все варианты времени должны быть в будущем.";
            return false;
        }

        if (deadline.Value <= nowUtc)
        {
            error = "Дедлайн голосования должен быть в будущем.";
            return false;
        }

        if (deadline.Value >= options.Min())
        {
            error = "Дедлайн голосования должен быть раньше первого предложенного времени.";
            return false;
        }

        input = new RescheduleVotingInput(options, deadline.Value);
        return true;
    }

    private static bool IsDeadlineLine(string line)
    {
        var normalized = line.TrimStart('-', '*', ' ', '\t').ToLowerInvariant();

        return normalized.StartsWith("дедлайн", StringComparison.Ordinal)
            || normalized.StartsWith("deadline", StringComparison.Ordinal)
            || normalized.StartsWith("до:", StringComparison.Ordinal);
    }
}

internal sealed record RescheduleOptionDto(
    Guid OptionId,
    int DisplayOrder,
    DateTimeOffset ProposedAt);

internal sealed record RescheduleOptionVoteDto(
    Guid OptionId,
    Guid PlayerId,
    string DisplayName,
    string? TelegramUsername);

internal sealed record RescheduleOptionVoteCount(
    Guid OptionId,
    int VoteCount);
