using Elwig.Models.Entities; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder; using System.Linq; using System.Threading.Tasks; namespace Elwig.Models.Dtos { public class WineQualityStatisticsData { public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, double AvgKmw, double Grad, int Num, int Weight); public record struct QualitySection(string Name, string? Type, Dictionary Data); public bool UseOe = true; public QualitySection[] Sections; public WineQualityStatisticsData(QualitySection[] sections) { Sections = sections; } private static QualitySection[] GetQualitySections(IEnumerable rows) { var data = new List(); var currentQual = new Dictionary(); var current = new Dictionary(); string? lastSection = null; string? lastType = null; string? lastQual = null; foreach (var row in rows) { var sec = $"{row.Variety ?? (row.Type == "R" ? "Rotweinsorten" : row.Type == "W" ? "Weißweinsorten" : "Gesamt")}" + $"{(row.Attribute != null ? " / " : "")}{row.Attribute}" + $"{(row.Cultivation != null ? " / " : "")}{row.Cultivation}"; if (lastQual != null && lastQual != row.QualId) { current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } if (lastSection != null && lastSection != sec) { if (!current.ContainsKey(lastQual!)) { current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } data.Add(new(lastSection, lastType, current)); current = []; currentQual.Clear(); } currentQual[row.Grad] = (row.AvgKmw, row.Num, row.Weight); lastSection = sec; lastType = row.Type; lastQual = row.QualId; } if (lastQual != null) { current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } if (lastSection != null) { data.Add(new(lastSection, lastType, current)); current = []; currentQual.Clear(); } return [.. data]; } public static async Task FromQuery(IQueryable query, int mode = 0) { var rows = (await query .GroupBy(p => new { p.Variety.Type, Variety = p.Variety.Name, Attribute = p.Attribute!.Name, Cultivation = p.Cultivation!.Name, p.QualId, Grad = mode == 0 ? Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0) : mode == 1 ? Math.Floor(p.Kmw) : mode == 2 ? Math.Floor(p.Kmw * 2) / 2 : mode == 3 ? Math.Floor(p.Kmw * 5) / 5 : Math.Round(p.Kmw, 1), }, (k, g) => new { Key = k, Num = g.Count(), Weight = g.Sum(p => p.Weight), AvgKmw = g.Sum(p => p.Weight * p.Kmw) / g.Sum(p => p.Weight), }) .OrderBy(g => g.Key.Variety) .ThenBy(g => g.Key.Attribute) .ThenBy(g => g.Key.Cultivation) .ThenBy(g => g.Key.QualId) .ThenBy(g => g.Key.Grad) .ToListAsync()) .Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight)) .ToList(); var data = GetQualitySections(rows); if (data.Length <= 1) return new(data); var typeRows = rows .GroupBy(s => new { s.Type, s.QualId, s.Grad }, (k, g) => new QualityRow( null, null, null, k.Type, k.QualId, g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight), k.Grad, g.Sum(p => p.Num), g.Sum(p => p.Weight) )) .OrderBy(g => g.Type) .ThenBy(g => g.QualId) .ThenBy(g => g.Grad) .ToList(); var typeData = GetQualitySections(typeRows); if (typeData.Length <= 1) return new([.. typeData, .. data]); var totalRows = rows .GroupBy(s => new { s.QualId, s.Grad }, (k, g) => new QualityRow( null, null, null, null, k.QualId, g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight), k.Grad, g.Sum(p => p.Num), g.Sum(p => p.Weight) )) .OrderBy(g => g.QualId) .ThenBy(g => g.Grad) .ToList(); var totalData = GetQualitySections(totalRows); return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 }; } } }