using ArtikelUpdateOpencart.Models;
using Serilog;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Email;
using WK5.Core.Models;


namespace ArtikelUpdateOpencart
{
    internal static class Kundenabgleich
    {
        public static async Task RunAsync(MySqlController2 mySqlController, FbController2 fbController, EmailController emailController)
        {
            DataTable KundenTabelle = await fbController.SelectDataAsync("select KUND_A_NR, KUND_A_EMAIL, KUND_A_USTIDNR, KUND_A_PLZ, KUND_N_ZAHLUNG from KUNDEN WHERE KUND_L_SPERRE = 'N'");

            ZahlungsbedingungCollection zahlungsbedingungen = await Zahlungsbedingung.GetZahlungsbedingungenAsync(fbController);

            foreach (DataRow reihe in KundenTabelle.Rows)
            {
                string kundennummer = (reihe.Field<string>("KUND_A_NR") ?? String.Empty).Trim();
                Log.Logger.Information("Kundennummer: {kundennummer}", kundennummer);
                if (String.IsNullOrWhiteSpace(kundennummer))
                {
                    continue;
                }

                int KUND_N_ZAHLUNG = reihe.Field<int>("KUND_N_ZAHLUNG");
                Zahlungsbedingung? zahlungsbedingung = zahlungsbedingungen[KUND_N_ZAHLUNG];
                bool rechnungsKunde = zahlungsbedingungen.IstRechnung(KUND_N_ZAHLUNG);
                bool lastschriftKunde = zahlungsbedingungen.IstLastschrift(KUND_N_ZAHLUNG);

                // Scholz 06.04.2020 - Die Update Logik sollte Emails nach Domain prüfen
                string kundenEmail = reihe.Field<string>("KUND_A_EMAIL") ?? String.Empty;
                string domain = kundenEmail.Trim();
                try
                {
                    MailAddress mailAddress = new MailAddress(kundenEmail);
                    domain = mailAddress.Host.Trim();
                }
                catch (Exception ex)
                {
                    string[] parts = kundenEmail.Split('@');

                    domain = parts.Length > 1 ? parts[1] : kundenEmail;
                }


                string default_zahlart = "bank_transfer";

                if(zahlungsbedingung != null && !string.IsNullOrWhiteSpace(zahlungsbedingung.ZABD_A_CODE))
                {
                    default_zahlart = zahlungsbedingung.ZABD_A_CODE;
                }
                



                mySqlController.AddParameter("@customer_id", kundennummer);
                mySqlController.AddParameter("@RECHNUNG", rechnungsKunde ? 1 : 0);
                mySqlController.AddParameter("@DEFAULT_ZAHLART", default_zahlart);
                await mySqlController.QueryAsync($"update customer set customer_group_id = '5', auf_rechnung = @RECHNUNG, default_zahlart = @DEFAULT_ZAHLART where customer_id = @customer_id and email LIKE '%{domain}'");

                mySqlController.AddParameter("@KUNDENNUMMER", kundennummer);
                mySqlController.AddParameter("@LASTSCHRIFT", lastschriftKunde ? 1 : 0);
                await mySqlController.QueryAsync("INSERT INTO `direct_debit_payment` VALUES (@KUNDENNUMMER, @LASTSCHRIFT) ON DUPLICATE KEY UPDATE `direct_debit` = @LASTSCHRIFT");

                mySqlController.AddParameter("@customer_id", kundennummer);
                mySqlController.AddParameter("@email", kundenEmail);
                var obj = await mySqlController.FetchObjectAsync("select customer_id from customer where customer_id = @customer_id and email = @email");

                if (obj is not null)
                {
                    string ustId = reihe.Field<string>("KUND_A_USTIDNR") ?? String.Empty;
                    string plz = reihe.Field<string>("KUND_A_PLZ") ?? String.Empty;
                    ustId = ustId.Trim();
                    mySqlController.AddParameter("@USTID", ustId);
                    mySqlController.AddParameter("@customer_id", kundennummer);
                    mySqlController.AddParameter("@postcode", plz);
                    await mySqlController.QueryAsync("update address set tax_id = @USTID where customer_id = @customer_id and postcode = @postcode;");
                }
            }





            #region Händlerabgleich
            //Wenn ein Händler Händler ist tragen wir das in die W4 ein und dann daten wir das nach oben up!
            DataTable KDTab = await fbController.SelectDataAsync("SELECT KUND_A_NR, KUND_N_KUNDGRUPPE, KUND_A_USTIDNR, KUND_A_STEUERNR, KUND_A_EMAIL FROM KUNDEN WHERE KUND_N_KUNDGRUPPE = 2 OR KUND_N_KUNDGRUPPE = 3 OR KUND_N_KUNDGRUPPE = 4");
            int bearbeitet = 0;

            foreach (DataRow Reihe in KDTab.Rows)
            {
                bearbeitet++;
                Console.Write("[{0}/{1}] \r", bearbeitet, KDTab.Rows.Count);
                int kundengruppe = Reihe.Field<int>("KUND_N_KUNDGRUPPE");
                string kundennummer = Reihe.Field<string>("KUND_A_NR") ?? String.Empty;

#if TesteBesonderenHändler
                if (!kundennummer.Equals("26954", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
#endif

                if (String.IsNullOrWhiteSpace(kundennummer))
                {
                    continue;
                }

                string kundenEmail = Reihe.Field<string>("KUND_A_EMAIL") ?? String.Empty;
                string domain = kundenEmail.Trim();
                try
                {
                    MailAddress mailAddress = new MailAddress(kundenEmail);
                    domain = mailAddress.Host.Trim();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    string[] parts = kundenEmail.Split('@');

                    domain = parts.Length > 1 ? parts[1] : kundenEmail;
                }

                mySqlController.AddParameter("@customer_id", kundennummer);
                mySqlController.AddParameter("@email", kundenEmail);
                var obj = await mySqlController.FetchObjectAsync("select customer_id from customer where customer_id = @customer_id and email = @email");



                if (!GlobalConfig.Freemails.Contains(domain) || obj is not null)
                {

                    mySqlController.AddParameter("@customer_group_id", kundengruppe);
                    mySqlController.AddParameter("@customer_id", kundennummer);
                    mySqlController.AddParameter("@domain", $"%{domain}");


                    await mySqlController.QueryAsync("Update customer set approved = 1, customer_group_id = @customer_group_id WHERE customer_id = @customer_id;");

                    if (kundengruppe == 3)
                    {
                        string ustId = "bitte aktualisieren";
                        string KUND_A_USTIDNR = Reihe.Field<string>("KUND_A_USTIDNR") ?? String.Empty;
                        if (KUND_A_USTIDNR.Length < 8 && KUND_A_USTIDNR.Length > 0)
                        {
                            ustId = KUND_A_USTIDNR;
                        }

                        mySqlController.AddParameter("@USTID", ustId);
                        mySqlController.AddParameter("@customer_id", kundennummer);
                        await mySqlController.QueryAsync("Update address set tax_id = @USTID WHERE customer_id = @customer_id AND tax_id = '';");
                    }
                }
            }
            #endregion
        }
        public static async Task KundenRabatteSynchronisierenAsync(MySqlController2 mySqlController, FbController2 fbController, EmailController emailController)
        {
            List<FalscheKundenDaten> falscheKundenDaten = new List<FalscheKundenDaten>();

            //Rabatte vom Kunden auslesen (W4)
            //Erste alle KundenNummern aus dem Shop holen.
            DataTable onlineCustomerIds = await mySqlController.SelectDataAsync("SELECT distinct customer_id from customer");

            string customersString = String.Join(",", onlineCustomerIds.AsEnumerable().Select(x => x.Field<int>("customer_id")));


            //Rabatte aus W4 abfragen
            DataTable w4KundenRabatte = await fbController.SelectDataAsync(@"select 
KUND_A_NR, ARTI_A_NR, ARTI_N_EK, ARTI_N_VK1, ARTI_N_VK2, ARTI_N_VK3, ARTI_N_VK4, 
ARTI_N_VK5, KUSA_N_PREIS, KUSA_N_RABATT, KUND_N_PLVK, KUND_N_KUNDGRUPPE,ARTI_A_HERSTELLER 
from Kundensachnummer ks left
join ARTIKEL a on ks.KUSA_A_ARTNUMMEIG = a.ARTI_A_NR left
join KUNDEN k on ks.KUSA_A_KUNDE = k.KUND_A_NR
where (
(KUSA_N_PREIS IS NOT NULL AND KUSA_N_PREIS > 0) 
OR(KUSA_N_RABATT IS NOT NULL AND KUSA_N_RABATT > 0)
) 
AND KUSA_N_RABATT< 10
AND KUND_A_NR IN (" + customersString + @")
AND ARTI_L_INAKTIV = 'N'");

            //Online Rabatte erst löschen, damit alte gelöscht werden
            await mySqlController.QueryAsync("TRUNCATE TABLE customer_price");

            // Artikel einlesen, bei denen VK günstiger sein kann, als der EK
            List<string> ignoreEKTeurerAlsVK = await FileIO.LeseListe(Path.Combine(GlobalConfig.W4TmpFolder, "IgnoreEKTeurerAlsVK.txt"));

            foreach (DataRow rabatt in w4KundenRabatte.Rows)
            {
                //Kundenpreis berechnen - Artikel VK - Rabatt. (VK1 = Firma, VK2 = Händler) Gruppen: 2 Firma , 4 Behörde, 5 Firma EU
                decimal kundenPreis = 0;
                // Als erstes parsen, damit Programm nicht abstürzt bei eventuellen Convert Fehlern

                decimal ARTI_N_VK1 = rabatt.Field<decimal>("ARTI_N_VK1");
                decimal ARTI_N_VK2 = rabatt.Field<decimal>("ARTI_N_VK2");
                decimal KUSA_N_PREIS = rabatt.Field<decimal>("KUSA_N_PREIS");
                decimal KUSA_N_RABATT = rabatt.Field<decimal>("KUSA_N_RABATT");
                decimal ARTI_N_EK = rabatt.Field<decimal>("ARTI_N_EK");

                string kundennummer = rabatt.Field<string>("KUND_A_NR") ?? throw new ArgumentNullException("Kundennummer darf nicht null sein", "KUND_A_NR");
                string artikelnummer = rabatt.Field<string>("ARTI_A_NR")?.ToUpper() ?? throw new ArgumentNullException("Artikelnummer darf nicht null sein", "ARTI_A_NR"); ;

                decimal DEFAULT_VK = 0;

                int KUND_N_KUNDGRUPPE = rabatt.Field<int>("KUND_N_KUNDGRUPPE");

                if (new List<int>() { 2, 4, 5 }.Contains(KUND_N_KUNDGRUPPE))
                {
                    DEFAULT_VK = ARTI_N_VK1;
                }
                else // Wiederverkäufer Preis
                {
                    DEFAULT_VK = ARTI_N_VK2;
                }

                if (KUSA_N_RABATT > 0)
                {
                    kundenPreis = DEFAULT_VK - (DEFAULT_VK / 100 * KUSA_N_RABATT);
                }

                if (kundenPreis <= 0.0m)
                {
                    continue;
                }


                //die einzelnen Rabatte Online eintragen                    
                //ArtikelNr aus dem Shop holen
                mySqlController.AddParameter("@MODEL", artikelnummer);
                var product_id = await mySqlController.FetchObjectAsync("SELECT product_id from product where UPPER(model) = @MODEL");


                //Rabatte im Shop eintragen - customer_id;product_id,price                             

                if (product_id != null)
                {
                    string hersteller = rabatt.Field<string>("ARTI_A_HERSTELLER") ?? String.Empty;
                    decimal einkaufspreis = ARTI_N_EK;
                    if (hersteller.Equals("PRIMERA", StringComparison.OrdinalIgnoreCase))
                    {
                        // 01.09.2020 - Bei Primera brauchen wir den Min Lieferantenpreis-Rabatt
                        fbController.AddParameter("@ARLI_A_ARTIKELNR", artikelnummer);
                        var minPreisObj = await fbController.FetchObjectAsync("SELECT MIN(ARLI_N_PREIS * (1 - ARLI_N_RABATT / 100)) FROM LIEFERANTENARTIKEL WHERE ARLI_A_ARTIKELNR = @ARLI_A_ARTIKELNR");

                        if (minPreisObj != null)
                        {
                            if (decimal.TryParse(minPreisObj.ToString(), out decimal minEkPreis) && minEkPreis > 0)
                            {
                                einkaufspreis = minEkPreis;
                            }

                        }
                    }

                    if (kundenPreis > einkaufspreis * 1.03m // Ley: Mindestens 3% müssen wir verdienen
                        && (kundenPreis < DEFAULT_VK || ignoreEKTeurerAlsVK.Contains(artikelnummer)))
                    {
                        mySqlController.AddParameter("@KUND_A_NR", kundennummer);
                        mySqlController.AddParameter("@PRODUCT_ID", product_id);
                        mySqlController.AddParameter("@KUNDEN_PREIS", kundenPreis);
                        await mySqlController.QueryAsync("INSERT IGNORE INTO customer_price VALUES (@KUND_A_NR,@PRODUCT_ID,@KUNDEN_PREIS)");
                    }
                    else
                    {
                        falscheKundenDaten.Add(new FalscheKundenDaten(kundennummer, artikelnummer));
                    }
                }
            }


            if (falscheKundenDaten.Count > 0)
            {
                // Per E-Mail benachrichtigen
                falscheKundenDaten.Sort();

                StringBuilder sb = new StringBuilder();
                // kundenPreis > ARTI_N_EK * 1.03 && kundenPreis < DEFAULT_VK
                sb.AppendLine("Der errechnete Kunden-Rabatt für die Artikel ist entweder kleiner als der EK oder höher als der standardmäßige VK.<br />");
                sb.AppendLine("<br />");
                sb.AppendLine($"Arbeitsanweisung: <a href=\"http://wikis.local/wiki/doku.php/wk5:stammdaten:kunden:kundenrabatte\">http://wikis.local/wiki/doku.php/wk5:stammdaten:kunden:kundenrabatte</a><br />");
                sb.AppendLine("<br />");
                sb.AppendLine("<br />");
                foreach (FalscheKundenDaten daten in falscheKundenDaten)
                {
                    sb.AppendLine($"Kundennummer: <a href=\"http://wk5.local/Kunden/{daten.Kundennummer}\">{daten.Kundennummer}</a> ArtikelNr: <a href=\"http://wk5.local/Artikel/{daten.Artikelnummer}\">{daten.Artikelnummer}</a><br />");
                }

                string kdnNr = "";

                if (falscheKundenDaten.Count == 1)
                {
                    kdnNr = $" : {falscheKundenDaten[0].Kundennummer} - {falscheKundenDaten[0].Artikelnummer}";
                }

                await emailController.SendenAsync(
                    empfängerEmail: GlobalConfig.EmailShopverwalter,
                    betreff: $"Kundenartikel mit falschen Preisen - {kdnNr}",
                    body: sb.ToString()
                );

            }

        }
    }
}
