using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
using System.Linq.Expressions;
using System.Reflection;

namespace Modules.Library.Domain.EntityBuilders;

public abstract class AnimeItemBuilder<TAnimeItem> : EntityBuilder<TAnimeItem> where TAnimeItem : AnimeItem
{
    protected CommonPropertiesBuilder? _commonPropertiesBuilder;
    protected CommonProperties? _commonProperties = null;

    protected AnimeTitle _title = default!;
    private ushort? _order = null;
    protected int? _number = null;
    private bool? _completed = null;
    private TimeSpan? _expirationTime = null;

    public AnimeItemBuilder<TAnimeItem> SetCommonProperties(CommonPropertiesBuilder builder)
    {
        _commonPropertiesBuilder = builder;
        return this;
    }

    public AnimeItemBuilder<TAnimeItem> SetOrder(ushort value)
    {
        _order = value;
        return this;
    }

    public AnimeItemBuilder<TAnimeItem> SetNumber(int? value)
    {
        _number = value;
        return this;
    }

    public AnimeItemBuilder<TAnimeItem> Completed()
    {
        _completed = true;
        return this;
    }

    public AnimeItemBuilder<TAnimeItem> SetExpirationTime(TimeSpan value)
    {
        _expirationTime = value;
        return this;
    }

    public override TAnimeItem Build() => throw new NotImplementedException();

    protected void BuildLoaclObjects()
    {
        if (_commonPropertiesBuilder != null) _commonProperties = _commonPropertiesBuilder.BuildObject();
    }

    //AnimeItemBuilder<TAnimeItem> itemBuilder, AnimeEpisode item, 
    protected static Action<AnimeItemBuilder<TAnimeItem>, TAnimeItem> AddFields(List<string> fields)
    {
        var type = typeof(AnimeEpisode);
        var builderType = typeof(AnimeItemBuilder<TAnimeItem>);
        var builder = Expression.Parameter(builderType, "builder");
        var entity = Expression.Parameter(type, "entity");

        var expressions = new List<Expression>();
        var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
        var members = new List<FieldInfo>();
        fields.ForEach(q =>
        {
            var fi = fieldInfos.FirstOrDefault(x => x.Name == q.Trim());
            if (fi != null) members.Add(fi);
        });
        foreach (var fi in members)
        {
            var field = type.GetField(fi.Name, BindingFlags.Instance | BindingFlags.NonPublic);
            if (field != null) expressions.Add(Expression.Assign(Expression.Field(entity, field), Expression.Field(builder, fi)));
        }

        var lambda = Expression.Lambda<Action<AnimeItemBuilder<TAnimeItem>, TAnimeItem>>(Expression.Block(expressions), builder, entity);
        return lambda.Compile();
    }
}