using System;
using System.Collections.Generic;
using System.Linq;

namespace MuzikaGromche;

public delegate bool SeasonalContentPredicate(DateTime dateTime);

// I'm not really sure what to do with seasonal content yet.
//
// There could be two approaches:
// - Force seasonal content tracks to be the only available tracks during their season.
//   Then seasons must be short, so they don't cut off too much content for too long.
// - Exclude seasonal content tracks from the pool when their season is not active.
//   Considering how many tracks are there in the playlist permanently already,
//   this might not give the seasonal content enough visibility.
//
// Either way, seasonal content tracks would be listed in the config UI at all times,
// which makes it confusing if you try to select only seasonal tracks outside of their season.

// Seasons may NOT overlap. There is at most ONE active season at any given date.
public readonly record struct Season(string Name, string Description, SeasonalContentPredicate IsActive)
{
    public override string ToString() => Name;

    public static readonly Season NewYear = new("New Year", "New Year and Christmas holiday season", dateTime =>
    {
        // December 10 - February 29
        var month = dateTime.Month;
        var day = dateTime.Day;
        return (month == 12 && day >= 10) || (month == 1) || (month == 2 && day <= 29);
    });

    // Note: it is important that this property goes last
    public static readonly Season[] All = [NewYear];
}

public interface ISeasonalContent
{
    public Season? Season { get; init; }
}

public static class SeasonalContentManager
{
    public static Season? CurrentSeason(DateTime dateTime)
    {
        foreach (var season in Season.All)
        {
            if (season.IsActive(dateTime))
            {
                return season;
            }
        }
        return null;
    }

    public static Season? CurrentSeason() => CurrentSeason(DateTime.Today);

    // Take second approach: filter out seasonal content that is not in the current season.
    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Season? season) where T : ISeasonalContent
    {
        return items.Where(item =>
        {
            if (item.Season == null)
            {
                return true; // always available
            }
            return item.Season == season;
        });
    }

    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, DateTime dateTime) where T : ISeasonalContent
    {
        var season = CurrentSeason(dateTime);
        return Filter(items, season);
    }

    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items) where T : ISeasonalContent
    {
        return Filter(items, DateTime.Today);
    }
}
