#if DEBUG
#define MBE_TESTACCOUNT
//#define PRINT_NO_LABELS
//#define CREATE_MBE_ERROR
#endif
using KarleyLibrary.Erweiterungen;
using MbeSoap;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Basis.Filter;
using WK5.Core.Drucken.Briefe;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Models.Versand;
using WK5.Core.PageModels.Tools.Gewichtsberechner;
using WK5.Core.PageModels.Tools.Versand;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionen zur Verwendung der MBE-API zur Verfügung
    /// <para>
    /// Abrufen von Paketpreisen
    /// </para>
    /// <para>
    /// Abrufen von Paketen
    /// </para>
    /// <para>
    /// Eintragen von neuen Paketen
    /// </para>
    /// </summary>
    public class VersandService
    {
        #region Konstanten
        /// <summary>
        /// Dieser Zuschlag muss zum Gesamtpreis hinzugerechnet werden, wenn <see cref="Gebietszuschlag"/> True ist.
        /// </summary>
        public const decimal ZUSCHLAG = 25.65m;
        #endregion
        #region Eigenschaften und Felder
        private readonly OnlineMbe onlineMbe = new OnlineMbeClient();



        /// <summary>
        /// Die Credentials die wir für OnlineMBE brauchen, einmal für neutralen und normalen Versand
        /// </summary>
#if MBE_TESTACCOUNT
        public static CredentialsType MbeKarleyCredentials { get; } = new CredentialsType
        {
            Passphrase = "e7a2b2afe8517a0dc3037d3755236998",
            Username = "karley_test"
        };
#else
        public static CredentialsType MbeKarleyCredentials { get; } = new CredentialsType
        {
            Passphrase = "13c88b2d8217e2080e9f779110d606ed",
            Username = "karley@mbe0159"
        };
#endif
#if MBE_TESTACCOUNT
        // Damit der Testaccount Funktioniert, muss durch MBE eine Preisliste im Testaccount hinterlegt werden.
        public static CredentialsType MbeNeutralCredentials { get; } = new CredentialsType
        {
            Passphrase = "21f8f2f3d1ddf956878ebd39abc9a6d4",
            Username = "karley_neutral_test"
        };
#else
        public static CredentialsType MbeNeutralCredentials { get; } = new CredentialsType
        {
            Passphrase = "9f840f04d777c12aac6ab38e639a2924",
            Username = "kvzr@mbe0159"
        };
#endif

        /// <summary>
        /// Die StoreID gibt an welchen MBE Store wir nutzen. In unserem Fall ist das Zemelka (0159) und für den neutralen Versand ein Test Store (0998)
        /// </summary>
        /// 
#if MBE_TESTACCOUNT
        public static string MbeStoreID { get; } = "0998";
#else
        public static string MbeStoreID { get; } = "0159";
#endif

#if MBE_TESTACCOUNT
        public static string MbeStoreIDNeutral { get; } = "0998";
#else
        public static string MbeStoreIDNeutral { get; } = "0159";
#endif
        #endregion

        #region Pakete Erstellen, Label drucken und in W4 Eintragen
        /// <summary>
        /// Erstellt ein neues Versandetikett für eine RMA.
        /// </summary>
        /// <param name="rma"></param>
        /// <param name="pakete"></param>
        /// <param name="zumLieferanten"></param>
        /// <param name="versandOption"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public async Task<(bool erfolgreich, List<ShipmentResponseType> successResponses, List<AlertBox> alerts)> PaketeEintragenAsync(DruckRma rma, List<PaketInput> pakete, bool zumLieferanten, VersandOption versandOption, FbController2 fbController)
        {
            List<AlertBox> fehlermeldungen = new List<AlertBox>();
            if (versandOption.Versender == Courier.MANUAL)
            {
                throw new ArgumentException($"Der Versender darf nicht MANUAL sein.");
            }
            var lieferanschrift = rma.ToRecipientType(zumLieferanten);
            var product = new ProductType
            {
                SKUCode = rma.Artikelnummer,
                Description = $"{rma.ArtikelBezeichnung1} {rma.ArtikelBezeichnung2}",
                Quantity = rma.Menge
            };

            ShipmentRequestRequest shipmentRequest = new ShipmentRequestRequest()
            {
                RequestContainer = new ShipmentRequestType
                {
                    System = SystemType.DE,
                    InternalReferenceID = $"RMA-{rma.Id}",
                    Recipient = lieferanschrift,
                    Credentials = MbeKarleyCredentials
                }
            };

            shipmentRequest.RequestContainer.Shipment = new ShipmentType()
            {
                COD = false,
                Insurance = false,
                PackageType = ShipmentTypePackageType.GENERIC,
                LabelFormat = ShipmentTypeLabelFormat.OLD,
                Products = new ProductType[] { product },
                ShipperType = ShipmentTypeShipperType.COURIERLDV,
                Courier = versandOption.Versender.ToString(),
                CourierService = versandOption.Versandart.ToString(),
                Description = "Waren"
            };
            int erfolgreichEingetragen = 0;
            List<ShipmentResponseType> success = new List<ShipmentResponseType>();
            List<ShipmentRequestResponse> errors = new List<ShipmentRequestResponse>();

#if CREATE_MBE_ERROR
            // Simulieren von ungültigen Mbe Daten
            shipmentRequest.RequestContainer.Shipment.Courier = "DEBUG TEST COURIER DER NICHT EXISTIERT UND VIEL ZU LANG IST";
            shipmentRequest.RequestContainer.Shipment.CourierService = "DEBUG COURIERSERVICE DER NICHT EXITIERT";

#endif
            foreach (var paket in pakete)
            {
                shipmentRequest.RequestContainer.Shipment.Items = new ItemType[] { paket.ToItemType() };

                // Paket bei OnlineMbe eintragen
                try
                {
                    var response = await onlineMbe.ShipmentRequestAsync(shipmentRequest);
                    if (response.RequestContainer.Errors == null)
                    {
                        success.Add(response.RequestContainer);
#if !PRINT_NO_LABELS
                    PrintLabel(response.RequestContainer.Labels);
#endif

                        foreach (var trackingnummer in response.RequestContainer.TrackingsMBE)
                        {
                            string beschreibung = "Lieferung an Kunde";
                            if (zumLieferanten)
                            {
                                beschreibung = "Lieferung an Lieferant";
                            }

                            await PaketInW4EintragenAsync("RM", rma.Id, beschreibung, trackingnummer, lieferanschrift, paket.Gewicht);
                        }

                        erfolgreichEingetragen++;
                    }
                    else
                    {
                        errors.Add(response);
                    }

                }
                catch (Exception ex)
                {
                    errors.Add(new ShipmentRequestResponse
                    {
                        RequestContainer = new ShipmentResponseType
                        {
                            Errors = new ErrorType[] {
                                new ErrorType {
                                    Id = ex.HResult,
                                    Description = ex.Message
                                }
                            }
                        }
                    });
                }




            }

            // Fehlermails senden
            if (errors.Any())
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"Es ist ein Fehler beim eintragen der Pakete für die RMA-{rma.Id} aufgetreten. <br /><br />");
                sb.AppendLine($"{erfolgreichEingetragen} von {pakete.Count} Pakete wurden erfolgreich erstellt.<br /><br />");
                int zähler = 1;
                foreach (var paket in pakete)
                {
                    sb.AppendLine($"Paket {zähler++} Gewicht: {paket.Gewicht}<br />");
                }
                sb.AppendLine("<h4>Mögliche Gründe:</h4>");
                sb.AppendLine("<ol>");
                sb.AppendLine("<li>MBE war nicht erreichbar => Später nochmal probieren</li>");
                sb.AppendLine("<li>E-Mail-Adresse des Kunden ist falsch => Korrigieren und manuell die Trackingmail an den Kunden versenden</li>");
                sb.AppendLine("<li>Kein Internet => Später nochmal probieren</li>");
                sb.AppendLine("<li>Unbekannter Fehler beim Mailclient (HRESULT) => Wenn Pakete erstellt wurden, dann Trackingmail manuell nochmal versenden, ansonsten einfach nochmal Pakete eintragen</li>");
                sb.AppendLine("<li>Zu der Anschrift des Kunden ist eine Standard/Expresslieferung mit UPS nicht möglich => Manuell in online MBE die Adressdaten des Kunden eingeben und prüfen wo das Problem liegt. Im Zweifelsfall bei MBE anrufen.</li>");
                sb.AppendLine("</ol>");
                sb.AppendLine("<br /><br />");
                foreach (var error in errors)
                {
                    foreach (var mbeError in error.RequestContainer.Errors)
                    {
                        sb.AppendLine($"ID: {mbeError.Id} Description: {mbeError.Description}<br />");
                    }
                }

                await EmailController.FehlerMailSendenAsync(
                    betreff: "WK5_Blazor_VersandService - Fehler beim Eintragen der Pakete",
                    body: sb.ToString(),
                    empfänger: "software@karley.eu;info@karley.eu"
                );

                fehlermeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Fehler beim Eintragen der Pakete. Ein Fehlerbericht wurde an den Vertrieb gesendet. {erfolgreichEingetragen} von {pakete.Count} Pakete wurden erfolgreich erstellt.."
                });
                return (false, success, fehlermeldungen);
            }

            return (true, success, fehlermeldungen);

        }
        /// <summary>
        /// Trägt Pakete bei OnlineMbe ein.
        /// <para>
        /// Im Falle eines MbeFehlers wird automatisch eine Mail an software und info@karley.eu gesendet.
        /// </para>
        /// </summary>
        /// <param name="beleg"></param>
        /// <param name="lieferanschrift"></param>
        /// <param name="pakete"></param>
        /// <param name="versandOption"></param>
        /// <param name="personalNummer"></param>
        /// <returns>Ein Tuple mit zwei Werten.
        /// <para>bool erfolgreich gibt an, ob alle Pakete erfolgreich bei Mbe eingetragen wurden. Wurde nur ein Teil erfolgreich versendet, ist dieser Wert false.</para>
        /// <para>List<ShipmentResponseType> successResponses liefert alle responses von Mbe, für die erolfreich ein Paket eingetragen wurde.</para>
        /// </returns>
        public async Task<(bool erfolgreich, List<ShipmentResponseType> successResponses, List<AlertBox> alerts)> PaketeEintragen(Beleg beleg, RecipientType lieferanschrift, List<ItemType> pakete, VersandOption versandOption, int personalNummer)
        {
            List<AlertBox> fehlermeldungen = new List<AlertBox>();
            if (versandOption.Versender == Courier.MANUAL)
            {
                throw new ArgumentException($"Der Versender darf nicht MANUAL sein.");
            }

            List<ProductType> produkte = new List<ProductType>();
            foreach (var position in beleg.Positionen)
            {
                produkte.Add(new ProductType
                {
                    SKUCode = position.Artikelnummer,
                    Description = $"{position.Bezeichnung1} {position.Bezeichnung2}",
                    Quantity = position.Menge
                });
            }
            ShipmentRequestRequest shipmentRequest = new ShipmentRequestRequest()
            {
                RequestContainer = new ShipmentRequestType
                {
                    System = SystemType.DE,
                    InternalReferenceID = $"{beleg.Belegtyp}-{beleg.Belegnummer}",
                    Recipient = lieferanschrift,
                    Credentials = beleg.NeutralerVersender ? MbeNeutralCredentials : MbeKarleyCredentials
                }
            };



            shipmentRequest.RequestContainer.Shipment = new ShipmentType()
            {
                COD = false,
                Insurance = false,
                PackageType = ShipmentTypePackageType.GENERIC,
                LabelFormat = ShipmentTypeLabelFormat.OLD,
                Products = produkte.ToArray(),
                ShipperType = ShipmentTypeShipperType.COURIERLDV,
                Courier = versandOption.Versender.ToString(),
                CourierService = versandOption.Versandart.ToString(),
                Description = await GetVersandDescriptionAsync(beleg),
                Referring = $"{beleg.Belegtyp}-{beleg.Belegnummer}"
            };
            int erfolgreichEingetragen = 0;
            List<ShipmentResponseType> success = new List<ShipmentResponseType>();
            List<ShipmentRequestResponse> errors = new List<ShipmentRequestResponse>();
            // Wir tragen die Pakete einzeln ein, da mehrere Shipments für den selben Kunden billiger sind, als ein Shipment mit mehreren Paketen.
#if CREATE_MBE_ERROR
            // Simulieren von ungültigen Mbe Daten
            shipmentRequest.RequestContainer.Shipment.Courier = "DEBUG TEST COURIER DER NICHT EXISTIERT UND VIEL ZU LANG IST";
            shipmentRequest.RequestContainer.Shipment.CourierService = "DEBUG COURIERSERVICE DER NICHT EXITIERT";

#endif
            foreach (var paket in pakete)
            {

                shipmentRequest.RequestContainer.Shipment.Items = new ItemType[] { paket };

                // Paket bei OnlineMbe eintragen
                try
                {
                    var response = await onlineMbe.ShipmentRequestAsync(shipmentRequest);
                    if (response.RequestContainer.Errors == null)
                    {
                        success.Add(response.RequestContainer);
#if !PRINT_NO_LABELS
                    PrintLabel(response.RequestContainer.Labels);
#endif

                        await PaketInW4EintragenAsync(beleg, response.RequestContainer, lieferanschrift, paket.Weight);



                        erfolgreichEingetragen++;
                    }
                    else
                    {
                        errors.Add(response);
                    }

                }
                catch (Exception ex)
                {
                    errors.Add(new ShipmentRequestResponse
                    {
                        RequestContainer = new ShipmentResponseType
                        {
                            Errors = new ErrorType[] {
                                new ErrorType {
                                    Id = ex.HResult,
                                    Description = ex.Message
                                }
                            }
                        }
                    });
                }




            }

            _ = UpdateBelegShippingValue(beleg, lieferanschrift, pakete, versandOption);

            // Fehlermails senden
            if (errors.Any())
            {
                StringBuilder sb = new StringBuilder();
                StringBuilder errorBuilder = new();
                sb.AppendLine($"Es ist ein Fehler beim eintragen der Pakete für den Beleg {beleg.Belegtyp}-{beleg.Belegnummer} aufgetreten. Bitte die untenstehende Fehlermeldung prüfen und ggf. korrigieren. Dann Erneut probieren. <br /><br />");

                sb.AppendLine("<br /><br />");
                sb.AppendLine("<strong style='color: red;'>ACHTUNG! Der Kunde hat noch keine Rechnung per E-Mail erhalten!!!!</strong>");
                sb.AppendLine("<br /><br />");
                sb.AppendLine("<strong>ACHTUNG! Werden die Pakete manuell über OnlineMBE erstellt, dann sind diese noch über den manuellen Versand der WK5 einzutragen, damit der Kunde noch die Rechnung und die Sendungsnummer erhält und wir das im System nachvollziehen können.</strong>");
                sb.AppendLine("<br /><br />");

                foreach (var error in errors)
                {
                    foreach (var mbeError in error.RequestContainer.Errors)
                    {
                        sb.AppendLine($"ID: {mbeError.Id} Fehler: {mbeError.Description}<br />");
                        errorBuilder.AppendLine($"ID: {mbeError.Id} Fehler: {mbeError.Description}<br />");
                    }
                }
                sb.AppendLine("<br /><br />");

                int zähler = 1;
                foreach (var paket in pakete)
                {
                    sb.AppendLine($"Paket {zähler++} Gewicht: {paket.Weight}<br />");
                }

                sb.AppendLine("<h4>Mögliche Gründe:</h4>");
                sb.AppendLine("<ol>");
                sb.AppendLine("<li>MBE war nicht erreichbar => Später nochmal probieren</li>");
                sb.AppendLine("<li>E-Mail-Adresse des Kunden ist falsch => Korrigieren und manuell die Trackingmail an den Kunden versenden</li>");
                sb.AppendLine("<li>Kein Internet => Später nochmal probieren</li>");
                sb.AppendLine("<li>Unbekannter Fehler beim Mailclient (HRESULT) => Wenn Pakete erstellt wurden, dann Trackingmail manuell nochmal versenden, ansonsten einfach nochmal Pakete eintragen</li>");
                sb.AppendLine("<li>Zu der Anschrift des Kunden ist eine Standard/Expresslieferung mit UPS nicht möglich => Manuell in online MBE die Adressdaten des Kunden eingeben und prüfen wo das Problem liegt. Im Zweifelsfall bei MBE anrufen.</li>");
                sb.AppendLine("</ol>");



                await EmailController.FehlerMailSendenAsync(
                    betreff: "WK5_Blazor_VersandService - Fehler beim Eintragen der Pakete",
                    body: sb.ToString(),
                    empfänger: "software@karley.eu;info@karley.eu"
                );

                fehlermeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Fehler beim Eintragen der Pakete:<br /><br />{errorBuilder}<br /><br />Es wurde ein Fehlerbericht an den Vertrieb gesendet."
                });

                return (false, success, fehlermeldungen);
            }

            return (true, success, fehlermeldungen);
        }
        /// <summary>
        /// Erstellt ein neues Versandetikett ohne einen Beleg als Zuordnung.
        /// </summary>
        /// <param name="account"></param>
        /// <param name="zuordnungsTyp"></param>
        /// <param name="zuordnungsnummer"></param>
        /// <param name="lieferanschrift"></param>
        /// <param name="shipment"></param>
        /// <param name="pakete"></param>
        /// <param name="personalNummer"></param>
        /// <returns></returns>
        public async Task<(bool erfolgreich, List<ShipmentResponseType> successResponses, List<AlertBox> alerts)> PaketOhneBeleg(MbeVersandAccount account, VersandZuordnungsTyp zuordnungsTyp, int zuordnungsnummer, RecipientType lieferanschrift, ShipmentType shipment, List<ItemType> pakete, int personalNummer)
        {
            List<AlertBox> fehlermeldungen = new List<AlertBox>();
            string paketTyp = "KU";

            if (zuordnungsTyp == VersandZuordnungsTyp.Lieferant)
            {
                paketTyp = "LI";
            }

            ShipmentRequestRequest shipmentRequest = new ShipmentRequestRequest
            {
                RequestContainer = new ShipmentRequestType
                {
                    System = SystemType.DE,
                    Credentials = account == MbeVersandAccount.NormalerAccount ? MbeKarleyCredentials : MbeNeutralCredentials,
                    InternalReferenceID = "Versand ohne Beleg",
                    Recipient = lieferanschrift,
                    Shipment = shipment
                }
            };
            int erfolgreichEingetragen = 0;
            List<ShipmentResponseType> success = new List<ShipmentResponseType>();
            List<ShipmentRequestResponse> errors = new List<ShipmentRequestResponse>();
            foreach (var paket in pakete)
            {
                shipmentRequest.RequestContainer.Shipment.Items = new ItemType[] { paket };
                // Paket bei OnlineMbe eintragen
                try
                {
                    var response = await onlineMbe.ShipmentRequestAsync(shipmentRequest);
                    if (response.RequestContainer.Errors == null)
                    {
                        success.Add(response.RequestContainer);
#if !PRINT_NO_LABELS
                    PrintLabel(response.RequestContainer.Labels);
#endif

                        await PaketInW4EintragenAsync(paketTyp, zuordnungsnummer, shipment.Description, response.RequestContainer.CourierMasterTrk, lieferanschrift, paket.Weight);

                        erfolgreichEingetragen++;
                    }
                    else
                    {
                        errors.Add(response);
                    }

                }
                catch (Exception ex)
                {
                    errors.Add(new ShipmentRequestResponse
                    {
                        RequestContainer = new ShipmentResponseType
                        {
                            Errors = new ErrorType[] {
                                new ErrorType {
                                    Id = ex.HResult,
                                    Description = ex.Message
                                }
                            }
                        }
                    });
                }
            }

            // Fehlermails senden
            if (errors.Any())
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"Es ist ein Fehler beim eintragen der Pakete für {paketTyp}-{zuordnungsnummer} aufgetreten. <br /><br />");
                sb.AppendLine($"{erfolgreichEingetragen} von {pakete.Count} Pakete wurden erfolgreich erstellt.<br /><br />");
                foreach (var error in errors)
                {
                    foreach (var mbeError in error.RequestContainer.Errors)
                    {
                        sb.AppendLine($"ID: {mbeError.Id} Description: {mbeError.Description}<br />");
                    }
                }

                await EmailController.FehlerMailSendenAsync(
                    betreff: "WK5_Blazor_VersandService - Fehler beim Eintragen der Pakete",
                    body: sb.ToString(),
                    empfänger: "software@karley.eu;info@karley.eu"
                );

                fehlermeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Fehler beim Eintragen der Pakete. Ein Fehlerbericht wurde an den Vertrieb gesendet. {erfolgreichEingetragen} von {pakete.Count} Pakete wurden erfolgreich erstellt.."
                });
                return (false, success, fehlermeldungen);
            }

            return (true, success, fehlermeldungen);
        }
        /// <summary>
        /// Trägt die Paketdaten in die WK5 ein.
        /// </summary>
        /// <param name="beleg"></param>
        /// <param name="response"></param>
        /// <param name="emp"></param>
        /// <param name="paketGewicht"></param>
        /// <returns></returns>
        private async Task PaketInW4EintragenAsync(Beleg beleg, ShipmentResponseType response, RecipientType emp, decimal paketGewicht)
        {
            foreach (var trackingnummer in response.TrackingsMBE)
            {
                await PaketInW4EintragenAsync(beleg, trackingnummer, emp, paketGewicht);

                if (beleg.RmaNummerVerknüpfung > 0)
                {
                    string beschreibung = "Lieferung an Kunde";
                    await PaketInW4EintragenAsync("RM", beleg.RmaNummerVerknüpfung, beschreibung, trackingnummer, emp, paketGewicht);
                }
            }
        }

        public async Task PaketInW4EintragenAsync(Beleg beleg, string trackingnummer, RecipientType emp, decimal paketGewicht)
        {
            W4Paket paket = new W4Paket
            {
                PAKE_A_NR = trackingnummer,
                PAKE_A_KUNDNR = beleg.Kundennummer,
                PAKE_T_DATUM = DateTime.Now,
                PAKE_N_BELENR = beleg.Belegnummer,
                PAKE_N_LFDNR = await W4Paket.GetNeuePaketNummerAsync(beleg.Belegtyp, beleg.Belegnummer),
                PAKE_A_TYP = beleg.Belegtyp,
                PAKE_L_LS = true,
                PAKE_N_VERSENDER = 1,
                PAKE_N_WERT = beleg.GetTrueVk(),
                PAKE_N_GEWICHT = paketGewicht,
                PAKE_L_VERSENDET = true,
                PAKE_N_EXPRESSART = beleg.LieferbedingungId,
                PAKE_L_SAMSTAG = false,
                PAKE_A_EMP_NAME1 = emp.CompanyName,
                PAKE_A_EMP_NAME2 = emp.Name,
                PAKE_A_EMP_NAME3 = emp.Nickname ?? "",
                PAKE_A_EMP_STR = emp.Address,
                PAKE_A_EMP_LAND = emp.Country,
                PAKE_A_EMP_PLZ = emp.ZipCode,
                PAKE_A_EMP_ORT = emp.City,
                PAKE_A_ABS_NAME1 = "WK5 Mbe Api"
            };

            await W4Paket.InsertPaketAsync(paket);

            if (beleg.RmaNummerVerknüpfung > 0)
            {
                await PaketInW4EintragenAsync("RM", beleg.RmaNummerVerknüpfung, "Lieferung an Kunde", trackingnummer, emp, paketGewicht);
            }
        }
        public async Task PaketInW4EintragenAsync(string zuordnungsTyp, int zuordnungsnummer, string beschreibung, string trackingnummer, RecipientType emp, decimal paketGewicht)
        {
            W4Paket paket = new W4Paket
            {
                PAKE_A_NOTIZ = beschreibung,
                PAKE_A_TYP = zuordnungsTyp,
                PAKE_D_VERSANDDATE = DateTime.Now,
                PAKE_A_KUNDNR = zuordnungsTyp != "RM" ? zuordnungsnummer.ToString() : string.Empty,
                PAKE_N_GEWICHT = paketGewicht,
                PAKE_L_VERSENDET = true,
                PAKE_A_EMP_LAND = emp.Country,
                PAKE_A_EMP_NAME1 = emp.Name,
                PAKE_A_EMP_NAME2 = emp.CompanyName,
                PAKE_A_EMP_NAME3 = emp.Nickname,
                PAKE_A_EMP_ORT = emp.City,
                PAKE_A_EMP_PLZ = emp.ZipCode,
                PAKE_A_EMP_STR = $"{emp.Address};{emp.Address2};{emp.Address3}",
                PAKE_L_LS = false,
                PAKE_A_ABS_NAME1 = "WK5 MBE Api (Versand ohne Beleg)",
                PAKE_A_NR = trackingnummer,
                PAKE_TIMESTAMP = DateTime.Now,
                PAKE_T_DATUM = DateTime.Now,
                PAKE_N_BELENR = zuordnungsTyp == "RM" ? zuordnungsnummer : 0
            };

            await W4Paket.InsertPaketAsync(paket);
        }
        private void PrintLabel(LabelType[] labels)
        {
            foreach (var label in labels)
            {
                Printer.PrintLabel(label);
            }
        }
        #endregion
        #region Hilfsmethoden
        /// <summary>
        /// Holt die Beschreibung für die Sendung anhand der Belegpositionen.
        /// </summary>
        /// <param name="beleg"></param>
        /// <returns></returns>
        private async Task<string?> GetVersandDescriptionAsync(Beleg beleg)
        {

            if (beleg.Land.Equals("DE"))
            {
                return "Waren";
            }
            // Wir speichern uns nur unterschiedliche Beschreibungen, da der Platz auf dem Label auf 99 Zeichen begrenzt ist
            List<string> beschreibungen = new List<string>();

            foreach (var position in beleg.Positionen)
            {
                Zolltarif? zolltarif = await Zolltarif.GetZolltarifAsync(position.ARTI_N_ZOLLTARIF);


                if (zolltarif != null && !String.IsNullOrWhiteSpace(zolltarif.ZOTA_A_REFERENZ))
                {
                    beschreibungen.Add(zolltarif.ZOTA_A_REFERENZ);
                }
                else
                {
                    beschreibungen.Add(position.Bezeichnung1);
                }
            }

            StringBuilder sb = new StringBuilder();
            foreach (var beschreibung in beschreibungen.Distinct<string>())
            {
                sb.Append(beschreibung);
                sb.Append(",");
            }

            if (sb.Length > 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }

            return StringErweiterung.MaxLength(sb.ToString(), 99);
        }
        #endregion
        #region Pakete Abfragen
        public async IAsyncEnumerable<VersandKombi?> GetVersendetePaketeAsync(VersandFilter filter, bool neutralerAccount = false)
        {
            CredentialsType credentials = neutralerAccount ? MbeNeutralCredentials : MbeKarleyCredentials;

            ShipmentsListRequestRequest request = new ShipmentsListRequestRequest
            {
                RequestContainer = new ShipmentsListRequestType
                {
                    System = SystemType.DE,
                    Credentials = credentials,
                    InternalReferenceID = "",
                    DateFrom = filter.From.Date,
                    DateFromSpecified = true,
                    DateTo = filter.To.Date,
                    DateToSpecified = true,
                    StoreID = neutralerAccount ? MbeStoreIDNeutral : MbeStoreID
                }
            };

            var response = await onlineMbe.ShipmentsListRequestAsync(request);

            if (response is null)
            {
                yield return null;
            }
            else
            {

                foreach (var shipment in response.RequestContainer.ShipmentsFullInfo)
                {
                    if (shipment is null || (shipment.ReceiverInfo is null && shipment.ShipmentInfo is null && shipment.TrackingInfo is null))
                    {
                        continue;
                    }

                    W4Paket? paket = await W4Paket.GetPaketByTrackingnummerAsync(shipment.TrackingInfo!.CourierMasterTrk);

                    yield return new VersandKombi(shipment, paket, neutralerAccount);
                }
            }
        }
        #endregion
        #region Pakete löschen
        public async Task<DeleteShipmentsRequestResponse> PaketLöschen(VersandKombi versanddetails)
        {
            DeleteShipmentsRequestRequest request = new DeleteShipmentsRequestRequest
            {
                RequestContainer = new DeleteShipmentsRequestType
                {
                    SystemType = SystemType.DE,
                    Credentials = versanddetails.IstNeutralerAccount ? MbeNeutralCredentials : MbeKarleyCredentials,
                    InternalReferenceID = "",
                    MasterTrackingsMBE = new string[] { versanddetails.ShipmentFullInfo.TrackingInfo.MasterTrackingMBE }
                }
            };

            return await onlineMbe.DeleteShipmentsRequestAsync(request);
        }
        #endregion
        #region Preise Abfragen
        /// <summary>
        /// Forder die Preise für eine Sendung von OnlineMbe an.
        /// <para>
        /// Eventuelle Preiszuschläge sind nicht mit inbegriffen und müssen manuell noch draufgeschlagen werden.
        /// </para>
        /// </summary>
        /// <param name="destionationInfo"></param>
        /// <param name="pakete"></param>
        /// <returns>
        /// Gibt eine Liste mit der <see cref="ShippingOptionsRequestResponse"/> von MBE zurück. Anhand der InternalReferenceID kann die Antwort dem entsprechenden Paket zugeordnet werden.
        /// </returns>
        public async Task<ShippingOptionsRequestResponse> GetShippingOptionsAsync(DestinationInfoType destionationInfo, ItemType paket, string internalReferenceId)
        {
            ShippingOptionsRequestRequest request = new ShippingOptionsRequestRequest
            {
                RequestContainer = new ShippingOptionsRequestType
                {
                    Credentials = MbeKarleyCredentials,
                    InternalReferenceID = internalReferenceId,
                    ShippingParameters = new ShippingParametersType
                    {
                        ShipType = ShippingParametersTypeShipType.EXPORT,
                        DestinationInfo = destionationInfo,
                        PackageType = ShippingParametersTypePackageType.GENERIC,
                        Items = new ItemType[] { paket }
                    }
                }
            };

            return await onlineMbe.ShippingOptionsRequestAsync(request);
        }
        /// <summary>
        /// Prüft, ob der Gewichtsberechner für einen Beleg noch einen Gebietszuschlag aufschlagen muss.
        /// </summary>
        /// <returns></returns>
        public async Task<bool> BrauchtGebietszuschlagZuschlagAsync(string land, string postleitzahl)
        {

            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@PLZ", postleitzahl);
            fbController.AddParameter("@LAND", land);
            var row = await fbController.SelectRowAsync("SELECT * FROM WK5_AUSSENGEBIETE WHERE AUS_A_PLZ = @PLZ AND AUS_A_LAND = @LAND");
            return row is not null;
        }

        public decimal GetNotfallAufschlag(string land, decimal gewicht)
        {
            if (land == "DE")
            {
                return 0;
            }

            int weight = (int)Math.Ceiling(gewicht);
            decimal wert = 0.90m + (decimal)(weight * 0.22);
            return wert;
        }
        /// <summary>
        /// Berechnet auf Basis des EKs den VK für die WK5 in Staffelmengen. 
        /// </summary>
        /// <param name="ek"></param>
        /// <returns></returns>
        public decimal GetVkForEk(decimal ek)
        {
            // Wir teilen 1 cent unter dem VK Preis, damit volle Bteräge nicht mit + 1 berechnet werden
            int tmp = (int)((ek / 7.99m) + 1);
            return 8.0m * tmp;
        }
        /// <summary>
        /// Ruft alle verfügbaren Versandoptionen von MBE via API ab.
        /// </summary>
        /// <param name="pakete"></param>
        /// <param name="anschrift"></param>
        /// <param name="belegwert"></param>
        /// <param name="länder"></param>
        /// <param name="jsRuntime"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public async Task<Dictionary<string, decimal>> GetShippingOptionsAsync(List<PaketInput> pakete, GewichtsberechnerDestinationInfoInput anschrift, decimal belegwert, List<Land> länder, IJSRuntime? jsRuntime = null)
        {
            Dictionary<string, decimal> shippingOptions = new Dictionary<string, decimal>();
            foreach (var paket in pakete)
            {

                var result = await GetShippingOptionsAsync(anschrift.ToDestinationInfoType(), paket.ToItemType(), paket.Paketnummer.ToString());
                if (result.RequestContainer.Errors == null)
                {
                    if (result.RequestContainer.ShippingOptions is null)
                    {

                        shippingOptions.Clear();
                        throw new InvalidOperationException("Versandkosten konnten nicht ermittelt werden");
                    }
                    foreach (var mbeResponse in result.RequestContainer.ShippingOptions)
                    {
                        if (mbeResponse.CourierService.Equals("UST", StringComparison.OrdinalIgnoreCase) ||
                              mbeResponse.CourierService.Equals("USA", StringComparison.OrdinalIgnoreCase) ||
                              mbeResponse.CourierService.Equals("USO", StringComparison.OrdinalIgnoreCase))
                        {
                            var key = $"{mbeResponse.Courier} {mbeResponse.CourierServiceDesc}";
                            var preis = mbeResponse.NetShipmentTotalPrice + GetNotfallAufschlag(anschrift.Country, paket.Gewicht);
                            if (await BrauchtGebietszuschlagZuschlagAsync(anschrift.Country, anschrift.ZipCode))
                            {
                                preis += ZUSCHLAG;
                            }

                            // 13.04.2021 - MK: Wir schlagen immer 15% auf die Preise drauf, da Treibstoffkosten und Verpackungsmaterial auch berücksichtigt werden soll.
                            // 01.07.2022 - Scholz: Bomski hat festgestellt, das sich die Aufschläge bei UPS verändert haben.
                            // Bomski hat mit MBE gesprochen, auf normale Pakete müssen wir 16% Aufschlag zahlen
                            // auf Express Pakete 39,5%.

                            //05.07.2022 - Scholz: Bomski hat mit MBE gesprochen und wir behalten die 5% die wir ursprünglich bei Standard hatten statt der 16%
                            if (mbeResponse.CourierService.Equals(CourierArt.UST.ToString(), StringComparison.OrdinalIgnoreCase))
                            {
                                preis *= 1.05m;
                            }
                            else if (mbeResponse.CourierService.Equals(CourierArt.USA.ToString(), StringComparison.OrdinalIgnoreCase) ||
                                mbeResponse.CourierService.Equals(CourierArt.USO.ToString(), StringComparison.OrdinalIgnoreCase))
                            {
                                preis *= 1.395m;
                            }

                            if (länder.Any(x => !x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == anschrift.Country) && anschrift.Country != "DE" && belegwert >= 1000)
                            {
                                preis += 30m;
                            }

                            // Nur gerundete Preise sind korrekt
                            preis = Math.Round(preis, 2);

                            if (shippingOptions.ContainsKey(key))
                            {
                                shippingOptions[key] += preis;
                            }
                            else
                            {
                                shippingOptions.Add(key, preis);
                            }
                        }
                    }


                }
                else
                {

                    foreach (var error in result.RequestContainer.Errors)
                    {
                        string fehlermeldung = $"#WK5_GEWICHTSBERECHNER_PREISABFRAGE - Fehler beim Abfragen der Preise. Fehlermeldung: {error.Description}";
                        Serilog.Log.Logger.Error($"#WK5_GEWICHTSBERECHNER_PREISABFRAGE - Fehler beim Abfragen der Preise. Fehlermeldung: {error.Description}");
                        if (jsRuntime is not null)
                        {
                            await jsRuntime.ShowToast(ToastType.error, fehlermeldung, 7000);
                        }
                    }

                }
            }

            return shippingOptions;
        }
        /// <summary>
        /// Aktualisiert den EK des Versandes im Beleg auf den realen EK.
        /// </summary>
        /// <param name="beleg"></param>
        /// <param name="lieferanschrift"></param>
        /// <param name="pakete"></param>
        /// <param name="versandOption"></param>
        /// <returns></returns>
        public async Task UpdateBelegShippingValue(Beleg beleg, RecipientType lieferanschrift, List<ItemType> pakete, VersandOption versandOption)
        {
            DestinationInfoType destination = new DestinationInfoType
            {
                City = lieferanschrift.City,
                Country = lieferanschrift.Country,
                ZipCode = lieferanschrift.ZipCode,
                idSubzone = lieferanschrift.SubzoneId
            };

            ShippingOptionsRequestRequest request = new ShippingOptionsRequestRequest
            {
                RequestContainer = new ShippingOptionsRequestType
                {
                    Credentials = MbeKarleyCredentials,
                    InternalReferenceID = "",
                    ShippingParameters = new ShippingParametersType
                    {
                        ShipType = ShippingParametersTypeShipType.EXPORT,
                        DestinationInfo = destination,
                        PackageType = ShippingParametersTypePackageType.GENERIC
                    }
                }
            };

            decimal value = 0.0m;
            foreach (ItemType paket in pakete)
            {
                request.RequestContainer.ShippingParameters.Items = new ItemType[] { paket };

                ShippingOptionsRequestResponse res = await onlineMbe.ShippingOptionsRequestAsync(request);
                if (res.RequestContainer.Errors == null)
                {
                    if (res.RequestContainer.ShippingOptions is not null)
                    {
                        foreach (ShippingOptionType resp in res.RequestContainer.ShippingOptions)
                        {
                            if (resp.CourierService.Equals(versandOption.Versandart.ToString(), StringComparison.OrdinalIgnoreCase))
                            {
                                decimal preis = resp.NetShipmentTotalPrice + GetNotfallAufschlag(lieferanschrift.Country, paket.Weight);
                                if (await BrauchtGebietszuschlagZuschlagAsync(lieferanschrift.Country, lieferanschrift.ZipCode))
                                {
                                    preis += ZUSCHLAG;
                                }
                                value += preis;
                            }
                        }
                    }
                    else
                    {

                    }
                }
            }

            if (value > 0.0m)
            {
                BelegService belegService = new BelegService();
                using FbController2 fbController = new FbController2(2);

                await belegService.UpdateBelegVersandEK(EnumHelper.GetBelegTyp(beleg.Belegtyp), beleg.Belegnummer, value, fbController);
            }
        }

        #endregion


    }
}
