using Modules.Library.Domain.Entities.MediaContent.CommonProperties; using Modules.Library.Domain.Entities.MediaContent.Items.Anime.ShadowEntities; namespace Modules.Library.Domain.Entities.MediaContent.Items.Anime; public class AnimeTitle : Entity { public CommonProperties.CommonProperties CommonProperties { get; private set; } = new(); /* private List _items = []; public IReadOnlyList Items => _items.AsReadOnly(); */ public List Items { get; set; } = []; public bool Completed { get; internal set; } public TimeSpan ExpirationTime { get; set; } private AnimeTitle() { } internal AnimeTitle(string nameOriginal, Guid nameOriginalLanguageId) { CommonProperties.Names.Add(new NameItem(nameOriginalLanguageId, NameType.Original, nameOriginal)); } private AnimeItem ConvertToAnimeItem(AnimeItemShadow shadow) { if (shadow is AnimeEpisodeShadow episode) return new AnimeEpisode(this, null, episode); else if (shadow is AnimeSeasonShadow season) return new AnimeSeason(this, season); else throw new NotImplementedException(); } public void AddEpisode(AnimeEpisodeType episodeType) { var episode = new AnimeEpisodeShadow { type = episodeType, order = AnimeItem.GetNewOrder(_shadow.items), number = _shadow.items.OfType().Select(q => q.number).DefaultIfEmpty(-1).Max() + 1, }; _shadow.items.Add(episode); CheckIsCompleted(); } public void AddEpisodeAsVariant(AnimeEpisodeType episodeType, ushort order) { if (order < 0 || order > _shadow.items.Select(q => q.order).DefaultIfEmpty(0).Max()) throw new ArgumentOutOfRangeException(nameof(order)); var episode = new AnimeEpisodeShadow { type = episodeType, order = order, variant = AnimeItem.GetNewVariant(_shadow.items, order), number = _shadow.items.OfType().FirstOrDefault(q => q.order == order)?.number, }; _shadow.items.Add(episode); CheckIsCompleted(); } public void RemoveEpisode(AnimeEpisode episode) { episode.SetDeleted(); AnimeItem.Sort(_shadow.items.Where(q => !q.deleted)); CheckIsCompleted(); } internal void SetEpisodeOrder(ushort currentOrder, ushort newOrder) => AnimeItem.SetItemOrder(_shadow.items, currentOrder, newOrder); internal void SetEpisodeVariant(ushort order, ushort currentVariant, ushort newVariant) => AnimeItem.SetItemVariant(_shadow.items.OfType() .Where(q => q.order == order), currentVariant, newVariant); internal void SetEpisodeCompleted(ushort order, ushort variant, bool value = true) => SetCompleted(order, variant, value); internal void SetEpisodeExpirationTime(ushort order, ushort variant, TimeSpan value) => SetExpirationTime(order, variant, value); public void AddSeason() { var episode = new AnimeSeasonShadow { order = AnimeItem.GetNewOrder(_shadow.items), number = _shadow.items.OfType().Select(q => q.number).DefaultIfEmpty(-1).Max() + 1, }; _shadow.items.Add(episode); CheckIsCompleted(); } /* public void AddSeasonAsVariant(AnimeEpisodeType episodeType, ushort order) { if (order < 0 || order > _shadow.items.Select(q => q.order).DefaultIfEmpty(0).Max()) throw new ArgumentOutOfRangeException(nameof(order)); var episode = new AnimeEpisodeShadow { type = episodeType, order = order, variant = AnimeItem.GetNewVariant(_shadow.items, order), number = _shadow.items.OfType().FirstOrDefault(q => q.order == order)?.number, }; _shadow.items.Add(episode); CheckIsCompleted(); } */ public void RemoveSeason(AnimeSeason season) { season.SetDeleted(); AnimeItem.Sort(_shadow.items.Where(q => !q.deleted)); CheckIsCompleted(); } internal void SetSeasonCompleted(ushort order, ushort variant, bool value = true) => SetCompleted(order, variant, value); internal void SetSeasonExpirationTime(ushort order, ushort variant, TimeSpan value) => SetExpirationTime(order, variant, value); private void SetCompleted(ushort order, ushort variant, bool value = true) where T : AnimeItemShadow { var item = GetItem(order, variant); item.completed = value; CheckIsCompleted(); } private void SetExpirationTime(ushort order, ushort variant, TimeSpan value) where T : AnimeItemShadow { var item = GetItem(order, variant); item.expirationTime = value; CheckIsCompleted(); } private T GetItem(ushort order, ushort variant) where T : AnimeItemShadow { var type = typeof(T); var itemName = string.Empty; if (type == typeof(AnimeEpisodeShadow)) itemName = "Episode"; else if (type == typeof(AnimeSeason)) itemName = "Season"; else throw new NotImplementedException(); return _shadow.items.OfType() .FirstOrDefault(q => q.order == order && q.variant == variant) ?? throw new Exception(string.Concat(itemName, " not found")); } public void SetCompleted() => _shadow.completed = true; public void SetNotCompleted() => _shadow.completed = false; public void SetExpirationTime(TimeSpan value) { _shadow.expirationTime = value; CheckIsCompleted(); } public void Delete() => SetDeleted(); internal override void SetDeleted() => _shadow.deleted = true; internal void CheckIsCompleted() { 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(); } }