using KarleyLibrary.Erweiterungen;
using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Toolbelt.Blazor.HotKeys;
using WK5.Core;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Basis.Filter;
using WK5.Core.Drucken.Gutschriften;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Models.Tools.Lagerregal;
using WK5.Core.PageModels.Verkauf.Gutschriften;

namespace WK5_Blazor.Pages.Verkauf.Gutschriften
{
    public partial class GutschriftForm
    {
        [Parameter] public int Gutschriftnummer { get; set; }

        private Queue<Belegposition> _chargenContinueWith = new Queue<Belegposition>();
        private Belegposition? _seriennummerChargenPosition;
        private List<Belegcharge> _lieferscheinChargen = new List<Belegcharge>();
        private List<BelegSeriennummer> _lieferscheinSeriennummern = new List<BelegSeriennummer>();
        private List<BelegSeriennummer> _chargenSeriennummern = new List<BelegSeriennummer>();


        private bool _showStücklisteModal;
        private bool _showKundenArtikelhistorieModal;
        private bool _showPosLöschenModal;
        private bool _showSeriennummerModal;
        public GutschriftForm()
        {
            Input = new Gutschrift();
            FilterZeiterfassung.Option = ZeitenFilterOption.Gutschrift;
            StartCopy = new Gutschrift();
            ActiveTab = GutschriftenTabs.Kundendaten;
            EditOnlyTabs.Add(GutschriftenTabs.Dokumentenablage);
            EditOnlyTabs.Add(GutschriftenTabs.Historie);
        }
        public override string ActivePageName => Modus switch
        {
            EditMode.Anlage => "Neue Gutschrift",
            EditMode.Bearbeiten => $"GU-{Gutschriftnummer}",
            _ => "Unbekannt"
        };
        public override string FinalBreadcrumbItemName => Modus switch
        {
            EditMode.Anlage => "Neu",
            EditMode.Bearbeiten => $"{Gutschriftnummer}",
            _ => "Unbekannt"
        };

        protected override async Task OnParametersSetAsync()
        {
            _versandMehrwertsteuer = await Mehrwertsteuer.GetVersandMehrwertsteuerAsync();

            if (Gutschriftnummer > 0)
            {
                await LadeEditModeAsync();
            }

            FilterZeiterfassung.Suchbegriff = Gutschriftnummer.ToString();
            FilterZeiterfassung.Kundennummer = Input.Kundennummer;

            if (Kunde is null)
            {
                _showKundenSucheModal = true;
            }

            StartCopy = Input.DeepCopy();



            await SetAlerts();
        }
        public async override Task LadeEditModeAsync()
        {
            using FbController2 fbController = new FbController2();
            Gutschrift? gutschrift = await Gutschrift.GetGutschriftAsync(Gutschriftnummer, fbController);
            if (gutschrift is not null)
            {
                Kunde = await Kunde.GetKundeAsync(gutschrift.Kundennummer);
                if (Kunde is not null)
                {
                    await KundeSelectedAsync(Kunde);

                    Input = gutschrift;
                    _zähler = gutschrift.Positionen.Count;
                    await LieferanschriftChangedAsync(Input.LieferanschriftId);
                    await RechnungsanschriftChangedAsync(Input.RechnungsanschriftId);
                    await PositionSelected(Input.Positionen.FirstOrDefault());
                    _subBelege = await belegService.GetSubBelege(BelegTyp.Gutschrift, Gutschriftnummer, fbController);
                    if (Input.LieferscheinnummerVerknüpfung > 0)
                    {
                        await LadeVerfügbareChargenAsync(fbController);
                    }
                    Modus = EditMode.Bearbeiten;
                }
            }
            else
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Gutschrift {Gutschriftnummer} konnte nicht gefunden werden."
                });


                navigationManager.NavigateTo("/Gutschriften");
            }

            if (!_isDisposed)
            {
                await CheckActivePageAsync();
            }
        }
        private async Task SubmitAsync()
        {
            if ((NurDurchAdminZuBearbeiten && !Mitarbeiter.IsAdmin) || SperreDurchAnderenUser || !Input.HasBeenModified(StartCopy) || Gesperrt)
            {
                return;
            }


            if (_editForm is null || _editForm.EditContext is null || Kunde is null)
            {
                return;
            }

            if (_editForm.EditContext.Validate())
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
                await fbController.StartTransactionAsync();
                try
                {
                    if (Modus is EditMode.Anlage)
                    {
                        await belegService.CreateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
                        await AddAlertAsync(new AlertBox
                        {
                            AlertType = AlertType.Success,
                            Message = $"Gutschrift {Input.Belegnummer} erfolgreich angelegt",
                            DecayTime = 10
                        });
                    }
                    else
                    {
                        if (Input.BELE_L_FIBUUEBERGABE)
                        {
                            await belegService.UpdateGesperrtenBelegAsync(Input, fbController);
                            await AddAlertAsync(new AlertBox
                            {
                                AlertType = AlertType.Success,
                                Message = $"Notiz wurde erfolgreich gespeichert",
                                DecayTime = 10
                            });
                        }
                        else
                        {
                            await belegService.UpdateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
                            await AddAlertAsync(new AlertBox
                            {
                                AlertType = AlertType.Success,
                                Message = $"Gutschrift {Input.Belegnummer} erfolgreich gespeichert",
                                DecayTime = 10
                            });
                        }
                    }
                    await fbController.CommitChangesAsync();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    await fbController.RollbackChangesAsync();
                    throw;
                }

                if (Modus is EditMode.Anlage)
                {
                    navigationManager.NavigateTo($"/Gutschriften/{Input.Belegnummer}");
                }
                else
                {
                    await OnParametersSetAsync();
                }


            }


        }
        private async Task LadeVerfügbareChargenAsync(FbController2 fbController)
        {
            _lieferscheinChargen = await Belegcharge.GetLieferscheinChargenAsync(Input.LieferscheinnummerVerknüpfung, fbController).ToListAsync();
            _lieferscheinSeriennummern = await BelegSeriennummer.GetBelegSeriennummernAsync(BelegTyp.Lieferschein, Input.LieferscheinnummerVerknüpfung, fbController).ToListAsync();

            foreach (var pos in Input.Positionen)
            {
                foreach (Seriennummer seriennummer in pos.Seriennummern)
                {
                    var lieferscheinSeriennummer = _lieferscheinSeriennummern.Where(x => x.BSNR_A_SN == seriennummer.Nummer && x.Artikelnummer == pos.Artikelnummer).FirstOrDefault();
                    if (lieferscheinSeriennummer is not null)
                    {
                        _lieferscheinSeriennummern.Remove(lieferscheinSeriennummer);
                    }
                }

                decimal bereits_gechargt = pos.Gechargt;
                foreach (var charge in _lieferscheinChargen.Where(x => x.Artikelnummer == pos.Artikelnummer))
                {
                    decimal tmpMenge = charge.BCHA_N_MENGE;
                    if (charge.BCHA_N_MENGE - bereits_gechargt < 0)
                    {
                        charge.BCHA_N_MENGE = 0;
                    }
                    else
                    {
                        charge.BCHA_N_MENGE -= bereits_gechargt;
                    }
                    bereits_gechargt -= tmpMenge;

                    if (bereits_gechargt is 0)
                    {
                        break;
                    }
                }

            }
        }

        #region Chargen
        private async Task<bool> IstSeriennummerChargenVerfügbarAsync()
        {
            if (_editForm is null || _editForm.EditContext is null || Kunde is null)
            {
                return false;
            }

            if (!_editForm.EditContext.Validate())
            {
                await jsRuntime.ShowToast(ToastType.error, "Chargen ist zurzeit nicht möglich, da der Lieferschein aufgrund eines Eingabefehlers nicht gespeichert werden konnte.");
                return false;
            }

            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            if (!StartCopy.BELE_L_FIBUUEBERGABE)
            {
                await fbController.StartTransactionAsync();
                await belegService.UpdateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
                await fbController.CommitChangesAsync();
            }

            return true;
        }
        private async Task AutoChargenAsync(Belegposition pos)
        {
            if (_editForm is null || _editForm.EditContext is null || Kunde is null)
            {
                return;
            }
            if (!pos.PositionIstStückliste && pos.PositionBenötigtSeriennummer)
            {
                return;
            }

            if (!_editForm.EditContext.Validate())
            {
                await jsRuntime.ShowToast(ToastType.error, "Chargen ist zurzeit nicht möglich, da die Gutschrift aufgrund eines Eingabefehlers nicht gespeichert werden kann.");
                return;
            }

            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            await fbController.StartTransactionAsync();
            await belegService.UpdateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
            await fbController.CommitChangesAsync();
            await fbController.StartTransactionAsync();
            try
            {
                if (!pos.PositionIstStückliste)
                {
                    decimal zu_chargen_rest = pos.Menge;
                    decimal muss_gechargt_sein = pos.Menge;
                    foreach (var charge in _lieferscheinChargen.Where(x => x.Artikelnummer == pos.Artikelnummer && x.BCHA_N_MENGE > 0))
                    {

                        decimal zu_chargen = zu_chargen_rest;
                        if (charge.BCHA_N_MENGE < zu_chargen_rest)
                        {
                            zu_chargen = charge.BCHA_N_MENGE;
                        }

                        await chargenService.ChargenAsync(pos, charge.BCHA_N_CHARGE, zu_chargen, Mitarbeiter.PersonalNummer, fbController);

                        zu_chargen_rest -= zu_chargen;
                        charge.BCHA_N_MENGE -= zu_chargen;
                        pos.Gechargt += zu_chargen;
                        if (zu_chargen_rest is 0)
                        {
                            break;
                        }
                    }

                    if (zu_chargen_rest is not 0)
                    {
                        await jsRuntime.ShowToast(ToastType.warning, $"Es konnten nur {pos.Gechargt} Chargen für den Artikel {pos.Artikelnummer} zugewiesen werden.");
                    }
                }



                await fbController.CommitChangesAsync();
                await jsRuntime.ShowToast(ToastType.success, "Position erfolgreich gechargt");
            }
            catch (ChargenException ex)
            {
                await jsRuntime.ShowToast(ToastType.error, $"{ex.Artikelnummer} konnte nicht ausreichend gechargt werden, da nur {ex.VerfügbareMenge} Chargen zur Verfügung stehen.");
                await fbController.RollbackChangesAsync();
            }
            catch (Exception)
            {
                await fbController.RollbackChangesAsync();
                throw;
            }





        }
        private async Task SeriennummerChargenAsync(BelegSeriennummer seriennummer, Belegposition pos)
        {
            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            try
            {
                await chargenService.SeriennummerChargenAsync(seriennummer, pos, Mitarbeiter.PersonalNummer, Input.Name1, fbController);
                _chargenSeriennummern.Remove(seriennummer);
                await jsRuntime.ShowToast(ToastType.success, "Position erfolgreich gechargt");
                if (pos.Gechargt == pos.Menge)
                {
                    if (_chargenContinueWith.Any())
                    {
                        await LadeSeriennummernAsync();
                    }
                    else
                    {
                        _chargenSeriennummern.Clear();
                    }
                }
            }
            catch (ChargenException ex)
            {

                await jsRuntime.ShowToast(ToastType.error, ex.Message);
            }



        }
        private async Task RemoveChargenAsync(Belegposition pos)
        {
            if (Kunde is null)
            {
                return;
            }
            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            await fbController.StartTransactionAsync();
            await belegService.UpdateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
            try
            {
                await chargenService.RemoveBelegChargenAsync(pos, Mitarbeiter.PersonalNummer, fbController);
                pos.Seriennummern.Clear();
                foreach (var item in pos.GetEndPositionen())
                {
                    pos.Seriennummern.Clear();
                }
                await LadeVerfügbareChargenAsync(fbController);
                await fbController.CommitChangesAsync();
                await jsRuntime.ShowToast(ToastType.success, "Chargen erfolgreich gelöscht");
            }
            catch (Exception)
            {
                await fbController.RollbackChangesAsync();
                throw;
            }
        }
        private Task SetupChargenPositionenAsync(Belegposition pos)
        {
            if (pos.PositionIstStückliste)
            {
                foreach (var subPos in pos.GetEndPositionen().Where(x => x.PositionBenötigtSeriennummer && x.Gechargt < x.Menge))
                {
                    _chargenContinueWith.Enqueue(subPos);
                }
            }
            else
            {
                _chargenContinueWith.Enqueue(pos);
            }

            return Task.CompletedTask;
        }
        private async Task LadeSeriennummernAsync()
        {
            if (!_chargenContinueWith.Any())
            {
                await jsRuntime.ShowToast(ToastType.error, "Für die Position wurden bereits alle Seriennummern gechargt.");
                return;
            }
            _seriennummerChargenPosition = _chargenContinueWith.Dequeue();
            if (_seriennummerChargenPosition is not null)
            {
                _chargenSeriennummern = _lieferscheinSeriennummern.Where(x => x.Artikelnummer == _seriennummerChargenPosition.Artikelnummer).ToList();

                if (_chargenSeriennummern.Count is 0)
                {
                    await jsRuntime.ShowToast(ToastType.error, $"Für den Artikel {_seriennummerChargenPosition.Artikelnummer} konnten keine offenen Seriennummern gefunden werden.");
                }
            }
        }
        #endregion

        public async override Task DownloadAsync(bool confirmed = false)
        {
            if (Kunde is null)
            {
                return;
            }

            _isDownloading = true;
            StateHasChanged(); // Wird für den Shortcut benötigt
            using FbController2 fbController = new FbController2();
            var gutschrift = await Gutschrift.GetGutschriftAsync(Gutschriftnummer, fbController);

            if (gutschrift is not null)
            {

                PrintGutschriftRegelsatz printRegeln = new PrintGutschriftRegelsatz
                {
                    ShowFooter = true,
                    ShowHeader = true
                };

                if (Program.AppDaten.VersandMehrwertsteuer is null)
                {
                    throw new ArgumentNullException(nameof(Program.AppDaten.VersandMehrwertsteuer));
                }

                PrintGutschrift printer = await PrintGutschrift.CreateAsync(gutschrift, printRegeln, fbController);
                string filenamePdf = printer.Print(GlobalConfig.Configuration.OutputPfad);
                await belegService.SetDruckdatumAsync(BelegTyp.Gutschrift, Gutschriftnummer, fbController);

                await downloadService.DownloadFile($"GU-{Gutschriftnummer}.pdf", await File.ReadAllBytesAsync(filenamePdf), "application/pdf");
                await downloadService.ClearBuffers();
            }

            _isDownloading = false;
        }
        public async override Task ÖffneMailAsync(bool confirmed = false)
        {

            if (Kunde is null)
            {
                return;
            }

            if (Kunde.KUND_A_EMAIL is null)
            {
                await jsRuntime.ShowToast(ToastType.error, "Gutschrift konnte nicht in David geöffnet werden, da beim Kunden keine Mailadresse hinterlegt ist");
                return;
            }
            _mailIsLoading = true;
            StateHasChanged(); // Wird für den Shortcut benötigt
            using FbController2 fbController = new FbController2();
            var gutschrift = await Gutschrift.GetGutschriftAsync(Gutschriftnummer, fbController);

            if (gutschrift is not null)
            {

                string empfängerEmail = Kunde.KUND_A_EMAIL;
                if (gutschrift.RechnungsanschriftId > 0)
                {
                    Rechnungsanschrift rechnungsanschrift = await Rechnungsanschrift.GetRechnungsanschriftAsync(gutschrift.Kundennummer, gutschrift.RechnungsanschriftId) ?? throw new NullReferenceException(nameof(rechnungsanschrift));

                    if (!String.IsNullOrWhiteSpace(rechnungsanschrift.KURE_A_EMAIL))
                    {
                        empfängerEmail = rechnungsanschrift.KURE_A_EMAIL;
                    }
                }


                KarleyBrowserInterfaceEmail email = new KarleyBrowserInterfaceEmail
                {
                    Absender = GlobalConfig.EmailInfoEU,
                    Empfänger = empfängerEmail,
                    Content = String.Empty,
                    Betreff = $"Gutschrift {Gutschriftnummer}"
                };

                PrintGutschriftRegelsatz printRegeln = new PrintGutschriftRegelsatz
                {
                    ShowFooter = true,
                    ShowHeader = true
                };

                if (Program.AppDaten.VersandMehrwertsteuer is null)
                {
                    throw new ArgumentNullException(nameof(Program.AppDaten.VersandMehrwertsteuer));
                }

                PrintGutschrift printer = await PrintGutschrift.CreateAsync(gutschrift, printRegeln, fbController);
                string filenamePdf = printer.Print(GlobalConfig.Configuration.OutputPfad);
                await belegService.SetDruckdatumAsync(BelegTyp.Gutschrift, Gutschriftnummer, fbController);
                email.Anhänge.Add(filenamePdf);

                var (success, data, _) = KarleyLibrary.Serialization.XMLWriter.Serialize(email);
                if (success)
                {
                    string xmlFilename = $"{email.GetHashCode()}.xml";
                    await File.WriteAllTextAsync(Path.Combine(GlobalConfig.Configuration.OutputPfad, xmlFilename), data);
                    await jsRuntime.OpenNewTab($"karley:davidMail;{xmlFilename}");
                }


            }
            _mailIsLoading = false;

        }
        public override string GetPositionNavListClass(Belegposition pos)
        {
            if (!_posValidator.Validate(pos).IsValid)
            {
                return $"{GetSubNavListClass(SelectedPosition == pos)} bg-danger text-light";
            }
            if (pos.BenötigtWeitereSeriennummern || pos.BenötigtWeitereChargen)
            {
                return $"{GetSubNavListClass(SelectedPosition == pos)} bg-secondary text-light";
            }

            return GetSubNavListClass(SelectedPosition == pos);
        }

        public override async Task CheckActivePageAsync()
        {
            var (success, page) = ActivePages.AddActivePage(new ActivePage(PageType.Gutschrift, Gutschriftnummer.ToString(), Mitarbeiter.PersonalNummer));

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

                SperreDurchAnderenUser = true;
            }
        }

        public async Task OnTabChange(GutschriftenTabs newActiveTab)
        {
            switch (newActiveTab)
            {
                case GutschriftenTabs.Positionen:
                    if (Input.Positionen.Count is 0)
                    {
                        _showArtikelSucheModal = true;
                    }
                    break;
                case GutschriftenTabs.Historie:
                    await LadeHistorieAsync();
                    break;
                default:
                    break;
            }
        }

        public override void AddHotKeys(HotKeysContext context)
        {
            context.Add(ModKeys.Alt, Keys.S, SubmitAsync, "Speichert den Auftrag", Exclude.Default);
            base.AddHotKeys(context);
        }
    }
}
