using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WK5.Core.Models.Bestellungen
{
    public class AuftragBestellenBestellung
    {

        private readonly AuftragBestellenController _controller;
        private AuftragBestellenLieferant? _lieferant;
        private int _lieferantId;


        /// <summary>
        /// Dieser Wert ist nur für die Eingabe der Artikelnummer gedacht, welche in einen Artikel aufgelöst wird.
        /// </summary>
        public string? InputArtikelnummer { get; set; }

        public AuftragBestellenArtikel? GetArtikelByArtikelnummer() => _controller.Artikel.Where(x => x.Artikelnummer == InputArtikelnummer).FirstOrDefault();


        /// <summary>
        /// Ruft einen Wert ab, der angibt, ob für die Bestellung noch eine weitere Position hinzugefügt werden kann oder nicht.
        /// </summary>
        public bool CanAddPosition
        {
            get
            {
                var artikel = GetArtikelByArtikelnummer();

                return artikel is not null;
            }
        }


        public AuftragBestellenLieferant? Lieferant
        {
            get => _lieferant;
            set
            {
                _lieferant = value;

                Lieferbedingung = _lieferant?.Lieferbedingung ?? 0;
                Zahlungsbedingung = _lieferant?.Zahlungsbedingung ?? 0;
                Währung = _lieferant?.Währung ?? String.Empty;
                Direktlieferung = _lieferant?.DirektLieferungErlaubt ?? false;

                var sucheHauptAnsprechpartner = _lieferant?.Ansprechpartner?.Where(x => x.LIEP_L_HAUPTPARTNER).FirstOrDefault();

                Ansprechpartner = sucheHauptAnsprechpartner?.LIEP_A_NAME ?? String.Empty;

                var tmpPositionen = new List<AuftragBestellenPosition>(Positionen);
                if (_lieferant is not null)
                {
                    _lieferantId = _lieferant.LieferantId;
                    foreach (var pos in tmpPositionen)
                    {
                        var lfArtikel = _controller.GetLieferantenArtikel(pos.SelectedArtikel, _lieferantId);
                        // Kein Lieferantenartikel gefunden, oder die Position ist als Abrufposition hinterlegt, dann entfernen wir die Pos direkt. Im Zweifelsfall muss man die Position halt wieder hinzufügen
                        if (lfArtikel is null)
                        {
                            Positionen.Remove(pos);
                            if (Positionen.Count == 0)
                            {
                                _lieferant = null;
                            }
                        }
                        else
                        {
                            pos.Bezeichnung1 = lfArtikel.Bezeichnung1;
                            pos.Bezeichnung2 = lfArtikel.Bezeichnung2;
                            pos.Bezeichnung3 = lfArtikel.Bezeichnung3;
                            pos.Bezeichnung4 = lfArtikel.Bezeichnung4;
                            pos.Bezeichnung5 = lfArtikel.Bezeichnung5;
                            pos.Bestellnummer = lfArtikel.Bestellnummer;
                            pos.Preis = lfArtikel.GetPreis(pos.Menge);
                            var (rabatt1, rabatt2) = lfArtikel.GetRabatte(pos.Menge);
                            pos.Rabatt1 = rabatt1;
                            pos.Rabatt2 = rabatt2;
                        }
                    }


                }
                else
                {
                    Positionen.Clear();
                }
            }
        }
        public int LieferantId
        {
            get => _lieferantId;
            set
            {
                _lieferantId = value;
                var sucheLieferant = _controller.Lieferanten.Where(x => x.LieferantId == _lieferantId).FirstOrDefault();

                if (sucheLieferant is not null)
                {
                    Lieferant = sucheLieferant;
                }
            }
        }
        public string? Ansprechpartner { get; set; }
        public int Lieferbedingung { get; set; }
        public int Zahlungsbedingung { get; set; }
        public DateTime Liefertermin { get; set; } = DateTime.Now.AddDays(1);
        public string Währung { get; set; } = String.Empty;
        /// <summary>
        /// Ruft einen Wert ab, der angibt, ob es sich bei der Bestellung um einen Abruf handelt oder nicht
        /// </summary>
        public bool Abrufbestellung { get; set; }
        /// <summary>
        /// Ruft einen Wert ab, der angibt, ob die Bestellung als Direktlieferung ausgeführt werden soll, oder nicht.
        /// </summary>
        public bool Direktlieferung { get; set; }
        public List<AuftragBestellenPosition> Positionen { get; } = new List<AuftragBestellenPosition>();

        
        public AuftragBestellenBestellung(AuftragBestellenController controller)
        {
            _controller = controller;
            Abrufbestellung = controller.Auftrag.BELE_L_ABRUF;
        }

        /// <summary>
        /// Fügt einen Arikel als neue Position zur <see cref="AuftragBestellenBestellung"/> hinzu.
        /// </summary>
        /// <param name="artikel"></param>
        /// <returns>
        /// Liefert bei erfolg das neue <see cref="AuftragBestellenPosition"/>-Objekt, ansonsten null.
        /// <para>Ein Artikel kann nur dann zur Bestellung hinzugefügt werden, wenn dieser in noch keiner anderen Bestellung enthalten ist und für die Eigenschaft <see cref="Lieferant"/> ein passender Lieferantenartikel gefunden werden konnte. Wenn <see cref="Lieferant"/> null zurückliefert, dann wird versucht automatisch den günstigsten Lieferanten zu ermitteln.</para>
        /// <para>Damit ein Lieferantenartikel gefunden wird, muss dieser über ausreichend Lagerbestand verfügen, oder in der Liste der LieferantenIds mit unbegrenzten Lagerbestand aufgeführt sein.</para>
        /// </returns>
        public async Task<AuftragBestellenPosition?> AddPositionAsync(AuftragBestellenArtikel artikel)
        {
            //Wir prüfen als erstes, ob der Artikel bereits in einer anderen Bestellung vorhanden ist
            foreach (var bestellung in _controller.Bestellungen.Where(x => x != this))
            {
                if (bestellung.Positionen.Where(x => x.SelectedArtikel == artikel).Any())
                {
                    return null;
                }
            }
            if (Lieferant is null)
            {

                // Wenn es noch keinen Lieferanten gibt, dann können wir den günstigsten bestimmen lassen
                var lieferantenArtikel = _controller.GetGünstigstenLieferantenArtikel(artikel);
                // Wenn wir keinen Lieferanten finden, dann können wir den Artikel auch nicht hinzufügen
                if (lieferantenArtikel is null)
                {
                    return null;
                }

                // Unabhängig vom günstigsten soll der Hauptlieferant bevorzugt werden
                var hauptlieferantenArtikel = _controller.GetHauptLieferantenArtikel(artikel);

                if (hauptlieferantenArtikel is not null)
                {
                    lieferantenArtikel = hauptlieferantenArtikel;
                }

                // Wir prüfen hier, dass der Lieferant in noch keiner anderen Bestellung enthalten ist.
                // Lieferant kann hier nicht null sein, da wir nur die selecten, wo Lieferant nicht null ist.
                var anderenBestellungenLieferantenIds = _controller.Bestellungen
                    .Where(x => x.Lieferant is not null && x != this)
                    .Select(x => x.Lieferant!.LieferantId).ToArray();

                if (lieferantenArtikel is not null && anderenBestellungenLieferantenIds.Contains(lieferantenArtikel.Lieferant.LieferantId))
                {
                    return null;
                }

                Lieferant = lieferantenArtikel?.Lieferant;
                if (Lieferant is not null)
                {
                    Lieferant.Ansprechpartner = await AnsprechpartnerLieferant.GetAnsprechpartnerAsync(Lieferant.LieferantId).ToArrayAsync();
                }
            }

            // Prüfen ob ein Artikel überhaupt hinzugefügt werden darf. 
            // Er darf nur dann hinzugefügt werden, wenn der Lieferant des Artikels auch in den vorherigen Artikeln enthalten ist
            if (Lieferant is not null)
            {
                var lieferantenIdsFürArtikel = _controller.GetLieferantenFürArtikel(artikel).Select(x => x.LieferantId).ToArray();
                if (!lieferantenIdsFürArtikel.Contains(Lieferant.LieferantId))
                {
                    return null;
                }

                var lfArtikel = _controller.GetLieferantenArtikel(artikel, Lieferant.LieferantId);
                if (lfArtikel is null)
                {
                    return null;
                }

                var neuePosition = new AuftragBestellenPosition(artikel, lfArtikel);

                if (neuePosition.Artikelnummer.StartsWith("SO-", StringComparison.OrdinalIgnoreCase))
                {
                    // Bei Sonderproduktionen gehen wir von einem Liefertermin ab 4 Wochen aus
                    neuePosition.Lieferdatum = DateTime.Now.AddDays(28);
                }

                Positionen.Add(neuePosition);
                _controller.ClearArtikelnummernInBestellungen();
                return neuePosition;
            }

            return null;
        }

        public void DeletePosition(AuftragBestellenPosition pos) => Positionen.Remove(pos);
    }
}
