using Elwig.Helpers;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Elwig.Documents {
    public class CreditNote : BusinessDocument {

        public new static string Name => "Traubengutschrift";

        public PaymentMember? Payment;
        public Credit? Credit;
        public CreditNoteDeliveryData Data;
        public string? Text;
        public string CurrencySymbol;
        public int Precision;
        public string MemberModifier;
        public IEnumerable<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
        public decimal MemberTotalUnderDelivery;
        public int MemberAutoBusinessShares;
        public decimal MemberAutoBusinessSharesAmount;
        public PaymentCustom? CustomPayment;

        public CreditNote(
            AppDbContext ctx,
            PaymentMember p,
            CreditNoteDeliveryData data,
            bool considerContractPenalties,
            bool considerTotalPenalty,
            bool considerAutoBusinessShares,
            bool considerCustomModifiers,
            Dictionary<string, UnderDelivery>? underDeliveries = null
        ) :
            base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} – {p.Variant.Name}", p.Member) {
            UseBillingAddress = true;
            ShowDateAndLocation = true;
            Data = data;
            Payment = p;
            Credit = p.Credit;
            var season = p.Variant.Season;
            if (considerCustomModifiers) {
                CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr);
            }

            var mod = App.Client.IsMatzen ? ctx.Modifiers.Where(m => m.Year == season.Year && m.Name.StartsWith("Treue")).FirstOrDefault() : null;
            if (CustomPayment?.ModComment != null) {
                MemberModifier = CustomPayment.ModComment;
            } else if (mod != null) {
                MemberModifier = $"{mod.Name} ({mod.ValueStr})";
            } else {
                MemberModifier = "Sonstige Zu-/Abschläge";
            }
            Aside = Aside.Replace("</table>", "") +
                $"<thead><tr><th colspan='2'>Gutschrift</th></tr></thead><tbody>" +
                $"<tr><th>TG-Nr.:</th><td>{(p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : "-")}</td></tr>" +
                $"<tr><th>Datum:</th><td>{p.Variant.Date:dd.MM.yyyy}</td></tr>" +
                $"<tr><th>Überw. am:</th><td>{p.Variant.TransferDate:dd.MM.yyyy}</td></tr>" +
                $"</tbody></table>";
            Text = App.Client.TextCreditNote;
            DocumentId = $"Tr.-Gutschr. " + (p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : p.MgNr);
            CurrencySymbol = season.Currency.Symbol ?? season.Currency.Code;
            Precision = season.Precision;

            if (considerTotalPenalty) {
                var total = data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value);
                var totalUnderDelivery = total - p.Member.BusinessShares * season.MinKgPerBusinessShare;
                MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerBsAmount * Math.Floor(-(decimal)totalUnderDelivery / season.MinKgPerBusinessShare) ?? 0) : 0;
                if (total == 0)
                    MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * p.Member.BusinessShares ?? 0);
            }
            if (considerAutoBusinessShares) {
                var fromDate = $"{season.Year}-01-01";
                var toDate = $"{season.Year}-12-31";
                MemberAutoBusinessShares = ctx.MemberHistory
                    .Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto")
                    .Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
                    .Sum(h => h.BusinessShares);
                MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
            }
            if (considerContractPenalties) {
                var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
                var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
                var comTypes = ctx.AreaCommitmentTypes.ToDictionary(t => t.VtrgId, t => t);
                MemberUnderDeliveries = underDeliveries?
                    .OrderBy(u => u.Key)
                    .Select(u => (
                        varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""),
                        u.Value.Diff,
                        u.Value.Diff * (comTypes[u.Key].PenaltyPerKg ?? 0)
                          - (comTypes[u.Key].PenaltyAmount ?? 0)
                          - ((u.Value.Weight == 0 ? comTypes[u.Key].PenaltyNone : null) ?? 0)))
                    .Where(u => u.Item3 != 0)
                    .ToList();
            }
        }
    }}