using KarleyLibrary.Attributes;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WK5.Core.Models
{
    public class Bestellung
    {
        private string _kund_a_name1 = String.Empty;
        private string _kund_a_name2 = String.Empty;
        #region Datenbankfelder Tabelle BESTELLUNGEN
        public string? BEST_A_ANGEBOTNR { get; set; } = String.Empty;
        public string? BEST_A_BESTAET_NR_LIEF { get; set; }
        public string? BEST_A_DRUCKZEICH { get; set; }
        public string BEST_A_FORMULAR { get; set; } = String.Empty;
        public string BEST_A_KOMMISSION { get; set; } = String.Empty;
        public string? BEST_A_LIEFERKUNDE { get; set; } = String.Empty;
        public int BEST_A_LIEFERKUNDELA { get; set; }
        public string? BEST_A_PARTNER { get; set; } = String.Empty;
        public string? BEST_A_RABATTBEZ { get; set; }
        [CompareField("BEST_A_WAEHRUNG")]
        public string Währung { get; set; } = String.Empty;
        public string? BEST_A_ZEICHEN { get; set; }
        public string? BEST_B_ENDTEXT { get; set; }
        public string? BEST_B_FUSSTEXT { get; set; }
        public string? BEST_B_KOPFTEXT { get; set; }
        public string? BEST_B_NOTIZ { get; set; }
        public DateTime BEST_D_ANGEBOTVOM { get; set; }
        public DateTime BEST_D_ANGEMAHNTAM { get; set; }
        [CompareField("BEST_D_DATE")]
        public DateTime Belegdatum { get; set; }
        public DateTime BEST_D_DRUCKDATUM { get; set; }
        public DateTime BEST_D_ERLEDIGTAM { get; set; }
        public DateTime BEST_D_LIEFERANMAHNUNG { get; set; }
        public DateTime BEST_D_LIEFTERMIN { get; set; }
        public DateTime BEST_D_VERSENDET { get; set; }
        public DateTime BEST_D_BESTAETIGT { get; set; }
        public bool BEST_L_BESTAETIGT { get; set; }
        public bool BEST_L_ERLEDIGT { get; set; }
        public bool BEST_L_VERSENDET { get; set; }
        public int BEST_N_AB_NR { get; set; }
        public int BEST_N_ANLAGEUSER { get; set; }
        public int BEST_N_BESTAETIGTUSER { get; set; }
        public int BEST_N_FILIALE { get; set; }
        public int BEST_N_LASTUSER { get; set; }
        [CompareField("BEST_N_LIEFERUNG")]
        public int LieferbedingungId { get; set; }
        [CompareField("BEST_N_LIEFNR")]
        public int LieferantenId { get; set; }
        [CompareField("BEST_N_NR")]
        public int Bestellnummer { get; set; }
        public int BEST_N_PROJEKT_NR { get; set; }
        public int BEST_N_SPERRUSERID { get; set; }
        public int BEST_N_VERSENDET_USER { get; set; }
        public int BEST_N_ZAHLUNG { get; set; }
        public decimal BEST_N_BRUTTO { get; set; }
        [CompareField("BEST_N_FRACHT")]
        public decimal Versandkosten { get; set; }
        public decimal BEST_N_KURS { get; set; }
        public decimal BEST_N_MWST { get; set; }
        public decimal BEST_N_NETTO { get; set; }
        public decimal BEST_N_RABATT { get; set; }
        public decimal BEST_N_RABATTPROZ { get; set; }
        public decimal BEST_N_RABATTZUSATZ { get; set; }
        [CompareField("BEST_N_VERPACKUNG")]
        public decimal Verpackungskosten { get; set; }
        [CompareField("BEST_N_VERSICHERUNG")]
        public decimal Versicherungskosten { get; set; }
        public decimal BEST_N_ZUSATZKOST { get; set; }
        public DateTime BEST_TIMESTAMP { get; set; }

        [CompareField("BEST_N_MINDERMENGENZUSCHLAG")]
        public decimal Mindermengenzuschlag { get; set; }

        /// <summary>
        /// Ruft das Flag für Direktlieferung des Auftrages ab.
        /// </summary>
        public bool WK5_BELE_L_DIREKTLIEFERUNG { get; set; }
        public decimal Zusatzkosten => Versicherungskosten + Verpackungskosten + Versandkosten + Mindermengenzuschlag;

        public bool BEST_L_FRACHTFREI { get; set; }

        #endregion
        #region Datenbankfelder Tabelle LIEFERANTEN
        public string LIEF_A_NAME1 { get; set; } = String.Empty;
        public string? LIEF_A_NAME2 { get; set; }
        #endregion
        #region Datenbankfelder Tabelle Kunden
        public string KUND_A_NAME1 { get => _kund_a_name1; set => _kund_a_name1 = value ?? String.Empty; }
        public string KUND_A_NAME2 { get => _kund_a_name2; set => _kund_a_name2 = value ?? String.Empty; }
        #endregion
        public bool BestellungExistiert { get; set; }



        public bool Direktlieferung => !String.IsNullOrWhiteSpace(BEST_A_LIEFERKUNDE);

        [CompareField("BEST_L_ABRUF")]
        public bool IstAbrufbestellung { get; set; }
        public Task<Lieferanschrift?> GetLieferanschriftAsync() => Lieferanschrift.GetLieferanschriftAsync(BEST_A_LIEFERKUNDE, BEST_A_LIEFERKUNDELA);

        public List<Bestellposition> Positionen { get; private set; } = new List<Bestellposition>();

        public Bestellung()
        {
            int addDays = 1;
            if (DateTime.Today.DayOfWeek is DayOfWeek.Friday)
            {
                addDays = 3;
            }

            if (DateTime.Today.Hour >= 14 && addDays is not 3)
            {
                addDays = 2;
            }

            BEST_D_LIEFTERMIN = DateTime.Now.AddDays(addDays);
        }

        private Bestellung(int BEST_N_NR)
        {
            this.Bestellnummer = BEST_N_NR;
        }



        public static async Task<Bestellung?> GetBestellungAsync(int BEST_N_NR, FbController2 fbController2)
        {
            var bestellung = new Bestellung(BEST_N_NR);
            await bestellung.InitializeAsync(fbController2);
            return bestellung.BestellungExistiert ? bestellung : null;
        }

        public async Task InitializeAsync(FbController2 fbController2)
        {
            fbController2.AddParameter("@BEST_N_NR", Bestellnummer);
            var bestellungRow = await fbController2.SelectRowAsync(@"SELECT 
LIEF_A_NAME1, LIEF_A_NAME2, KUND_A_NAME1, KUND_A_NAME2, B.*, WK5_BELE_L_DIREKTLIEFERUNG
FROM BESTELLUNGEN B
LEFT JOIN LIEFERANTEN LF ON B.BEST_N_LIEFNR = LF.LIEF_N_NR
LEFT JOIN KUNDEN K ON B.BEST_A_LIEFERKUNDE = K.KUND_A_NR
LEFT JOIN BELEGE BE ON (BE.BELE_A_TYP = 'AU' AND BE.BELE_N_NR = B.BEST_N_AB_NR)
WHERE BEST_N_NR = @BEST_N_NR");

            if (bestellungRow is not null)
            {
                BestellungExistiert = true;
                ObjectErweiterung.DataRowZuObjekt(this, bestellungRow);

                // Positionen laden
                fbController2.AddParameter("@BEPO_N_BESTNR", Bestellnummer);
                fbController2.AddParameter("@ARLI_N_LIEFNR", LieferantenId);
                var data = await fbController2.SelectDataAsync(@"SELECT 
BP.*, 
ARLI_N_MINDESTABNAHME AS MINDESTABNAHME,
ARLI_L_NURVIELFACHES
FROM BESTELLUNGEN_POS BP
LEFT JOIN LIEFERANTENARTIKEL LFA ON LFA.ARLI_N_LIEFNR = @ARLI_N_LIEFNR AND ARLI_A_ARTIKELNR = BP.BEPO_A_ARTIKELNR
WHERE BEPO_N_BESTNR = @BEPO_N_BESTNR ORDER BY BEPO_N_POS");

                foreach (DataRow posRow in data.Rows)
                {
                    Positionen.Add(ObjectErweiterung.DataRowZuObjekt(new Bestellposition(), posRow));
                }
            }
        }

        public async IAsyncEnumerable<Bestellung> GetBestellungenMitArtikelAsync(string Artikelnummer, FbController2 fbController)
        {
            string sql = "SELECT BEPO_N_BESTNR FROM BESTELLUNGEN_POS WHERE BEPO_A_ARTIKELNR = @ARTIKELNUMMER";
            fbController.AddParameter("@ARTIKELNUMMER", Artikelnummer);
            DataTable data = await fbController.SelectDataAsync(sql);
            foreach (DataRow row in data.Rows)
            {
                int bestnr = row.Field<int>("BEPO_N_BESTNR");
                Bestellung? best = await GetBestellungAsync(bestnr, fbController);
                if (best is not null)
                {
                    yield return best;
                }
            }
        }

        public decimal GetNetto() => Positionen.Sum(x => x.BEPO_N_MENGE * x.BEPO_N_PREIS);
        public decimal GetRabatt() => GetNetto() - GetNettoBetrag() + Zusatzkosten;
        public decimal GetNettoBetrag()
        {
            decimal netto = Zusatzkosten;

            foreach (var pos in Positionen)
            {
                netto += pos.BEPO_N_MENGE * pos.PreisMitRabatt;
            }
            return netto;
        }

        public decimal GetMwst(bool berechnen, Mehrwertsteuer? versandMehrwertsteuer)
        {
            if (!berechnen)
            {
                return 0;
            }

            decimal mwst = 0;
            foreach (var pos in Positionen)
            {
                mwst += pos.BEPO_N_MENGE * pos.PreisMitRabatt * pos.BEPO_N_MWSTPROZ / 100;
            }

            if (versandMehrwertsteuer is not null)
            {
                mwst += Zusatzkosten * versandMehrwertsteuer.MWST_N_PROZENT / 100;
            }

            return mwst;
        }
        public decimal GetBruttoBetrag(bool berechnen, Mehrwertsteuer? versandMehrwertsteuer) => GetNettoBetrag() + GetMwst(berechnen, versandMehrwertsteuer);

        public async Task<string?> GetEmailRecipient()
        {
            using FbController2 fbController = new FbController2();

            string? empfängerEmail = null;
            var ansprechpartner = await AnsprechpartnerLieferant.GetAnsprechpartnerByNameAsync(LieferantenId, BEST_A_PARTNER);

            if (ansprechpartner is not null)
            {
                if (!String.IsNullOrWhiteSpace(ansprechpartner.LIEP_A_EMAIL))
                {
                    empfängerEmail = ansprechpartner.LIEP_A_EMAIL;
                }

            }

            if (String.IsNullOrWhiteSpace(empfängerEmail))
            {
                var lieferant = await WK5.Core.Models.Lieferant.GetLieferantAsync(LieferantenId) ?? throw new ArgumentNullException($"Lieferant {LieferantenId} konnte nicht gefunden werden.");

                if (!String.IsNullOrWhiteSpace(lieferant.LIEF_A_EMAIL))
                {
                    empfängerEmail = lieferant.LIEF_A_EMAIL;
                }
            }

            return empfängerEmail;
        }

        public async Task<string> GetEmailTextAsync(string emailVon)
        {
            using FbController2 fbController = new FbController2();

            string anrede = "Sehr geehrte Damen und Herren,";
            string ansprechpartnerName = String.Empty;
            var ansprechpartner = await AnsprechpartnerLieferant.GetAnsprechpartnerByNameAsync(LieferantenId, BEST_A_PARTNER);

            var lieferant = await Lieferant.GetLieferantAsync(LieferantenId) ?? throw new ArgumentNullException($"Lieferant {LieferantenId} konnte nicht gefunden werden.");

            if (ansprechpartner is not null)
            {
                anrede = ansprechpartner.LIEP_A_ANREDE ?? anrede;
                ansprechpartnerName = ansprechpartner.LIEP_A_NAME;
            }

            StringBuilder bodyBuilder = new StringBuilder();


            if (anrede.Equals("Sehr geehrte Damen und Herren,", StringComparison.OrdinalIgnoreCase))
            {
                bodyBuilder.AppendLine($"{anrede}<br /><br />");
            }
            else
            {
                bodyBuilder.AppendLine($"{anrede} {ansprechpartnerName},<br />");
            }

            if (!WK5_BELE_L_DIREKTLIEFERUNG)
            {
                // Die Ware geht an uns
                if (GlobalConfig.DachLächer.Contains(lieferant.LIEF_A_LAND))
                {
                    bodyBuilder.AppendLine(@"anbei finden Sie unsere Bestellung für Ihre Produkte. Bitte prüfen Sie die Bestellung und teilen uns in einer Auftragsbestätigung den voraussichtlichen Liefertermin mit.<br /><br />Vielen Dank für Ihre Kooperation.");
                }
                else
                {
                    bodyBuilder.AppendLine(@"attached you will find our order for your products. Please check the order and let us know the expected delivery date in an order confirmation.<br /><br />Thank you for your cooperation.");
                }
            }
            else
            {
                // Direkt an den Kunden
                if (GlobalConfig.DachLächer.Contains(lieferant.LIEF_A_LAND))
                {
                    bodyBuilder.AppendLine("anbei finden Sie unsere Bestellung für Ihre Produkte nebst Warenbegleitschein zur direkten Auslieferung an unseren Kunden. Falls Sie unser Briefpapier bereits in Ihrer Warenwirtschaft hinterlegt haben, nutzen Sie gerne dieses. Bitte prüfen Sie die Bestellung und teilen uns in einer Auftragsbestätigung den voraussichtlichen Liefertermin mit.<br /><br />Vielen Dank für Ihre Kooperation.");
                }
                else
                {
                    bodyBuilder.AppendLine("Attached you will find our order for your products together with the goods accompanying slip for direct delivery to our customer. If you have already stored our goods accompanying slip in your ERP system, please feel free to use it. Please check the order and let us know the expected delivery date in an order confirmation.<br /><br />Thank you for your cooperation.");
                }
            }


            bodyBuilder.AppendLine("<br />");
            if (GlobalConfig.DachLächer.Contains(lieferant.LIEF_A_LAND))
            {
                bodyBuilder.AppendLine("Mit freundlichen Grüßen<br />");
            }
            else
            {
                bodyBuilder.AppendLine("Best regards<br />");
            }
            bodyBuilder.AppendLine($"{emailVon}<br />");
            bodyBuilder.AppendLine(GlobalConfig.Configuration.FirmenDaten.ImpressumHTML());

            return bodyBuilder.ToString();
        }

        public async Task<string> GetEmailTextFürAbrufAsync(string emailVon, BestellungAbruf abruf, Bestellung bestellung)
        {
            using FbController2 fbController = new FbController2();

            string anrede = "Sehr geehrte Damen und Herren,";
            string ansprechpartnerName = String.Empty;
            var ansprechpartner = await AnsprechpartnerLieferant.GetAnsprechpartnerByNameAsync(LieferantenId, BEST_A_PARTNER);

            var lieferant = await Lieferant.GetLieferantAsync(LieferantenId) ?? throw new ArgumentNullException($"Lieferant {LieferantenId} konnte nicht gefunden werden.");

            if (ansprechpartner is not null)
            {
                anrede = ansprechpartner.LIEP_A_ANREDE ?? anrede;
                ansprechpartnerName = ansprechpartner.LIEP_A_NAME;
            }

            StringBuilder bodyBuilder = new StringBuilder();


            if (anrede.Equals("Sehr geehrte Damen und Herren,", StringComparison.OrdinalIgnoreCase))
            {
                bodyBuilder.AppendLine($"{anrede}<br /><br />");
            }
            else
            {
                bodyBuilder.AppendLine($"{anrede} {ansprechpartnerName},<br />");
            }



            if (GlobalConfig.DachLächer.Contains(lieferant.LIEF_A_LAND))
            {
                bodyBuilder.AppendLine($"Ihre Auftragsbestätigungsnummer: {bestellung.BEST_A_BESTAET_NR_LIEF} <br />");
                bodyBuilder.AppendLine(@$"zu unserer Abrufbestellung {bestellung.Bestellnummer} möchten wir folgende Produkte abrufen:<br />");
                foreach (var pos in abruf.Positionen)
                {
                    var tmp = bestellung.Positionen.First(x => x.BEPO_N_POSID == pos.PosId);
                    if(!string.IsNullOrWhiteSpace(tmp.BEPO_A_BESTELLNUMMER) && !tmp.BEPO_A_BESTELLNUMMER.Equals(pos.Artikelnummer))
                    {
                        bodyBuilder.AppendLine(@$"Bestellnummer: {tmp.BEPO_A_BESTELLNUMMER}; Unsere Artikelnummer: {pos.Artikelnummer}; Menge: {pos.Menge}; Noch Offen: {tmp.BEPO_N_MENGE - tmp.BEPO_N_LIEFERMENGE}<br />");
                    }
                    else
                    {
                        bodyBuilder.AppendLine(@$"Bestellnummer: {pos.Artikelnummer}; Unsere Artikelnummer: {pos.Artikelnummer}; Menge: {pos.Menge}; Noch Offen: {tmp.BEPO_N_MENGE - tmp.BEPO_N_LIEFERMENGE}<br />");
                    }
                }

                bodyBuilder.AppendLine("<br />");
                bodyBuilder.AppendLine("Wir bitten um eine Bestätigung samt Sendungsnummer.<br />");
                bodyBuilder.AppendLine("Die Lieferung soll an die abgemachte Adresse erfolgen.");
            }
            else
            {
                bodyBuilder.AppendLine($"Your order confirmation number: {bestellung.BEST_A_BESTAET_NR_LIEF} <br />");
                bodyBuilder.AppendLine(@$"We would like to call off the following products for our call-off order {bestellung.Bestellnummer}:<br />");
                foreach (var pos in abruf.Positionen)
                {
                    var tmp = bestellung.Positionen.First(x => x.BEPO_N_POSID == pos.PosId);
                    if (!string.IsNullOrWhiteSpace(tmp.BEPO_A_BESTELLNUMMER) && !tmp.BEPO_A_BESTELLNUMMER.Equals(pos.Artikelnummer))
                    {
                        bodyBuilder.AppendLine(@$"Art-No.: {tmp.BEPO_A_BESTELLNUMMER}; Our Art-No.: {pos.Artikelnummer}; Quantity: {pos.Menge}; Still Open: {tmp.BEPO_N_MENGE - tmp.BEPO_N_LIEFERMENGE}<br />");
                    }
                    else
                    {
                        bodyBuilder.AppendLine(@$"Art-No.: {pos.Artikelnummer}; Our Art-No.: {pos.Artikelnummer}; Quantity: {pos.Menge}; Still Open: {tmp.BEPO_N_MENGE - tmp.BEPO_N_LIEFERMENGE}<br />");
                    }
                }

                bodyBuilder.AppendLine("<br />");
                bodyBuilder.AppendLine("We ask for a confirmation including the shipment number.<br />");
                bodyBuilder.AppendLine("Delivery should be made to the agreed address.");
            }
            
            



            bodyBuilder.AppendLine("<br /><br />");
            if (GlobalConfig.DachLächer.Contains(lieferant.LIEF_A_LAND))
            {
                bodyBuilder.AppendLine("Mit freundlichen Grüßen<br />");
            }
            else
            {
                bodyBuilder.AppendLine("Best regards<br />");
            }
            bodyBuilder.AppendLine($"{emailVon}<br />");
            bodyBuilder.AppendLine(GlobalConfig.Configuration.FirmenDaten.ImpressumHTML());

            return bodyBuilder.ToString();
        }
    }
}