using System.Linq.Expressions;
using InABox.Core;

namespace InABox.Database;

public abstract class DatabaseUpdateScript
{
    public abstract VersionNumber Version { get; }
    public abstract bool Update();
        
    protected struct Map<T>
    {
        public String Old;
        public Expression<Func<T, object>> New;

        public Map(String oldcolumn, Expression<Func<T, object>> newcolumn)
        {
            Old = oldcolumn;
            New = newcolumn;
        }
    }
    
    protected void Convert<T>(
        Filter<T> filter,
        params Map<T>[] maps
    ) where T : Entity, IPersistent, IRemotable, new()
    {
        Logger.Send(LogType.Information, "", $"Converting {typeof(T).EntityName().Split('.').Last()}...");
        List<T> updates = new List<T>();
        var columns = Columns.None<T>().Add(x => x.ID);
        foreach (var map in maps)
        {
            columns.Add(map.Old);
            columns.Add(map.New);
        }

        CoreTable table = DbFactory.NewProvider(Logger.Main).Query<T>(filter,columns);
        int iCount = 0;
        foreach (var row in table.Rows)
        {
            

            var update = row.ToObject<T>();
            foreach (var map in maps)
                CoreUtils.SetPropertyValue(update, CoreUtils.GetFullPropertyName<T, object>(map.New, "."), CoreUtils.GetPropertyValue(update, map.Old));
            if (update.IsChanged())
                updates.Add(update);
    
            if (updates.Count == 100)
            {
                iCount += updates.Count;
                Logger.Send(LogType.Information, "", $"Converting {typeof(T).EntityName().Split('.').Last()} Times ({iCount}/{table.Rows.Count}");
                DbFactory.NewProvider(Logger.Main).Save(updates);
                updates.Clear();
            }
        }
        
        if (updates.Count > 0)
        {
            iCount += updates.Count;
            Logger.Send(LogType.Information, "", $"Converting {typeof(T).EntityName().Split('.').Last()} Times ({iCount}/{table.Rows.Count})");
            DbFactory.NewProvider(Logger.Main).Save(updates);
            updates.Clear();
        }
        
    }
    
}