using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Basis.Filter;
using WK5.Core.Models;
using WK5.Core.PageModels.Einkauf.Bestellungen;

namespace WK5_Blazor.Pages.Bestellungen
{
    public partial class BestelldispositionView
    {
#nullable disable
        [CascadingParameter] public AppMitarbeiter Mitarbeiter { get; set; }
#nullable enable

        public BestelldispoSorting Sorting { get; set; } = BestelldispoSorting.BezahlterBedarf;
        public Bestellung? Bestellung { get; set; }
        private CancellationTokenSource _tokenSource = new CancellationTokenSource();
        private CancellationTokenSource _tokenSourceClicked = new CancellationTokenSource();
        private readonly List<Bestelldisposition> _items = new List<Bestelldisposition>();
        private readonly List<Auftrag> _belege = new List<Auftrag>();
        private bool _isLoading;
        private bool _showLieferantenSucheModal;
        private bool _showVerbrauchsdatenModal;
        private bool _isSaving;
        private bool _sortDescending = true;

        private Lieferantenartikel? _günstigsterLieferantMitBestand;
        private Lieferantenartikel? _günstigsterHauptlieferant;
        private LieferantenFilter FilterLieferant { get; set; } = new LieferantenFilter();
        private Lieferant? _lieferant;
        private Artikelbewegung? _letzteZugangsBewegung;
        private Bestelldisposition? _selectedBestelldisposition;
        private Artikel? _selectedArtikel;
        private Bestellposition? _selectedPos;
        private List<(decimal menge, decimal preis, decimal rabatt)> _staffelpreise = new List<(decimal menge, decimal preis, decimal rabatt)>();
        private bool _isDisposed;

        private readonly BestelldispositionFilter _filter = new BestelldispositionFilter();
        private async Task SelectLieferant(Lieferant? lieferant)
        {
            _lieferant = lieferant;
            _filter.LieferantenId = lieferant?.LIEF_N_NR ?? 0;
            _showLieferantenSucheModal = false;
            await LadeDisposition();


            if (lieferant is not null)
            {
                if (Bestellung is null)
                {
                    Bestellung = new Bestellung();
                }
                else
                {
                    Bestellung.Positionen.Clear();
                }

                Bestellung.LieferantenId = lieferant.LIEF_N_NR;
                Bestellung.BEST_N_ZAHLUNG = lieferant.LIEF_N_ZABD;
                Bestellung.LieferbedingungId = lieferant.LIEF_N_LIBD;
                Bestellung.Währung = lieferant.LIEF_A_WAEHRUNG;
                Bestellung.Versicherungskosten = lieferant.LIEF_WK5_N_VERSICHERKOSTEN;
                Bestellung.Verpackungskosten = lieferant.LIEF_WK5_N_VERPACKKOSTEN;
                Bestellung.Versandkosten = lieferant.LIEF_WK5_N_VERSANDKOSTEN;
                var ansprechpartner = await AnsprechpartnerLieferant.GetAnsprechpartnerAsync(lieferant.LIEF_N_NR).FirstOrDefaultAwaitAsync(x => ValueTask.FromResult(x.LIEP_L_HAUPTPARTNER));
                Bestellung.BEST_A_PARTNER = ansprechpartner?.LIEP_A_NAME ?? String.Empty;
            }
            else
            {
                Bestellung = null;
            }
        }

        private async Task OnLieferantFocusOut()
        {
            await SelectLieferant(await Lieferant.GetLieferantAsync(_filter.LieferantenId));
        }

        private Task SortAsync(BestelldispoSorting sorting)
        {
            if(sorting == Sorting)
            {
                _sortDescending = !_sortDescending;
            }
            else
            {
                Sorting = sorting;
            }

            return Task.CompletedTask;
        }

        private string GetRowClass(Bestelldisposition dispo)
        {
           
            if (dispo.BezahlterBedarf > 0)
            {
                if (_selectedBestelldisposition == dispo)
                {
                    return "table-success fw-bold";
                }
                return "table-success";
            }

            if(dispo.Bedarf > 0)
            {
                if (_selectedBestelldisposition == dispo)
                {
                    return "table-danger fw-bold";
                }
                return "table-danger";
            }

            if (_selectedBestelldisposition == dispo)
            {
                return "fw-bold";
            }
            return string.Empty;
        }
        private string GetSortedIcon(BestelldispoSorting sorting)
        {
            if(sorting == Sorting)
            {
                return _sortDescending ? "fas fa-sort-amount-down" : "fas fa-sort-amount-up-alt";
            }

            return string.Empty;
            
        }
        private IEnumerable<Bestelldisposition> GetBestelldispo()
        {
            switch (Sorting)
            {
                case BestelldispoSorting.Artikelnummer:
                    return _sortDescending 
                        ? _items.OrderByDescending(x => x.Artikelnummer)
                        : _items.OrderBy(x => x.Artikelnummer);
                case BestelldispoSorting.Bezeichnung:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.ArtikelBezeichnung)
                        : _items.OrderBy(x => x.ArtikelBezeichnung);
                case BestelldispoSorting.BestellvorschlagEuro:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.BestellvorschlagEuro)
                        : _items.OrderBy(x => x.BestellvorschlagEuro);
                case BestelldispoSorting.Bestellvorschlag:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.Bestellvorschlag)
                        : _items.OrderBy(x => x.Bestellvorschlag);
                case BestelldispoSorting.Bestand:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.Bestand)
                        : _items.OrderBy(x => x.Bestand);
                case BestelldispoSorting.Bedarf:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.Bedarf)
                        : _items.OrderBy(x => x.Bedarf);
                case BestelldispoSorting.Mindestbestand:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.Mindestbestand)
                        : _items.OrderBy(x => x.Mindestbestand);
                case BestelldispoSorting.Bestellt:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.Bestellt)
                        : _items.OrderBy(x => x.Bestellt);
                case BestelldispoSorting.BezahlterBedarf:
                    return _sortDescending
                        ? _items.OrderByDescending(x => x.BezahlterBedarf)
                        : _items.OrderBy(x => x.BezahlterBedarf);
                default:
                    throw new ArgumentOutOfRangeException(nameof(Sorting));
            }
           
        }
        protected override async Task OnInitializedAsync()
        {
            await LadeDisposition();
            //_showLieferantenSucheModal = true;
        }

        private bool BestellungContainsArtikel(string artikelnummer)
        {
            if (Bestellung is null)
            {
                return false;
            }

            return Bestellung.Positionen.Any(x => x.BEPO_A_ARTIKELNR.Equals(artikelnummer));
        }
        private Task DeleteBestellpositionAsync()
        {
            if (_selectedPos is not null && Bestellung is not null)
            {
                Bestellung.Positionen.Remove(_selectedPos);
                _selectedPos = null;
            }

            return Task.CompletedTask;
        }
        private Task EditBestellpositionAsync(Bestelldisposition bestelldispo)
        {
            if (_lieferant is not null && Bestellung is not null)
            {
                _selectedPos = Bestellung.Positionen.FirstOrDefault(x => x.BEPO_A_ARTIKELNR.Equals(bestelldispo.Artikelnummer));
            }

            return Task.CompletedTask;
        }

        private async Task AddArtikelToBestellungAsync(Bestelldisposition bestelldispo)
        {
            if (_lieferant is null || Bestellung is null)
            {
                return;
            }

            using FbController2 fbController = new FbController2();
            Lieferantenartikel? lieferantenartikel = await Lieferantenartikel.GetLieferantenartikelAsync(bestelldispo.Artikelnummer, _lieferant.LIEF_N_NR, fbController);

            if (lieferantenartikel is null)
            {
                await jsRuntime.ShowToast(ToastType.error, $"{bestelldispo.Artikelnummer} kann nicht durch den Lieferanten {_lieferant.LIEF_A_NAME1} geliefert werden.");
            }
            else
            {
                var (rabatt1, rabatt2) = lieferantenartikel.GetRabatte(bestelldispo.Bestellvorschlag);
                Artikel artikel = await artikelService.GetAsync(bestelldispo.Artikelnummer, fbController) ?? throw new NullReferenceException(nameof(artikel));
                Bestellposition pos = new Bestellposition
                {
                    BEPO_A_ARTIKELNR = lieferantenartikel.ARLI_A_ARTIKELNR,
                    BEPO_A_BEZ1 = lieferantenartikel.ARLI_A_BEZ1 ?? string.Empty,
                    BEPO_A_BEZ2 = lieferantenartikel.ARLI_A_BEZ2 ?? string.Empty,
                    BEPO_A_BEZ3 = lieferantenartikel.ARLI_A_BEZ3 ?? string.Empty,
                    BEPO_A_BEZ4 = lieferantenartikel.ARLI_A_BEZ4 ?? string.Empty,
                    BEPO_A_BEZ5 = lieferantenartikel.ARLI_A_BEZ5 ?? string.Empty,
                    BEPO_A_BESTELLNUMMER = lieferantenartikel.ARLI_A_BESTELLNR ?? string.Empty,
                    BEPO_N_MENGE = bestelldispo.Bestellvorschlag,
                    BEPO_N_PREIS = lieferantenartikel.GetPreis(bestelldispo.Bestellvorschlag),
                    BEPO_N_RABATTPROZ = rabatt1,
                    BEPO_N_RABATTPROZ2 = rabatt2,
                    BEPO_N_MWSTPROZ = artikel.MWST_N_PROZENT
                };

                Bestellung.Positionen.Add(pos);
                _selectedPos = pos;
            }
        }

        private async Task SaveBestellungAsync()
        {
            if (_isSaving || Bestellung is null || _lieferant is null)
            {
                return;
            }

            _isSaving = true;
            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            if(Bestellung.GetNettoBetrag() >= _lieferant.LIEF_N_FRACHTFR_AB)
            {
                Bestellung.Versandkosten = 0;
                Bestellung.BEST_L_FRACHTFREI = true;
            }

            for (int i = 0; i < Bestellung.Positionen.Count; i++)
            {
                Bestellung.Positionen[i].BEPO_N_POS = i + 1;
            }

            int bestellnummer = await bestellService.CreateBestellungAsync(Bestellung, Mitarbeiter.PersonalNummer, fbController);
            await AddAlertAsync(new AlertBox
            {
                AlertType = AlertType.Success,
                Message = "Bestellung wurde erfolgreich angelegt",
                DecayTime = 10
            });
            navigationManager.NavigateTo($"/Bestellungen/{bestellnummer}");
        }
        private async Task LadeDisposition()
        {
            _tokenSource.Cancel();
            _items.Clear();
            _tokenSource = new CancellationTokenSource();
            _selectedBestelldisposition = null;
            var token = _tokenSource.Token;
            await foreach (var item in bestellService.GetBestelldispositionAsync(_filter, token))
            {
                _items.Add(item);
                StateHasChanged();
            }
        }

        private async Task MengeChangedAsync(decimal menge)
        {
            if(_selectedPos is not null && _lieferant is not null)
            {
                _selectedPos.BEPO_N_MENGE = menge;

                using FbController2 fbController = new FbController2();
                var lieferantenartikel = await Lieferantenartikel.GetLieferantenartikelAsync(_selectedPos.BEPO_A_ARTIKELNR, _lieferant.LIEF_N_NR, fbController);

                if(lieferantenartikel is not null)
                {
                    _selectedPos.BEPO_N_PREIS = lieferantenartikel.GetPreis(menge);
                    var (rabatt1, rabatt2) = lieferantenartikel.GetRabatte(menge);
                    _selectedPos.BEPO_N_RABATTPROZ = rabatt1;
                    _selectedPos.BEPO_N_RABATTPROZ2 = rabatt2;
                }
            }
        }

        private async Task BestelldispositionsItemClicked(Bestelldisposition pos)
        {
            _tokenSourceClicked.Cancel();
            _tokenSourceClicked = new CancellationTokenSource();
            var token = _tokenSourceClicked.Token;
            _belege.Clear();
            using FbController2 fbController = new FbController2();
            _isLoading = true;
            _selectedBestelldisposition = pos;

            _selectedArtikel = await artikelService.GetAsync(pos.Artikelnummer, fbController);

            var lieferantenartikel = await Lieferantenartikel.GetLieferantenartikelAsync(pos.Artikelnummer, fbController).ToListAsync();
            _günstigsterLieferantMitBestand = lieferantenartikel.OrderBy(x => x.PreisMitRabatt(pos.Bestellvorschlag)).FirstOrDefault(x => x.WK5_ARLI_N_LIEFBESTAND > 0);
            _günstigsterHauptlieferant = lieferantenartikel.OrderBy(x => x.PreisMitRabatt(pos.Bestellvorschlag)).FirstOrDefault(x => x.ARLI_L_HAUPTLIEFERANT);

            try
            {
                _staffelpreise = await pos.GetStaffelpreiseAsync(_filter.LieferantenId, token).ToListAsync();
                _letzteZugangsBewegung = await bestellService.GetLetzterBewegungZugangAsync(pos.Artikelnummer, token);
                await foreach (var beleg in pos.GetBelegeMitPositionAsync(fbController, token))
                {

                    _belege.Add(beleg);
                    StateHasChanged();
                }
            }
            catch (OperationCanceledException) { }
            finally
            {
                _isLoading = false;
            }




        }

        public override ValueTask DisposeAsync()
        {
            _tokenSource?.Cancel();
            _tokenSource?.Dispose();
            _isDisposed = true;
            return base.DisposeAsync();
        }
    }
}
