using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;

namespace YBEE.EQM.Core;

public static class ListExtensions
{
    public static List<dynamic> ToPivotList<T, TColumn, TRow, TData>(this IEnumerable<T> source, Func<T, TColumn> columnSelector, Expression<Func<T, TRow>> rowSelector, Func<IEnumerable<T>, TData> dataSelector, string columnNamePrefix="")
    {
        var arr = new List<object>();
        var cols = new List<string>();
        string rowName = ((MemberExpression)rowSelector.Body).Member.Name;
        var columns = source.Select(columnSelector).Distinct();
        cols = (new[] { rowName }).Concat(columns.Select(x => $"{columnNamePrefix}{x}")).ToList();
        var rows = source.GroupBy(rowSelector.Compile())
                         .Select(rowGroup => new
                         {
                             rowGroup.Key,
                             Values = columns.GroupJoin(rowGroup, c => c, r => columnSelector(r), (c, columnGroup) => dataSelector(columnGroup))
                         }).ToArray();
        foreach (var row in rows)
        {
            var items = row.Values.Cast<object>().ToList();
            items.Insert(0, row.Key);
            var obj = GetAnonymousObject(cols, items);
            arr.Add(obj);
        }
        return arr.ToList();
    }

    private static dynamic GetAnonymousObject(IEnumerable<string> columns, IEnumerable<object> values)
    {
        IDictionary<string, object> eo = new ExpandoObject();
        int i;
        for (i = 0; i < columns.Count(); i++)
        {
            eo.Add(columns.ElementAt(i), values.ElementAt(i));
        }
        return eo;
    }
}
