using Modules.Library.Domain.Entities.MediaContent.CommonProperties;

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

public sealed class AnimeSeason : AnimeItem, IVariantItem
{
    private List<AnimeEpisode> _episodes = [];
    public IReadOnlyCollection<AnimeEpisode> Episodes => _episodes.AsReadOnly();

    public int? Number { get; private set; }
    public string? Director { get; private set; }
    public string? OriginCountry { get; private set; }

    private  AnimeSeason(AnimeTitle title) : base(title) { }

    private  AnimeSeason(AnimeTitle title, Models.AnimeSeason season) : base(title)
    {
        Id = season.Id;
        CommonProperties = MediaContent.CommonProperties.CommonProperties.New(season.CommonProperties);
        Deleted = season.Deleted;
        Number = season.Number;
        Order = season.Order;
        //Variant = season.Variant;
        Director = season.Director;
        OriginCountry = season.OriginCountry;
        Completed = season.Completed;
        ExpirationTime = season.ExpirationTime;
        _episodes = season.Episodes.Select(q => AnimeEpisode.New(title, this, q)).ToList();
    }

    internal AnimeSeason(AnimeTitle title, ushort order, int? number = null) :
        base(title)
    {
        Order = order;
        Number = number;
    }

    internal AnimeSeason(AnimeTitle title, IEnumerable<NameItem> names, ushort order, int? number = null) : base(title, names)
    {
        Order = order;
        Number = number;
    }

    internal static AnimeSeason New(AnimeTitle title, Models.AnimeSeason season) => new(title, season);

    public AnimeEpisode AddEpisode(AnimeEpisodeType type, int? number = null) =>
        CreateAndAddEpisode(type, number: number);

    public AnimeEpisode AddEpisodeAsVariant(AnimeEpisodeType type, ushort order, int? number = null) =>
        CreateAndAddEpisode(type, order, number:number);

    private AnimeEpisode CreateAndAddEpisode(AnimeEpisodeType type, ushort? order = null, ushort? variant = null, int? number = null)
    {
        StructureAction(() =>
        {
            (order, variant) = GetOrderAndVariant(_episodes.Select(q => (AnimeItem)q), order, variant);
            _episodes.Add(new AnimeEpisode(_title, this, type, order.Value, variant.Value, number));
        });
        return _episodes.OrderByDescending(q => q.Order).ThenByDescending(q => q.Variant).First();
    }

    public AnimeEpisode AddEpisode(AnimeEpisodeType type, IEnumerable<NameItem> names, int? number = null) =>
        CreateAndAddEpisode(type, names, number: number);

    public AnimeEpisode AddEpisodeAsVariant(AnimeEpisodeType type, IEnumerable<NameItem> names, ushort order, int? number = null) =>
        CreateAndAddEpisode(type, names, order, number:number);

    private AnimeEpisode CreateAndAddEpisode(AnimeEpisodeType type, IEnumerable<NameItem> names,
        ushort? order = null, ushort? variant = null, int? number = null)
    {
        StructureAction(() =>
        {
            (order, variant) = GetOrderAndVariant(_episodes.Select(q => (AnimeItem)q), order, variant);
            _episodes.Add(new AnimeEpisode(_title, this, type, names, order.Value, variant.Value, number));
        });
        return _episodes.OrderByDescending(q => q.Order).ThenByDescending(q => q.Variant).First();
    }

    public void RemoveEpisode(ushort order, ushort variant)
    {
        var episode = _episodes.FirstOrDefault(q => q.Order == order && q.Variant == variant) ??
            throw new Exception("EpisodeNotFoundException");
        _episodes.Remove(episode);
    }

    //public override void SetOrder(ushort order) => _title.SetItemOrder(Order, order);
    public override void SetOrder(ushort order) => SetItemOrder(_title.Items, Order, order);

    public override void SetVariant(ushort variant) => throw new NotImplementedException();


    internal void AfterEpisodeExpirationTimeSet() => StructureAction(() => { });

    public void SetNumber(int? number) => Number = number;

    public void SetDirector(string? director) => Director = director;

    public void SetOriginCountry(string? originCountry) => OriginCountry = originCountry;


    protected override void StructureAction(Action action)
    {
        action();
        CheckIfCompleted();
        _title.CheckIfCompleted();
    }

    internal void CheckIfCompleted()
    {
        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();

        if (unreleasedEpisodesAreExists || lastEpisodeReleaseDate >= DateTime.UtcNow - ExpirationTime) Completed = false;
        else Completed = true;

    }
}