#if DEBUG
//#define PREVENT_CHANGES
//#define TEST_BUCHUNG // Zum testen der Transaction werden Daten direkt geschrieben, damit man beim Debuggen Änderungen an der Datenbank nachvollziehen kann
#define NICHT_INS_ARCHIV
#endif
using KarleyLibrary.Erweiterungen;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
using PDFtoPrinter;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Drucken.Erstkundenbrief;
using WK5.Core.Drucken.Lieferscheine;
using WK5.Core.Drucken.Rechnungen;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Models.Tools.Lagerregal;
using WK5.Core.Models.Versand;
using WK5.Core.PageModels.Lagerregal;
using WK5.Core.Validators.Lagerregal;
using WK5_Blazor.Components.Modals;

namespace WK5_Blazor.Pages.Lagerregal
{
    public partial class AuftragsUebersicht
    {
        [Parameter] public int Belegnummer { get; set; }
#nullable disable
        [CascadingParameter] public AppMitarbeiter Mitarbeiter { get; set; } 
#nullable enable
        public PackAuftrag? Auftrag { get; private set; }
        private Werbemittel? Werbemittel { get; set; }
        public Lieferbedingung? Lieferbedingung { get; set; }
        public string EingabeArtikelnummer { get; set; } = String.Empty;
        public int PhotoAmount { get; set; } = 0;
        public string BuchenBtnText { get; set; } = "Teillieferung";
        private List<AlertBox> _warnmeldungen = new List<AlertBox>();
        private Pipeline<PackAuftrag?> AbschließenPipeline { get; set; } = new Pipeline<PackAuftrag?>();
        public FreigabeEntfernenInput FreigabeEntfernenInput { get; set; } = new FreigabeEntfernenInput();

        private FreigabeEntfernenInputValidator _freigabeEntfernenValidator = new FreigabeEntfernenInputValidator();


        private bool _showFreigabeEntfernenModal;
        private bool _showKundendetailsModal;
        private bool _showPausierenModal;
        private bool _showWerbemittelModal;
        private bool _showPacktextModal;
        private bool _showPhotoModal;
        private bool _photoIsSaving;
        private bool sperrBuchenButton;
        private bool _showBuchungenLöschenModal;
#nullable disable
        private VersandModal versandModal;
#nullable enable

        protected override async Task OnParametersSetAsync()
        {

            using FbController2 fbController = new FbController2();
            Auftrag = await PackAuftrag.GetPackAuftragAsync(Belegnummer, fbController);
            Werbemittel = await werbemittelService.GetWerbemittel(Auftrag);
            Lieferbedingung = Program.AppDaten.Lieferbedingungen.FirstOrDefault(x => x.LIBD_N_NR == Auftrag?.LieferbedingungId);


            if (Auftrag?.BuchenIstMöglich == true)
            {
                BuchenBtnText = "Buchen";
            }
            SetWarnmeldungen();

            await SetupAbschließenPipeline();

            if (Auftrag is not null)
            {
                _showPacktextModal = !string.IsNullOrWhiteSpace(Auftrag.GetPacktext());
                foreach (var pos in Auftrag.GetEndPositionen().Where(x => GlobalConfig.AutomatischBuchen.Contains(x.Artikelnummer)))
                {
                    decimal zuBuchen = pos.Menge - pos.BPOS_N_MENGEGELIEF - pos.BEREITS_GEBUCHT;
                    if (zuBuchen > 0)
                    {
                        BuchungResponse response = await buchenService.BuchenAsync(pos, zuBuchen, pos.Artikelnummer, null, fbController);
                        if (response.Success)
                        {
                            BuchenBtnText = Auftrag.BuchenIstMöglich ? "Buchen" : "Teillieferung";
                            await jsRuntime.InvokeVoidAsync("showToast", "success", $"Artikel {pos.Artikelnummer} wurde automatisch gebucht.", 1500);
                        }
                    }
                }

                if (!Directory.Exists(GlobalConfig.Configuration.PackbilderPfad))
                {
                    var result = FileErweiterung.EnsureCreateDirectory(GlobalConfig.Configuration.PackbilderPfad);

                    if (!result.success)
                    {
                        //Pfad nicht erstellbar handlen
                    }
                }
                PhotoAmount = Directory.GetFiles(GlobalConfig.Configuration.PackbilderPfad, $"{Auftrag.Belegtyp}-{Auftrag.Belegnummer}*").Length;
            }

            if (!_isDisposed)
            {
                await CheckActivePageAsync();
            }

        }
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (!firstRender)
            {
                await navigationManager.NavigateToFragmentAsync(jsRuntime);
                await jsRuntime.FocusByIdAsync("generelle-eingabe");
            }
        }
        private async Task SetupAbschließenPipeline()
        {
            await AbschließenPipeline.HardReset();
            AbschließenPipeline.Add((packAuftrag) =>
            {
                if (packAuftrag is null)
                {
                    return false;
                }

                if (!packAuftrag.NeutralerVersender && Werbemittel is not null)
                {
                    _showWerbemittelModal = true;
                    return false;
                }
                else
                {
                    return true;
                }
            });

            AbschließenPipeline.Add((packAuftrag) =>
            {
                if (packAuftrag is null)
                {
                    return false;
                }

                _showPhotoModal = true;
                return false;
            });




            AbschließenPipeline.Add(async (packAuftrag) =>
            {
                await Buchen();

                return true;
            });
        }
        private async Task Buchen()
        {
            if (Auftrag is null)
            {
                return;
            }

            sperrBuchenButton = true;


            try
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
#if !TEST_BUCHUNG
                await fbController.StartTransactionAsync();
#endif
                PackLieferschein lieferschein = await Auftrag.ÜbernahmeInLieferscheinAsync(fbController, Program.AppDaten.Optionen, belegService);
                await lieferschein.ChargenAsync(fbController, Mitarbeiter);

                // Werbung eintragen
                if (!Auftrag.NeutralerVersender)
                {
                    var werbung = await werbemittelService.GetWerbemittel(Auftrag);
                    // Es kann sein, dass ein Kunde bereits alle möglichen Werbungen erhalten hat.
                    if (werbung is not null)
                    {
                        fbController.AddParameter("@INP_A_WERBEMITTEL", werbung.Name);
                        fbController.AddParameter("@INP_A_KUNDENNR", Auftrag.Kundennummer);
                        await fbController.RunProcedureAsync("WK5_PROZ_KUNDENWERBUNG");
                    }
                }

                Rechnung? rechnung = null;
                Lieferbedingung? lieferbedingung = Program.AppDaten.Lieferbedingungen.FirstOrDefault(x => x.LIBD_N_NR == Auftrag.LieferbedingungId);
                if (lieferbedingung is null)
                {
                    throw new NullReferenceException(nameof(lieferbedingung));
                }



                if (!Auftrag.WK5_BELE_L_SAMMELRECHNUNG && !Auftrag.OhneBerechnung && !lieferbedingung.LIBD_L_ABHOLUNG)
                {
                    rechnung = await lieferschein.ÜbernahmeInRechnungAsync(fbController, Program.AppDaten.Optionen, belegService);
                }

                await lagerregalService.InsertGepacktAsync(Auftrag, lieferschein, rechnung, fbController);

#if !TEST_BUCHUNG
#if !PREVENT_CHANGES
                await fbController.CommitChangesAsync();
#else
                await fbController.RollbackChangesAsync();
#endif
#endif

                if (lieferbedingung.LIBD_L_ABHOLUNG)
                {
                    await ÜberAbholungInformierenAsync(lieferschein);
                }

                // Wenn es die erste Rechnung für den Kunden ist, dann den Erstkunden-Brief generieren
                string printerName = GlobalConfig.GetDocumentPrinterLager();

                if (await Kunde.IstErstkundeAsync(Auftrag.Kundennummer))
                {
                    PrintErstkundenbrief erstkundenBrief = await PrintErstkundenbrief.CreateAsync(Auftrag);
                    string filenameErstkundenbrief = erstkundenBrief.Print(GlobalConfig.Configuration.OutputPfad);
                    await Printer.PrintAsync(filenameErstkundenbrief, printerName);
                }

                // Bei neutralen Sendungen kommt kein Lieferschein dazu.
                if (lieferschein.NeutralerVersender && lieferschein.NeutralerLieferschein.Length > 0)
                {
                    string filenameNeutralerLieferschein = Path.Combine(GlobalConfig.Configuration.OutputPfad, $"LS_{lieferschein.Belegnummer}.pdf");
                    await File.WriteAllBytesAsync(filenameNeutralerLieferschein, lieferschein.NeutralerLieferschein);
                    await Printer.PrintAsync(filenameNeutralerLieferschein, printerName);
                }
                else
                {
                    Lieferschein druckLieferschein = await Lieferschein.GetLieferscheinAsync(lieferschein.Belegnummer, fbController) ?? throw new ArgumentNullException(nameof(druckLieferschein));
                    PrintLieferschein printLieferschein = await PrintLieferschein.CreateAsync(druckLieferschein, new PrintLieferscheinRegelsatz { ShowHeader = !lieferschein.NeutralerVersender, ShowFooter = !lieferschein.NeutralerVersender });
                    string filenameLieferschein = printLieferschein.Print(GlobalConfig.Configuration.OutputPfad);
                    await Printer.PrintAsync(filenameLieferschein, printerName);
                }

                if (rechnung != null)
                {
                    versandModal.SetBeleg(rechnung, Auftrag.BELE_A_STATUSFELD == "Teillief.", Auftrag.Bestellnummer);

                    PrintRechnung printRechnung = await PrintRechnung.CreateAsync(rechnung, new PrintRechnungRegelsatz { ShowHeader = true, ShowFooter = true }, fbController);
                    string filenameRechnungPdf = printRechnung.Print(GlobalConfig.Configuration.OutputPfad);


                    // Wir brauchen das noch auf unseren Export pfad
#if !NICHT_INS_ARCHIV
                    string archivpfad = await GlobalConfig.GetConfigAsync(GlobalConfig.WK5_ARCHIVPFAD_CONFIG_NAME, fbController);
                    File.Copy(filenameRechnungPdf, Path.Combine(archivpfad, Path.GetFileName(filenameRechnungPdf)), true);
#endif

                    string lieferland = rechnung.Land;
                    Lieferanschrift? lieferanschrift = await Lieferanschrift.GetLieferanschriftAsync(rechnung.Kundennummer, rechnung.LieferanschriftId);
                    if (lieferanschrift is not null && lieferanschrift.KULA_A_LAND is not null)
                    {
                        lieferland = lieferanschrift.KULA_A_LAND;
                    }


                    if (Program.AppDaten.Länder.Where(x => !x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == lieferland).Any())
                    {
                        for (int i = 0; i < 3; i++)
                        {
                            await Printer.PrintAsync(filenameRechnungPdf, printerName);
                        }
                    }

                    //Wenn der Kunde abholt, brauchen wir keine Versand Modal o.ä.
                    if (rechnung.IstAbholung || Auftrag.ÜberAbholungInformiert)
                    {
                        await Printer.PrintAsync(filenameRechnungPdf, printerName);
                    }



                }
                else
                {
                    versandModal.SetBeleg(lieferschein, Auftrag.BELE_A_STATUSFELD == "Teillief.", Auftrag.Bestellnummer);
                }

                string message = $"Lieferschein {lieferschein.Belegnummer} wurde erfolgreich erstellt.";

                if (Auftrag.WK5_BELE_L_SAMMELRECHNUNG)
                {
                    message = $"Lieferschein {lieferschein.Belegnummer} wurde erfolgreich erstellt. Der Beleg soll als Sammelrechnung versendet werden!";
                }

                if (Auftrag.OhneBerechnung)
                {
                    message = $"Lieferschein {lieferschein.Belegnummer} wurde erfolgreich erstellt. Für den Auftrag soll keine Rechnung erstellt werden.";
                }

                if (rechnung is not null)
                {
                    message = $"Lieferschein {lieferschein.Belegnummer} und Rechnung {rechnung!.Belegnummer} wurden erfolgreich erstellt.";
                }

                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Success,
                    Message = message
                });

                Beleg mailBeleg = rechnung is not null ? rechnung : lieferschein;
                VersandMailer mailer = await VersandMailer.CreateAsync(mailBeleg, new List<string>(), new VersandOption(mailBeleg), Mitarbeiter.PersonalNummer, fbController);

                if (lieferschein.IstVersandPalette)
                {
                    string body = @$"Der Beleg {mailBeleg.Belegtyp}-{mailBeleg.Belegnummer} wird per Palette versendet.<br/>Bitte alles fertig machen und dem Kunden bescheid geben!";
                    await EmailController.FehlerMailSendenAsync("Auftrag wird über Palette versendet", body, "info@karley.eu");
                    await AddAlertAsync(new AlertBox { AlertType = AlertType.Info, Message = "Der Auftrag wird per Palette versendet!" });
                    navigationManager.NavigateTo("/Lagerregal");
                }
                else if (lieferschein.IstVersandBrief)
                {
                    var responses = await mailer.EmailSendenAsync();
                    await AddAlertAsync(new AlertBox { AlertType = AlertType.Info, Message = "Der Auftrag wird per Brief versendet! Kein Label notwendig!" });
                    navigationManager.NavigateTo("/Lagerregal");
                }
                else if (lieferschein.IstAbholung)
                {
                    navigationManager.NavigateTo("/Lagerregal");
                }
                else
                {
                    versandModal.Show();
                }



            }
            catch (ChargenException ex)
            {
                await AddAlertAsync(new AlertBox()
                {
                    AlertType = AlertType.Danger,
                    Message = $"Der Auftrag {Auftrag.Belegnummer} konnte nicht gepackt werden, da nicht genügend Chargen vorrätig sind.{Environment.NewLine}{ex}"
                });

                navigationManager.NavigateTo("/Lagerregal");
            }
            catch (Exception ex)
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Fehler beim buchen.{Environment.NewLine}{ex}"
                });
                navigationManager.NavigateTo("/Lagerregal");
            }

            sperrBuchenButton = false;
        }
        private async Task BuchungenLöschenAsync()
        {
            if (Auftrag is not null)
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
                await buchenService.BuchungenLöschenAsync(Auftrag.Belegtyp, Auftrag.Belegnummer, fbController);
                await jsRuntime.ShowToast(ToastType.success, "Buchungen wurden erfolgreich gelöscht");
                Auftrag = await PackAuftrag.GetPackAuftragAsync(Auftrag.Belegnummer, fbController);
            }
        }
        private async Task Abschließen()
        {
            AbschließenPipeline.Reset();
            await AbschließenPipeline.RunUntilFailureAsync(Auftrag);
        }
        private async Task ArtikelnummerOnKeyUp(KeyboardEventArgs e)
        {
            if (Auftrag is null)
            {
                return;
            }

            if (e.Code == "Enter" || e.Key == "Enter")
            {
                bool positionGefunden = false;
                using FbController2 fbController = new FbController2();
                // Wir gehen alle Positionen durch, und schauen, ob die Eingabe mit einer Position übereinstimmt
                foreach (var position in Auftrag.GetEndPositionen())
                {
                    var (gültig, seriennummer) = await buchenService.PrüfeArtikelnummer(position, EingabeArtikelnummer, fbController);
                    if (gültig)
                    {

                        // Prüfen, ob die Position eine Seriennummer erfordert. Solche Positionen können nicht eingescannt werden
                        if (position.PositionBenötigtSeriennummer && seriennummer == null)
                        {
                            continue;
                        }
                        // Prüfen, ob die Position bereits vollständig gebucht worden ist
                        if (position.BEREITS_GEBUCHT == position.Menge - position.BPOS_N_MENGEGELIEF)
                        {
                            continue;
                        }

                        // Mengen mit Nachkommastelle sind auch problematisch, nur über Artikelansicht
                        if (position.MengeHatKommaStelle)
                        {
                            continue;
                        }

                        positionGefunden = true;

                        var result = await buchenService.BuchenAsync(position, 1, EingabeArtikelnummer, null, fbController);
                        if (result.Success)
                        {
                            position.BEREITS_GEBUCHT = result.Gebucht;


                            BuchenBtnText = Auftrag.BuchenIstMöglich ? "Buchen" : "Teillieferung";


                            await jsRuntime.ShowToast(ToastType.success, $"Artikel {position.Artikelnummer} erfolgreich gebucht.", 1500);
                        }
                        break;
                    }

                }

                if (!positionGefunden)
                {
                    await jsRuntime.InvokeVoidAsync("showToast", "error", "Es konnte keine buchbare Position gefunden werden", 1500);
                }

                EingabeArtikelnummer = "";
            }
        }
        private async Task AuftragPausieren()
        {
            if (Auftrag is null)
            {
                return;
            }

            await auftragsfreigabeService.AuftragPausierenAsync(Auftrag, Mitarbeiter.PersonalNummer);
            await jsRuntime.InvokeVoidAsync("showToast", "success", $"Pausiertstatus erfolgreich aktualisiert.", 1500);
        }
        private async Task ÜberAbholungInformierenAsync(PackLieferschein packLieferschein)
        {
            sperrBuchenButton = true;
            if (Auftrag is not null)
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
                List<EmailVersandResponse> result = await lagerregalService.ÜberAbholungInformierenAsync(packLieferschein, fbController);
                bool erfolgreich = !result.Any(x => !x.Success);
                foreach (var response in result.Where(x => !x.Success))
                {
                    await AddAlertAsync(new AlertBox
                    {
                        Message = response.Message ?? String.Empty,
                        AlertType = AlertType.Danger
                    });
                }

                if (erfolgreich)
                {
                    await AddAlertAsync(new AlertBox
                    {
                        Message = "Kunde wurde erfolgreich zur anstehenden Abholung informiert",
                        AlertType = AlertType.Success
                    });
                }
            }
        }
        private async Task FreigabeEntfernen()
        {
            if (Auftrag is null)
            {
                return;
            }

            // MailBody generieren
            StringBuilder mailBody = new StringBuilder();
            mailBody.AppendLine($"Der Mitarbeiter {Mitarbeiter.Username} hat die Freigabe für den Auftrag {Auftrag.Belegnummer} entfernt.<br />");
            mailBody.AppendLine($"Kunde: {Auftrag.Kundenname}<br />");
            mailBody.AppendLine($"Seine Begründung:<br />");
            mailBody.AppendLine(FreigabeEntfernenInput.Begründung);
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("Der Auftrag muss nun überprüft werden und ist pausiert.");
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("Also erst einmal Bestand prüfen und ggf. korrigieren. Danach im Auftrag die Pausierung wieder raus nehmen, damit er weiter bearbeitet werden kann wenn die Ware wieder da ist.");
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("Wenn Ihr die Ware natürlich nie wieder besorgen könnt: Auftrag auf erledigt und mit dem Kunden reden.");
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("<br />");
            mailBody.AppendLine("Diese E-Mail wurde automatisch durch die WK5 erzeugt.");

            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            await auftragsfreigabeService.FreigabeEntfernenAsync(Auftrag.Belegnummer, fbController);
            await BelegChange.InsertBelegChangeAsync(fbController, new BelegChange
            {
                BCNG_A_BELEGTYP = "AU",
                BCNG_N_BELEGNR = Auftrag.Belegnummer.ToString(),
                BCNG_A_WERTALT = "Begründung:",
                BCNG_A_WERTNEU = FreigabeEntfernenInput.Begründung,
                BCNG_N_ART = 63,
                BCNG_N_USER = fbController.UserId
            });


            EmailController emailController = new EmailController() { Html = true };
            var response = await emailController.SendenAsync(
                empfängerEmail: "info@karley.eu",
                betreff: $"Freigabe für Auftrag {Auftrag.Belegnummer} entfernt.",
                body: mailBody.ToString()
            );

            await AddAlertAsync(new AlertBox(message: $"AU-{Auftrag.Belegnummer} wurde aus der Freigabe entfernt.", alertType: AlertType.Success));

            navigationManager.NavigateTo("/Lagerregal");
        }
        public async Task TakePhotos()
        {
            await jsRuntime.InvokeAsync<string>("eval", new object[] { $"document.getElementById('lagerregal-photo-input').click();" });
        }
        private async Task HandleFileSelected(InputFileChangeEventArgs e)
        {
            if (Auftrag is null)
            {
                return;
            }
            _photoIsSaving = true;


            List<IBrowserFile> files = new List<IBrowserFile>();
            if (e.FileCount > 1)
            {
                files.AddRange(e.GetMultipleFiles());
            }
            else
            {
                files.Add(e.File);
            }


            foreach (IBrowserFile upload in files)
            {
                await Dokumentenablage.UploadPackbildAsync(DokumentenablageArt.Aufträge, Belegnummer.ToString(), upload);
                PhotoAmount++;
            }
            _photoIsSaving = false;
        }
        private async Task HandlePhotoModalClose()
        {
            if (_photoIsSaving)
            {
                return;
            }

            if (PhotoAmount < 1)
            {
                await jsRuntime.ShowToast(ToastType.error, "Es müssen noch Fotos vom Paketinhalt gemacht werden");
            }
            _showPhotoModal = false;
        }
        private void SetWarnmeldungen()
        {
            if (Auftrag is null)
            {
                return;
            }

            if (Auftrag.NeutralerVersender)
            {
                _warnmeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Warning,
                    Message = "Achtung! Neutraler Versand! Es darf kein Karley Logo auf Ware und Verpackung vorhanden sein!"
                });
            }

            if (Auftrag.Liefertermin > DateTime.Now)
            {
                _warnmeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Warning,
                    Message = $"Das Lieferdatum für den Auftrag ist noch nicht heute! Lieferdatum: {Auftrag.Liefertermin.ToShortDateString()}"
                });
            }

            if (Program.AppDaten.Zahlungsbedingungen.IstVorkasse(Auftrag.ZahlungsbedingungId) && !Auftrag.BELE_L_BEZAHLT)
            {
                _warnmeldungen.Add(new AlertBox
                {
                    AlertType = AlertType.Warning,
                    Message = "Der Auftrag ist Vorkasse und hat noch nicht den Status ZAHLUNGERHALTEN!"
                });
            }
        }
        
        public override async Task CheckActivePageAsync()
        {
            var (success, page) = ActivePages.AddActivePage(new ActivePage(PageType.Lagerregal, Belegnummer.ToString(), Mitarbeiter.PersonalNummer));

            if (success)
            {
                Page = page;
            }
            else
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Der Auftrag wird zurzeit durch {Program.AppDaten.GetMitarbeiterName(page.UserId)} gepackt."
                });

                SperreDurchAnderenUser = true;

                navigationManager.NavigateTo("/Lagerregal");
            }
        }
    }
}
