using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Threading.Tasks;

namespace Elwig.Models.Dtos {
    public class OverUnderDeliveryData : DataTable<OverUnderDeliveryRow> {

        private static readonly (string, string, string?, int)[] FieldNames = new[] {
            ("MgNr", "MgNr.", null, 12),
            ("Name", "Name", null, 40),
            ("GivenName", "Vorname", null, 40),
            ("Address", "Adresse", null, 60),
            ("Plz", "PLZ", null, 10),
            ("Locality", "Ort", null, 60),
            ("BusinessShares", "GA", null, 10),
            ("DeliveryObligation", "Lieferpflicht", "kg", 22),
            ("DeliveryRight", "Lieferrecht", "kg", 22),
            ("Weight", "Geliefert", "kg", 22),
            ("OverUnderDelivery", "Über-/Unterliefert", "kg|%", 34),
        };

        public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year) :
            base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) {
        }

        public static async Task<OverUnderDeliveryData> ForSeason(DbSet<OverUnderDeliveryRow> table, int year) {
            var rows = await table.FromSqlRaw($"""
                SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name AS ort, m.address, m.business_shares,
                       m.business_shares * s.min_kg_per_bs AS min_kg,
                       m.business_shares * s.max_kg_per_bs AS max_kg,
                       COALESCE(SUM(d.weight), 0) AS sum
                FROM member m
                    LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
                    LEFT JOIN AT_ort o ON o.okz = p.okz
                    LEFT JOIN season s ON s.year = {year}
                    LEFT JOIN v_delivery d ON d.mgnr = m.mgnr AND d.year = s.year
                WHERE m.active = 1
                GROUP BY d.year, m.mgnr
                ORDER BY 100.0 * sum / max_kg, m.mgnr;
                """).ToListAsync();
            return new OverUnderDeliveryData(rows, year);
        }
    }

    [Keyless]
    public class OverUnderDeliveryRow {
        [Column("mgnr")]
        public int MgNr { get; set; }
        [Column("family_name")]
        public string Name { get; set; }
        [Column("given_name")]
        public string GivenName { get; set; }
        [Column("address")]
        public string Address { get; set; }
        [Column("plz")]
        public int Plz { get; set; }
        [Column("ort")]
        public string LocalityFull { get; set; }
        [NotMapped]
        public string Locality => LocalityFull.Split(",")[0];
        [Column("business_shares")]
        public int BusinessShares { get; set; }
        [Column("min_kg")]
        public int DeliveryObligation { get; set; }
        [Column("max_kg")]
        public int DeliveryRight { get; set; }
        [Column("sum")]
        public int Weight { get; set; }
        [NotMapped]
        public (int? Kg, double? Percent) OverUnderDelivery =>
            Weight < DeliveryObligation ? (Weight - DeliveryObligation, Weight * 100.0 / DeliveryObligation - 100.0) :
            Weight > DeliveryRight ? (Weight - DeliveryRight, Weight * 100.0 / DeliveryRight - 100) : (null, null);
    }
}