namespace Modules.Library.Core.Domain.MediaContent.Items.Anime;

public class AnimeTitle : TopLevelItem
{
    public void AddSeason()
    {
        var season = new AnimeSeason();
        _items.Add(season);
        CheckIfCompleted();
    }


    public void AddEpisode(AnimeEpisodeType type, Guid? seasonId = null)
    {
        var episode = new AnimeEpisode
        {
            Type = type
        };
        if (!seasonId.HasValue)
        {
            _items.Add(episode);
            episode.SetOrder(GetItemsLastOrder() + 1);
        }
        else
        {
            var season = GetSeason(seasonId.Value);
            season.AddEpisode(episode);
        }
        CheckIfCompleted();
    }

    public void AddEpisodeVariant(AnimeEpisodeType type, uint episodeOrder, Guid? seasonId = null)
    {
        var episode = new AnimeEpisode
        {
            Type = type
        };
        if (!seasonId.HasValue)
        {
            var lastVariant = _items.OrderByDescending(q => q.Variant).FirstOrDefault(q => q.Order == episodeOrder)?.Variant ??
            throw new Exception($"Could not find episode with order [{episodeOrder}]");
            _items.Add(episode);
            episode.SetOrder(episodeOrder);
            episode.SetOrder(lastVariant + 1);
        }
        else
        {
            var season = GetSeason(seasonId.Value);
            season.AddEpisodeAsVariant(episode, episodeOrder);
        }
        CheckIfCompleted();
    }

    private uint GetItemsLastOrder() =>
        (uint)(_items.OfType<IOrderableItem>()
        .OrderByDescending(q => q.Order).LastOrDefault()?.Order ?? -1u);
    private void CheckIfCompleted()
    {
        var itemsQuery = Items.AsQueryable();
        var ucompletedSeasons = itemsQuery
            .Any(q => !q.CommonProperties.ReleaseDate.HasValue);
        var lastEpisodeReleaseDate = itemsQuery
            .OrderByDescending(q => q.CommonProperties.ReleaseDate)
            .FirstOrDefault()?.CommonProperties.ReleaseDate;
        if (ucompletedSeasons || lastEpisodeReleaseDate >= (DateTime.UtcNow - ExpirationTime)) SetNotCompleted();
        else SetCompleted();
    }

    #region Episode Properties
    public void SetEpisodeDuration(Guid episodeId, TimeSpan? value, Guid ? seasonId = null)
    {
        var episode = GetEpisode(episodeId, seasonId);
        episode.Duration = value;
    }

    #region Name
    public void AddEpisodeName(Guid episodeId, TimeSpan? value, Guid? seasonId = null)
    {
        var episode = GetEpisode(episodeId, seasonId);
        episode.Duration = value;
    }
    
    public void AddName(CommonProperties.CommonProperties commonProperties, Language.Language language, string? value)
    {
        var episode = GetEpisode(episodeId, seasonId);
        episode.Duration = value;
    }
    #endregion

    #region Description

    #endregion

    #region Genre

    #endregion

    #endregion

    private AnimeEpisode GetEpisode(Guid episodeId, Guid? seasonId = null)
    {
        AnimeEpisode? result = null;
        if (seasonId.HasValue)
        {
            var season = GetSeason(seasonId.Value);
            result = season.Items.OfType<AnimeEpisode>()
                .FirstOrDefault(q => q.Id == episodeId);
        }
        else
        {
            result = _items.OfType<AnimeEpisode>()
                .FirstOrDefault(q => q.Id == episodeId);
        }
        return result ?? throw new Exception($"Could not find episode with id [{episodeId}]");
    }

    private AnimeSeason GetSeason(Guid seasonId) =>
        _items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == seasonId) ??
        throw new Exception($"Could not find season with id [{seasonId}]");
}
