using Modules.Library.Domain.EntitiesV0.MediaContent.Items.Anime.ShadowEntities; namespace Modules.Library.Domain.EntitiesV0.MediaContent.Items.Anime; public class AnimeSeason : AnimeItem { private readonly AnimeTitle _title; private readonly AnimeSeasonShadow _shadow; public IReadOnlyCollection Episodes => _shadow.episodes.Select(q => new AnimeEpisode(_title, this, q)).ToList().AsReadOnly(); public int? Number => _shadow.number; public string? Director => _shadow.director; public string? OriginCountry => _shadow.originCountry; internal AnimeSeason(AnimeTitle title, AnimeSeasonShadow shadow) : base(shadow) { _title = title; _shadow = shadow; } protected override CommonProperties.CommonProperties GetCommonProperties() => new(_shadow.commonProperties, CheckIsCompleted, CheckIsCompleted, CheckIsCompleted); public void AddEpisode(AnimeEpisodeType episodeType) { StructureAction(() => { var episode = new AnimeEpisodeShadow { type = episodeType, order = GetNewOrder(_shadow.episodes), number = _shadow.episodes.OfType().Select(q => q.number).DefaultIfEmpty(-1).Max() + 1, }; _shadow.episodes.Add(episode); }); } public void AddEpisodeAsVariant(AnimeEpisodeType episodeType, ushort order) { StructureAction(() => { if (order < 0 || order > _shadow.episodes.Select(q => q.order).DefaultIfEmpty(0).Max()) throw new ArgumentOutOfRangeException(nameof(order)); var episode = new AnimeEpisodeShadow { type = episodeType, order = order, variant = GetNewVariant(_shadow.episodes, order), number = _shadow.episodes.FirstOrDefault(q => q.order == order)?.number, }; _shadow.episodes.Add(episode); }); } public void RemoveEpisode(AnimeEpisode episode) { StructureAction(() => { episode.SetDeleted(); Sort(_shadow.episodes.Where(q => !q.deleted)); }); } internal void SetEpisodeOrder(ushort currentOrder, ushort newOrder) => SetItemOrder(_shadow.episodes, currentOrder, newOrder); internal void SetEpisodeVariant(ushort order, ushort currentVariant, ushort newVariant) => SetItemVariant(_shadow.episodes.Where(q => q.order == order), currentVariant, newVariant); internal void SetEpisodeCompleted(ushort order, ushort variant, bool value = true) { StructureAction(() => { var episode = _shadow.episodes.FirstOrDefault(q => q.order == order && q.variant == variant) ?? throw new Exception("Episode not found"); episode.completed = value; }); } internal void SetEpisodeExpirationTime(ushort order, ushort variant, TimeSpan value) { StructureAction(() => { var episode = _shadow.episodes.FirstOrDefault(q => q.order == order && q.variant == variant) ?? throw new Exception("Episode not found"); episode.expirationTime = value; }); } private void StructureAction(Action action) { action(); CheckIsCompleted(); _title.CheckIsCompleted(); //return new AnimeEpisode(title, this, episodeShadow); } public override void SetOrder(ushort order) => SetItemOrder(_title._shadow.items, Order, order); public override void SetVariant(ushort variant) => throw new NotImplementedException(); public override void SetCompleted() { _title.SetSeasonCompleted(Order, Variant, true); } public override void SetNotCompleted() { throw new NotImplementedException(); } public override void SetExpirationTime(TimeSpan value) { throw new NotImplementedException(); } internal void SetNumber(int? number) => _shadow.number = number; internal void SetDirector(string? director) => _shadow.director = director; internal void SetOriginCountry(string? originCountry) => _shadow.originCountry = originCountry; internal void CheckIsCompleted() { var itemsQuery = Episodes.Where(q => !q.Deleted).AsQueryable(); var unreleasedEpisodesAreExists = itemsQuery .Any(q => !q.CommonProperties.ReleaseDate.HasValue); var lastEpisodeReleaseDate = itemsQuery .OrderByDescending(q => q.CommonProperties.ReleaseDate) .FirstOrDefault()?.CommonProperties.ReleaseDate; //return unreleasedEpisodesAreExists || lastEpisodeReleaseDate - DateTime.UtcNow > expirePeriod; if (unreleasedEpisodesAreExists || lastEpisodeReleaseDate >= DateTime.UtcNow - ExpirationTime) SetNotCompleted(); else SetCompleted(); } }