using Elwig.Documents;
using Elwig.Models.Entities;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Elwig.Helpers;
using System;

namespace Elwig.Models.Dtos {
    public class MemberListData : DataTable<MemberListRow> {

        private static readonly (string, string, string?, int?)[] FieldNames = [
            ("MgNr", "MgNr.", null, 12),
            ("Name1", "Name", null, 40),
            ("Name2", "Vorname", null, 40),
            ("Address", "Adresse", null, 60),
            ("Plz", "PLZ", null, 10),
            ("Locality", "Ort", null, 60),
            ("DefaultKg", "Stammgemeinde", null, 60),
            ("Branch", "Zweigstelle", null, 40),
            ("BusinessShares", "GA", null, 10),
            ("BillingName", "Rechnungsname", null, 60),
            ("BillingAddress", "Rechnungsadresse", null, 60),
            ("BillingPlz", "PLZ", null, 10),
            ("BillingLocality", "Ort", null, 60),
            ("LfbisNr", "Betr.-Nr.", null, 20),
            ("IsBuchführend", "buchf.", null, 15),
            ("IsOrganic", "Bio", null, 15),
            ("IsActive", "aktiv", null, 15),
            ("EntryDate", "Eintritt", null, 20),
            ("ExitDate", "Austritt", null, 20),
            ("AreaCommitment", "geb. Fläche", "m²", 20),
            ("AreaCommitmentsFiltered", "geb. Fläche", "Vtrg.|m²", 30),
            ("UstIdNr", "UID", null, 25),
            ("Iban", "IBAN", null, 45),
            ("Bic", "BIC", null, 30),
            ("TelNrLandline", "Festnetz", null, 35),
            ("TelNrMobile", "Mobil", null, 35),
            ("EmailAddress", "E-Mail", null, 70),
            ("AdditionalContact", "Weitere", null, 70),
            ("Comment", "Anmerkung", null, 80),
        ];

        public MemberListData(IEnumerable<MemberListRow> rows, List<string> filterNames) :
            base(MemberList.Name, MemberList.Name, string.Join(" / ", filterNames), rows, FieldNames) {
        }

        public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
            var areaComs = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
            return new((await query
                .Include(m => m.DefaultWbKg!.AtKg)
                .Include(m => m.Branch)
                .Include(m => m.PostalDest.AtPlz!.Ort)
                .Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
                .Include(m => m.TelephoneNumbers)
                .Include(m => m.EmailAddresses)
                .AsSplitQuery()
                .ToListAsync()).Select(m => new MemberListRow(m,
                    areaComs[m.MgNr].Sum(c => c.Area),
                    areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))),
                filterNames);
        }
    }

    public class MemberListRow {
        public int MgNr;
        public string? Name1;
        public string? AdminName1;
        public string? Name2;
        public string? DefaultKg;
        public string? Branch;
        public int BusinessShares;
        public string Address;
        public int Plz;
        public string Locality;
        public string? BillingName;
        public string? BillingAddress;
        public int? BillingPlz;
        public string? BillingLocality;
        public string? LfbisNr;
        public string? UstIdNr;
        public string? Iban;
        public string? Bic;
        public int? AreaCommitment;
        public (string VtrgId, int Area)[] AreaCommitmentsFiltered;
        public bool IsBuchführend;
        public bool IsOrganic;
        public bool IsActive;
        public DateOnly? EntryDate;
        public DateOnly? ExitDate;
        public string? TelNrLandline;
        public string? TelNrMobile;
        public string? EmailAddress;
        public string? AdditionalContact;
        public string? Comment;

        public MemberListRow(Member m, int? areaCom = null, Dictionary<string, int>? filtered = null) {
            MgNr = m.MgNr;
            Name1 = m.Name;
            AdminName1 = m.AdministrativeName1;
            Name2 = m.AdministrativeName2;
            DefaultKg = m.DefaultKg?.Name;
            Branch = m.Branch?.Name;
            BusinessShares = m.BusinessShares;
            Address = m.Address;
            Plz = m.PostalDest.AtPlz!.Plz;
            Locality = m.PostalDest.AtPlz!.Ort.Name;
            if (m.BillingAddress is BillingAddr a) {
                BillingName = a.FullName;
                BillingAddress = a.Address;
                BillingPlz = a.PostalDest.AtPlz!.Plz;
                BillingLocality = a.PostalDest.AtPlz!.Ort.Name;
            }
            LfbisNr = m.LfbisNr;
            UstIdNr = m.UstIdNr;
            Iban = m.Iban != null ? Utils.FormatIban(m.Iban) : null;
            Bic = m.Bic;
            IsBuchführend = m.IsBuchführend;
            IsOrganic = m.IsOrganic;
            IsActive = m.IsActive;
            EntryDate = m.EntryDate;
            ExitDate = m.ExitDate;
            TelNrLandline = m.TelephoneNumbers.OrderBy(n => n.Nr).FirstOrDefault(n => n.Type == "landline")?.Number;
            TelNrMobile = m.TelephoneNumbers.OrderBy(n => n.Nr).FirstOrDefault(n => n.Type == "mobile")?.Number;
            EmailAddress = m.EmailAddresses.OrderBy(a => a.Nr).FirstOrDefault()?.Address;
            AdditionalContact = string.Join(", ", m.TelephoneNumbers
                .OrderBy(n => n.Nr)
                .Select(n => n.Number)
                .Except([TelNrLandline, TelNrMobile])
                .Distinct()
                .Concat(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).Except([EmailAddress])));
            Comment = m.Comment;
            AreaCommitment = areaCom == 0 ? null : areaCom;
            AreaCommitmentsFiltered = filtered != null ? filtered.OrderBy(f => f.Key).Select(f => (f.Key, f.Value)).ToArray() : [];
        }
    }
}