using System.Globalization;
using System.Text.RegularExpressions;

namespace TeleWave.Application.Library;

/// <summary>Разбор сезона/серии из имени файла (SxxEyy либо NxNN). Номера в модели не хранятся —
/// вытаскиваются из имён по мере надобности (сводка в списке шоу, метка в расписании админки).</summary>
public static class EpisodeName
{
    /// <summary>Потолок на один Match. Шаблоны ниже линейные и в катастрофический бэктрекинг не уходят,
    /// но имя файла приходит извне (загрузка, inbox), а разбор идёт в цикле по всей библиотеке —
    /// страховка стоит ноль, а её отсутствие превращает любую будущую правку шаблона в риск.</summary>
    private static readonly TimeSpan MatchTimeout = TimeSpan.FromSeconds(1);

    private static readonly Regex SxxEyy = new(
        @"[Ss](\d{1,2})[ ._-]*[Ee](\d{1,3})",
        RegexOptions.Compiled,
        MatchTimeout
    );

    private static readonly Regex NxNN = new(
        @"(?:^|[^\d])(\d{1,2})x(\d{1,3})",
        RegexOptions.Compiled | RegexOptions.IgnoreCase,
        MatchTimeout
    );

    // Ведущий номер серии: «01. Название», «02 - Название», «03_Название» — сезон считаем первым.
    private static readonly Regex LeadingNumber = new(
        @"^\s*(\d{1,3})[\s._)\]-]",
        RegexOptions.Compiled,
        MatchTimeout
    );

    public static (int Season, int Episode)? Parse(string? name)
    {
        if (string.IsNullOrEmpty(name))
            return null;

        var match = SxxEyy.Match(name);
        if (match.Success)
            return (Int(match, 1), Int(match, 2));

        match = NxNN.Match(name);
        if (match.Success)
            return (Int(match, 1), Int(match, 2));

        match = LeadingNumber.Match(name);
        if (match.Success)
            return (1, Int(match, 1));

        return null;
    }

    private static int Int(Match match, int group) =>
        int.Parse(match.Groups[group].Value, CultureInfo.InvariantCulture);

    public static int? ParseSeason(string? name) => Parse(name)?.Season;

    /// <summary>Метка вида «S16E03», либо null если распознать не удалось.</summary>
    public static string? ParseLabel(string? name) =>
        Parse(name) is { } p ? $"S{p.Season:D2}E{p.Episode:D2}" : null;
}
