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; using System.Windows; namespace Elwig.Models.Dtos { public class WineQualityStatisticsData { public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, int Oe, int Weight); public record struct QualitySection(string Name, string? Type, Dictionary Data); 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)).ToArray(); currentQual.Clear(); } if (lastSection != null && lastSection != sec) { if (!current.ContainsKey(lastQual!)) { current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value)).ToArray(); currentQual.Clear(); } data.Add(new(lastSection, lastType, current)); current = []; currentQual.Clear(); } currentQual[row.Oe] = row.Weight; lastSection = sec; lastType = row.Type; lastQual = row.QualId; } if (lastQual != null) { current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value)).ToArray(); currentQual.Clear(); } if (lastSection != null) { data.Add(new(lastSection, lastType, current)); current = []; currentQual.Clear(); } return [.. data]; } public static async Task FromQuery(IQueryable query) { var rows = (await query .GroupBy(p => new { p.Variety.Type, Variety = p.Variety.Name, Attribute = p.Attribute!.Name, Cultivation = p.Cultivation!.Name, p.QualId, Oe = (int)Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0), }, (k, g) => new { Key = k, Weight = 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.Oe) .ToListAsync()) .Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.Key.Oe, 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.Oe }, (k, g) => new QualityRow(null, null, null, k.Type, k.QualId, k.Oe, g.Sum(p => p.Weight))) .OrderBy(g => g.Type) .ThenBy(g => g.QualId) .ThenBy(g => g.Oe) .ToList(); var typeData = GetQualitySections(typeRows); if (typeData.Length <= 1) return new([.. typeData, .. data]); var totalRows = rows .GroupBy(s => new { s.QualId, s.Oe }, (k, g) => new QualityRow(null, null, null, null, k.QualId, k.Oe, g.Sum(p => p.Weight))) .OrderBy(g => g.QualId) .ThenBy(g => g.Oe) .ToList(); var totalData = GetQualitySections(totalRows); return new([.. totalData, .. typeData, .. data]); } } }