using FluentFTP;
using Serilog.Core;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Services;

namespace KarleyUpdate
{
    internal class Bereinigung
    {
        private readonly Logger _logger;
        private readonly EmailController _emailController;
        public Bereinigung(Logger logger)
        {
            _logger = logger;
            _emailController = new EmailController();

        }
        /// <summary>
        /// Startet die Bereinigung
        /// <para>
        /// Diese Methode ist das Equivalent zum alten ArtikelUpdateOpencart "bereinigung"
        /// </para>
        /// </summary>
        public async Task RunAsync()
        {
            using FbController2 fbController = new FbController2();
            _logger.Information("Starte Bereinigung");

            await Wk5BereinigungAsync(fbController);
            await KundensperrenBereinigungAsync(fbController);
            await PreisgruppenBereinigenAsync(fbController);
            await ArtikelOhneLieferantenBereinigungAsync(fbController);
            await PreislistenUpdateAsync();
            await MachMichKostenstelleAsync();
            await Wk5OutputAsync(fbController);
            await Wk5UploadBereinigungAsync();
            await DokumentenablageBereinigenAsync(fbController);
            await ParseTelefonnummernAsync(fbController);
            await CheckInaktiveArtikelMitBestandAsync(fbController);

            await OnlineBereinigungAsync();
            _logger.Information("Bereinigung erfolgreich beendet.");

        }
        /// <summary>
        /// Führt eine generelle Bereinigung der WK5 durch.
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task Wk5BereinigungAsync(FbController2 fbController)
        {
            // Lagerführung korrigieren
            try
            {
                var artikelOhneLagerführung = await FileIO.LeseListe(@"\\srv01\Daten\W4\tmp\artikel_ohne_lagerfuehrung.txt");
                await fbController.QueryAsync($"UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'Y' WHERE ARTI_A_NR NOT IN('{String.Join("','", artikelOhneLagerführung)}') AND ARTI_A_NR NOT IN(SELECT BUNDLE_A_ARTINR FROM BUNDLES)");
                await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'Y' WHERE ARTI_L_INAKTIV = 'Y'");
                await fbController.QueryAsync($"UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'N' WHERE ARTI_A_NR IN('{String.Join("','", artikelOhneLagerführung)}') OR ARTI_A_NR IN(SELECT BUNDLE_A_ARTINR FROM BUNDLES)");
                await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'N' WHERE ARTI_L_DIENSTLEIST = 'Y'");

            }
            catch (Exception ex)
            {
                await EmailController.FehlerMailSendenAsync(
                    betreff: "#KARLEY_UPDATE_BEREINIGUNG_1",
                    body: $"Fehler beim bereinigen der Artikel mit und ohne Lagerführung.{ex.Message}"
                );
            }


            //Irgendein Kunde war mal auf USD ... damit es da keine Fehler gibt einfach zurück setzen
            await fbController.QueryAsync("UPDATE KUNDEN SET KUNDEN.KUND_A_WAEHRUNG = 'EUR'");

            //Setzt für die richtigen Provisionberechnungen die richtigen Vertreter
            // Die Abfrage braucht sehr lange. Ggf. anpassen, sodass es nur noch für x Monate geschieht?
            await fbController.QueryAsync("update belege set bele_n_vertreter = (select kund_n_vertretnumm  from kunden where kund_a_nr = bele_a_kundennr)");

            //Sicherstellen, das wir alle Artikel mit MwSt. verkaufen
            await fbController.QueryAsync("update ARTIKEL set ARTI_N_MWSTKENNUNG = 1");

            // Sicherstellen, dass Directshop Artikel auch über einen Preis verfügen
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_N_VK5 = ARTI_N_VK1 WHERE ARTI_L_INTERNET = 'Y' AND ARTI_N_VK5 = 0");

            // LEY 30.03.2020 -> Wenn ein Mitarbeiter vergisst ein Kundenlimit zu setzen, wird das automatisch auf 100EUR gesetzt. Sicherheitsmaßnahme gegen Corona Zahlungsausfälle 
            await fbController.QueryAsync("UPDATE KUNDEN SET KUND_N_KREDITLIMIT = 100 WHERE KUND_N_ZAHLUNG IN (10, 11, 12, 13, 14, 15, 16, 17, 18, 25, 26, 27, 28, 29, 33, 34, 35) AND KUND_N_KREDITLIMIT = 0");

            // Klein 07.05.2020 --> WK5_AUFTRAGSFREIGABE muss bereinigt werden, da manuell fortgeführte Aufträge ansonsten in der Tabelle weiterhin existieren
            await fbController.QueryAsync(@"DELETE FROM WK5_AUFTRAGSFREIGABE WHERE FREI_N_BELENR NOT IN(SELECT BELE_N_NR FROM BELEGE WHERE EXISTS ( SELECT BPOS_N_NR  FROM BELEGPOS WHERE  BPOS_N_MENGE > 0 AND  BPOS_N_MENGE > BPOS_N_MENGEGELIEF  AND BPOS_N_NR = BELE_N_NR AND BPOS_A_TYP = 'AU') AND BELE_L_ERLEDIGT = 'N' AND BELE_A_TYP = 'AU')");


            // Wir geben Belege, Kunden, Bestellungen und Zugänge wieder zum bearbeiten frei, sollte mal was schief gelaufen sein
            await fbController.QueryAsync("UPDATE BELEGE SET BELE_N_SPERRUSERID = NULL");
            _logger.Information("Belege freigegeben...");
            await fbController.QueryAsync("UPDATE KUNDEN SET KUND_N_SPERRUSERID = NULL");
            _logger.Information("Kunden freigegeben...");
            await fbController.QueryAsync("UPDATE BESTELLUNGEN SET BEST_N_SPERRUSERID = NULL");
            _logger.Information("Bestellungen freigegeben...");
            await fbController.QueryAsync("UPDATE ZUGAENGE SET ZUGA_N_SPERRUSERID = NULL");
            _logger.Information("Zugänge freigegeben...");

            // Anfrage Artikel festlegen
            // Wir setzen bei allen Artikel Anfrageartikel = Y, die ausschließlich Lieferanten haben, die nicht automatisch importiert werden
            // Einzige Ausnahme ist DTM (70002)
            await fbController.QueryAsync(@"UPDATE ARTIKEL SET WK5_ARTI_L_ANFRAGEARTIKEL = 'Y' WHERE ARTI_L_INAKTIV = 'N' AND ARTI_A_NR IN
(
    SELECT ARLI_A_ARTIKELNR
    FROM 
    (
    SELECT 
        ARLI_A_ARTIKELNR,
        (
            SELECT COUNT(*) AS ANZAHL_MIT_IMPORT FROM LIEFERANTENARTIKEL LFA
            INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
            WHERE L.LIEF_WK5_L_AUTOIMPORT = 'Y' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        ),
        (
            SELECT COUNT(*) AS ANZAHL_OHNE_IMPORT FROM LIEFERANTENARTIKEL LFA
            INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
            WHERE L.LIEF_WK5_L_AUTOIMPORT = 'N' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        )
        FROM LIEFERANTENARTIKEL LFA2 
        WHERE NOT EXISTS(SELECT 1 FROM LIEFERANTENARTIKEL LFA1 WHERE LFA1.ARLI_N_LIEFNR = 70002 AND LFA1.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR)
        GROUP BY LFA2.ARLI_A_ARTIKELNR 
        having 
        (
            SELECT COUNT(*) AS ANZAHL_MIT_IMPORT FROM LIEFERANTENARTIKEL LFA
                INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
                WHERE L.LIEF_WK5_L_AUTOIMPORT = 'Y' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        ) = 0
    )
)");

            // Im gleichen Zug müssen wir auch Anfrageartikel entfernen, bei denen die einen automatischen Lieferanten haben
            await fbController.QueryAsync(@"UPDATE ARTIKEL SET WK5_ARTI_L_ANFRAGEARTIKEL = 'N' WHERE ARTI_L_INAKTIV = 'N' AND ARTI_A_NR IN
(
    SELECT ARLI_A_ARTIKELNR
    FROM 
    (
    SELECT 
        ARLI_A_ARTIKELNR,
        (
            SELECT COUNT(*) AS ANZAHL_MIT_IMPORT FROM LIEFERANTENARTIKEL LFA
            INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
            WHERE L.LIEF_WK5_L_AUTOIMPORT = 'Y' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        ),
        (
            SELECT COUNT(*) AS ANZAHL_OHNE_IMPORT FROM LIEFERANTENARTIKEL LFA
            INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
            WHERE L.LIEF_WK5_L_AUTOIMPORT = 'N' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        )
        FROM LIEFERANTENARTIKEL LFA2 
        WHERE NOT EXISTS(SELECT 1 FROM LIEFERANTENARTIKEL LFA1 WHERE LFA1.ARLI_N_LIEFNR = 70002 AND LFA1.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR)
        GROUP BY LFA2.ARLI_A_ARTIKELNR 
        having 
        (
            SELECT COUNT(*) AS ANZAHL_MIT_IMPORT FROM LIEFERANTENARTIKEL LFA
                INNER JOIN LIEFERANTEN L ON L.LIEF_N_NR = LFA.ARLI_N_LIEFNR
                WHERE L.LIEF_WK5_L_AUTOIMPORT = 'Y' AND LFA.ARLI_A_ARTIKELNR = LFA2.ARLI_A_ARTIKELNR
        ) > 0
    )
)");
            _logger.Information("Anfrageartikel angepasst...");

            // E-Mail Adressen bereinigen
            await fbController.QueryAsync("UPDATE KUNDEN SET KUND_A_EMAIL = REPLACE(KUND_A_EMAIL, ' ','') WHERE COALESCE(KUND_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE ANSPRECHPARTNER SET PART_A_EMAIL = REPLACE(PART_A_EMAIL, ' ','') WHERE COALESCE(PART_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE LIEFERANSCHRIFTEN SET KULA_A_EMAIL = REPLACE(KULA_A_EMAIL, ' ','') WHERE COALESCE(KULA_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE KUNDENRECHNANSCHR SET KURE_A_EMAIL = REPLACE(KURE_A_EMAIL, ' ','') WHERE COALESCE(KURE_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE LIEFERANTEN SET LIEF_A_EMAIL = REPLACE(LIEF_A_EMAIL, ' ','') WHERE COALESCE(LIEF_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE LIEFRECHNANSCHR SET LIRE_A_EMAIL = REPLACE(LIRE_A_EMAIL, ' ','') WHERE COALESCE(LIRE_A_EMAIL, '') LIKE '% %'");
            await fbController.QueryAsync("UPDATE LIEF_PARTNER SET LIEP_A_EMAIL = REPLACE(LIEP_A_EMAIL, ' ', '') WHERE COALESCE(LIEP_A_EMAIL, '') LIKE '% %'");

            // Bestellungen bereinigen
            // Wir löschen an dieser Stelle alle Notizen von erledigten Bestellungen, die exakt die selben sind, wie die, die im Lieferanten hinterlegt ist.
            await fbController.QueryAsync("UPDATE BESTELLUNGEN SET BEST_B_NOTIZ = NULL WHERE BEST_L_ERLEDIGT = 'Y' AND EXISTS(SELECT 1 FROM LIEFERANTEN L WHERE L.LIEF_N_NR = BESTELLUNGEN.BEST_N_LIEFNR)");
            // Wir machen das selbe auch für die Bestellpositionen, nur, dass wir hier mit der Lieferantenartikel Notiz vergleichen müssen
            await fbController.QueryAsync("UPDATE BESTELLUNGEN_POS SET BEPO_A_NOTIZ = NULL WHERE BEPO_L_ERLEDIGT = 'Y' AND EXISTS(SELECT 1 FROM LIEFERANTENARTIKEL LFA WHERE LFA.ARLI_A_ARTIKELNR = BESTELLUNGEN_POS.BEPO_A_ARTIKELNR)");


            // Bereinigt BELEGSTUECKLISTE, für Positionen, die keine Stückliste sind, aber dennoch in der Liste ist (leichen, wenn eine Position getauscht wurde)
            await fbController.QueryAsync(@"DELETE FROM BELEGSTUECKLISTE WHERE BSTU_N_POSID IN(SELECT bstu_n_posid FROM BELEGSTUECKLISTE BST
INNER JOIN BELEGPOS BP ON BP.BPOS_N_POSID = BST.BSTU_N_BELEPOSID 
WHERE BPOS_A_ARTIKELNR NOT IN(SELECT ARST_A_HAUPTARTI FROM ARTIKELSTUECKLISTE) 
AND (SELECT COUNT(*) FROM BELEGCHARGEN BC where BC.BCHA_N_POSID = BP.BPOS_N_POSID AND BC.BCHA_N_STCKLPOSID = BST.BSTU_N_POSID) = 0)");

            // Löscht Telefonate die älter als 1 Jahr sind
            fbController.AddParameter("@DATUM", DateTime.Now.AddYears(-1));
            await fbController.QueryAsync("DELETE FROM TELEFONATE WHERE TELE_TIMESTAMP < @DATUM");

        }
        /// <summary>
        /// Bereinigt das Flag Sperre bei OP für alle Kunden
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task KundensperrenBereinigungAsync(FbController2 fbController)
        {
            //alle gesperrten Kunden abfragen und alle die nicht in der 2ten liste sind freischalten.
            DataTable gesperrteKunden = await fbController.SelectDataAsync("SELECT KUND_A_NR FROM KUNDEN WHERE KUND_L_SPERRE_OP = 'Y'");
            
            string gesperrteKundenString = "";
            foreach (DataRow row in gesperrteKunden.Rows)
            {
                gesperrteKundenString += $"'{row["KUND_A_NR"]}',";
            }

            gesperrteKundenString = gesperrteKundenString.TrimEnd(',');

            //Alt jetzt nur kunden abfragen die ihr KReditlimit überschritten haben.
            string selectAbfrage = @"select bel2.BELE_A_KUNDENNR 
                                                FROM BELEGE bel2
                                                     LEFT JOIN ZAHLUNGSBEDINGUNG 
                                                          ON(bel2.BELE_N_ZAHLUNG = ZAHLUNGSBEDINGUNG.zabd_n_nr)
                                                     LEFT JOIN KUNDEN 
                                                          ON KUNDEN.KUND_A_NR = bel2.BELE_A_KUNDENNR      
                                                WHERE bel2.bele_a_typ = 'RE'    
                                                      AND bel2.bele_l_bezahlt = 'N' 
                                                      AND datediff(day from dateadd(ZAHLUNGSBEDINGUNG.zabd_n_nettotage day to bel2.bele_d_date) to current_date) > 3 
                                                      and BELE_N_ZAHLUNG != 1 
                                                      AND BELE_N_ZAHLUNG != 2 
                                                      AND BELE_N_ZAHLUNG != 21 
                                                      AND BELE_N_ZAHLUNG != 22
                                                      AND BELE_N_ZAHLUNG != 23
                                                      AND BELE_N_ZAHLUNG != 4 
                                                      AND BELE_N_ZAHLUNG != 20 
                                                      AND BELE_N_ZAHLUNG != 24 
                                                      AND BELE_N_ZAHLUNG != 30 
                                                      AND BELE_N_ZAHLUNG != 31 
                                                      AND BELE_N_ZAHLUNG != 32
                                                      AND KUNDEN.KUND_N_KREDITLIMIT < (select sum(BELE_N_BRUTTO) from belege bel where BELE_A_TYP = 'RE' AND bel.BELE_A_KUNDENNR = bel2.BELE_A_KUNDENNR  AND BELE_L_BEZAHLT = 'N')
                                                      ";

            DataTable table = await fbController.SelectDataAsync(selectAbfrage);
            
            //Nur noch aktuell gesperrte Kunde abfragen.
            string neuGesperrteKunden = "";
            var trusted = new string[] { "'10046'", "'10100'", "'16301'", "'16149'", "'13684'", "'14729'", "'10091'", "'15908'", "'17901'" };
            foreach (DataRow row in table.Rows)
            {
                neuGesperrteKunden += $"'{row["BELE_A_KUNDENNR"]}',";
                fbController.AddParameter("@BELE_A_KUNDENNR", row["BELE_A_KUNDENNR"]);
                await fbController.QueryAsync($"UPDATE KUNDEN SET KUND_L_SPERRE_OP = 'Y' WHERE KUND_A_NR = @BELE_A_KUNDENNR AND KUND_A_NR NOT IN ({String.Join(", ", trusted)})");
            }

            neuGesperrteKunden = neuGesperrteKunden.Trim(',');

            // Bereits gesperrte Kunden werden freigegeben, da ja nun alle neu gesperrt worden sind. Also eine Bereinigung der zuvor gesperrten Kunden.
            await fbController.QueryAsync($"UPDATE KUNDEN SET KUND_L_SPERRE_OP = 'N' WHERE KUND_A_NR in({gesperrteKundenString}) AND KUND_A_NR NOT IN ({neuGesperrteKunden})");
        }
        /// <summary>
        /// Führt die Bereinigung für den Onlinestore durch
        /// </summary>
        /// <returns></returns>
        private async Task OnlineBereinigungAsync()
        {
            _logger.Information("Online bereinigung gestartet...");
            using MySqlController2 mySqlController = new MySqlController2();
            // Produkte ohne Kategorien wieder sichtbar machen

            //Konsistenzüberprüfung:
            await mySqlController.QueryAsync("insert into product_to_category (product_id, category_id) select product_id, 2425 from product where product_id not in (select distinct product_id from product_to_category)");
            // Produkte ohne Store-Zugehörigkeit wieder sichtbar machen
            await mySqlController.QueryAsync("insert into product_to_store (product_id, store_id) select product_id, 0 from product where product_id not in (select distinct product_id from product_to_store)");
            await mySqlController.QueryAsync("delete from product_to_category where category_id not in (select distinct category_id from category)");
            await mySqlController.QueryAsync("delete from product_to_download where product_id not in (select distinct product_id from product)");

            //früher optimize.php cron
            await mySqlController.QueryAsync("delete FROM `product_attribute` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_description` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_filter` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_image` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_option` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_option_value` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_related` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_reward` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_special` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `product_to_category` WHERE product_id not in (select product_id from product) or category_id not in (select category_id from category)");
            await mySqlController.QueryAsync("delete FROM `product_to_store` WHERE product_id not in (select product_id from product)");
            await mySqlController.QueryAsync("delete FROM `category_to_store` WHERE store_id not in (0,10)");
            await mySqlController.QueryAsync("delete FROM `product_to_store` WHERE store_id not in (0,10)");
            await mySqlController.QueryAsync("delete FROM `product` WHERE product_id not in (select product_id from product_description)");
            await mySqlController.QueryAsync("delete from product_attribute where product_id not in (select distinct product_id from product)");
            await mySqlController.QueryAsync("delete from product_attribute where attribute_id not in (select distinct attribute_id from product_attribute)");

            _logger.Information("Online bereinigung beendet!");
        }
        /// <summary>
        /// Bereinigt die Telefonnummern von Kunden und Lieferanten
        /// </summary>
        /// <returns></returns>
        private async Task ParseTelefonnummernAsync(FbController2 fbController)
        {
            _logger.Information($"{nameof(ParseTelefonnummernAsync)} bereinigung gestartet...");
            #region Kunden / Ansprechpartner
            string kundenSql = "SELECT KUND_A_NR FROM KUNDEN";
            List<string> kundennummern = (await fbController.SelectDataAsync(kundenSql)).Rows.Cast<DataRow>().Select(x => x.Field<string>("KUND_A_NR") ?? String.Empty).ToList();
            int kCount = 0;
            foreach (string kundennummer in kundennummern)
            {
                Console.Write($"\rKunden: {kCount}/{kundennummern.Count}");
                if (String.IsNullOrWhiteSpace(kundennummer))
                    continue;

                await Kunde.UpdateParsedTelefonnummern(kundennummer, fbController);
                kCount++;
            }
            #endregion

            #region Lieferanten / Lieferantenpartner
            string lieferantenSql = "SELECT LIEF_N_NR FROM LIEFERANTEN";
            List<int> lieferantennummern = (await fbController.SelectDataAsync(lieferantenSql)).Rows.Cast<DataRow>().Select(x => x.Field<int>("LIEF_N_NR")).ToList();
            int lCount = 0;
            foreach (int liefnummer in lieferantennummern)
            {
                Console.Write($"\rLieferanten: {lCount}/{lieferantennummern.Count}");
                await Lieferant.UpdateParsedTelefonnummern(liefnummer, fbController);
                lCount++;
            }

            #endregion

            _logger.Information($"{nameof(ParseTelefonnummernAsync)} bereinigung beendet!");
        }
        /// <summary>
        /// Bereinigt den Output Order der WK5. Siehe <see cref="GlobalConfig.OutputPfadWK5"/>
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task Wk5OutputAsync(FbController2 fbController)
        {
            _logger.Information("Starte WK5-Output Bereinigung");
            try
            {
                var files = Directory.GetFiles(GlobalConfig.Configuration.OutputPfad);

                foreach (var file in files)
                {
                    string extension = Path.GetExtension(file);
                    if (!extension.Equals(".log", StringComparison.OrdinalIgnoreCase))
                    {
                        File.Delete(file);
                    }
                }
            }
            catch (Exception ex)
            {
                await EmailController.FehlerMailSendenAsync("[OUTPUT-BEREINIGUNG] Fehler", $"Fehler beim bereinigen des WK5-Output Ordners. Fehlermeldung: {ex}");
            }

            _logger.Information("WK5-Output Bereinigung beendet!");
        }
        /// <summary>
        /// Bereinigt die hochgeladenen Dokumente in der WK5
        /// </summary>
        /// <param name="logger"></param>
        /// <returns></returns>
        private async Task Wk5UploadBereinigungAsync()
        {
            _logger.Information("Starte WK5-Upload Bereinigung");
            try
            {
                var files = Directory.GetFiles(@"\\srv01\inetpub\wwwroot\wk5\Uploads");

                foreach (var file in files)
                {
                    string extension = Path.GetExtension(file);
                    if (!extension.Equals(".log", StringComparison.OrdinalIgnoreCase))
                    {
                        File.Delete(file);
                    }
                }
            }
            catch (Exception ex)
            {
                await EmailController.FehlerMailSendenAsync("[UPLOAD-BEREINIGUNG] Fehler", $"Fehler beim bereinigen des WK5-Output Ordners. Fehlermeldung: {ex}");
            }
            _logger.Information("WK5-Upload Bereinigung beendet!");
        }
        /// <summary>
        /// Setzt in Belegen automatisch die MachMich Kostenstelle, wenn diese mit Mach-Mich zu tun haben.
        /// </summary>
        /// <returns></returns>
        private async Task MachMichKostenstelleAsync()
        {
            _logger.Information($"{nameof(MachMichKostenstelleAsync)} bereinigung gestartet...");
            int kostenstelle = 10110;
            string[] belegtypen = new string[] { "RE" };
            string artikelnr = "KLOPAPIER";

            string sql = @"UPDATE BELEGE SET
BELE_N_KOSTENST = @KOSTENSTELLE
WHERE BELE_A_TYP IN ('" + String.Join("','", belegtypen) + @"')
AND BELE_N_NR IN (
SELECT BELE_N_NR FROM BELEGE B LEFT JOIN BELEGPOS BP 
ON (B.BELE_N_NR = BP.BPOS_N_NR AND B.BELE_A_TYP = BP.BPOS_A_TYP) 
WHERE 
UPPER(BP.BPOS_A_ARTIKELNR) = @ARTIKELNR 
AND B.BELE_A_TYP IN ('" + String.Join("','", belegtypen) + @"')
)";
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@KOSTENSTELLE", kostenstelle);
            fbController.AddParameter("@ARTIKELNR", artikelnr.ToUpper());

            await fbController.QueryAsync(sql);
            _logger.Information($"{nameof(MachMichKostenstelleAsync)} bereinigung beendet!");
        }
        /// <summary>
        /// Löscht alle Dokumente aus der Dokumentenablage, die älter als 8 Jahre sind
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private Task DokumentenablageBereinigenAsync(FbController2 fbController)
        {
            _logger.Information("Dokumentenablage bereinigen...");
            void BereinigeAblage(string pfad)
            {
                _logger.Information($"{pfad} bereinigen...");
                DirectoryInfo di = new DirectoryInfo(pfad);
                foreach (var directory in di.GetDirectories())
                {
                    foreach (var file in directory.GetFiles())
                    {
                        if (file.LastWriteTime.AddYears(8) < DateTime.Now)
                        {
                            File.Delete(file.FullName);
                        }
                    }
                }
            }

            BereinigeAblage(GlobalConfig.Configuration.KundenDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.LieferantenDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.ArtikelDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.AngebotDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.AuftragDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.LieferscheinDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.RechnungDokumentenAblagePfad);
            BereinigeAblage(GlobalConfig.Configuration.GutschriftDokumentenAblagePfad);
            _logger.Information("Bereinigung der Dokumentenablage abgeschlossen.");
            return Task.CompletedTask;
        }
        /// <summary>
        /// Prüft, ob es inaktive Artikel mit Bestand gibt und meldet das Ergebnis an die Shopverwaltung.
        /// </summary>
        /// <param name="fbController"></param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException"></exception>
        private async Task CheckInaktiveArtikelMitBestandAsync(FbController2 fbController)
        {
            _logger.Information($"{nameof(CheckInaktiveArtikelMitBestandAsync)} gestartet...");
            DataTable data = await fbController.SelectDataAsync("SELECT ARTI_A_NR FROM ARTIKEL WHERE ARTI_L_INAKTIV = 'Y'");
            ArtikelService artikelService = new ArtikelService();
            List<Artikel> artikelAufInaktivMitBestand = new();
            foreach (DataRow row in data.Rows)
            {
                Artikel artikel = await artikelService.GetAsync(row.Field<string>("ARTI_A_NR"), fbController) ?? throw new NullReferenceException(nameof(artikel));

                if (artikel.Bestand > 0)
                {
                    artikelAufInaktivMitBestand.Add(artikel);
                }
            }

            if (artikelAufInaktivMitBestand.Any())
            {
                StringBuilder mailBuilder = new StringBuilder();
                mailBuilder.AppendLine("Es wurden Artikel gefunden, die auf inaktiv stehen, allerdings über einen Bestand verfügen. Diese Artikel müssen überprüft werden.<br /><br />");
                mailBuilder.AppendLine("<strong>Was ist zu tun?</strong><br />");
                mailBuilder.AppendLine("<p>Inaktiv Flag entfernen und zur Prüfung an die Programmierung weitergeben, oder ggf. nach Absprache den übrigen Bestand ausbuchen.</p><br /><br />");
                mailBuilder.AppendLine("<strong>Folgende Artikel müssen geprüft werden:</strong><br />");

                foreach (var artikel in artikelAufInaktivMitBestand)
                {
                    mailBuilder.AppendLine($"<a href='http://wk5.local/Artikel/{artikel.Artikelnummer}'>{artikel.Artikelnummer}</a> - {artikel.GetBezeichnung()}<br />");
                }

                await _emailController.SendenAsync(GlobalConfig.EmailShopverwalter,"Inaktive Artikel mit Bestand gefunden", mailBuilder.ToString());
            }

            _logger.Information($"{nameof(CheckInaktiveArtikelMitBestandAsync)} beendet!");
        }
        /// <summary>
        /// Prüft, ob Preisgruppen fhelen, die aber angelegt sein müssen und benachrichtigt die Shopverwaltung.
        /// </summary>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task PreisgruppenBereinigenAsync(FbController2 fbController)
        {
            _logger.Information("Preisgruppen Bereinigung gestartet...");
            //Hier überprüfen wir die Preisgruppen und machen Meldung:

            DataTable preisgruppen = await fbController.SelectDataAsync("SELECT DISTINCT ARTI_A_PREISGRUPPE FROM ARTIKEL WHERE ARTI_A_PREISGRUPPE != '' AND ARTI_A_PREISGRUPPE NOT IN (SELECT DISTINCT PRGR_A_NR FROM PREISGRUPPE)");
            
            string preisgruppen_fehlen = string.Empty;

            foreach (DataRow row in preisgruppen.Rows)
            {
                preisgruppen_fehlen += $"{row["ARTI_A_PREISGRUPPE"]}<br />";
            }
            
            string mailtext = "";
            if (preisgruppen_fehlen.Length > 0)
            {
                mailtext += "Es fehlen folgende Preisgruppen in der WK5, zu denen es Artikel gibt - bitte neu anlegen, damit Preise richtig berechnet werden können:<br />";
                mailtext += preisgruppen_fehlen;
            }

            if (mailtext.Length > 0)
            {
                _logger.Information("Fehlende Preisgruppen gefunden. Sende email...");
                await _emailController.SendenAsync(GlobalConfig.EmailShopverwalter,"Preisgruppen fehlen", mailtext);
            }

            _logger.Information("Preisgruppen Bereinigung beendet.");
        }
        
        private async Task ArtikelOhneLieferantenBereinigungAsync(FbController2 fbController)
        {
            //Artikel ohne Lieferantenholen und per Mail schreiben

            string ignoreList = Path.Combine(GlobalConfig.W4TmpFolderSrv01, "IgnoreOhneLieferanten.txt");
            List<string> ignore  = await FileIO.LeseListe(ignoreList);

            DataTable artikel_ohne_lieferanten = await fbController.SelectDataAsync(@"SELECT * FROM ARTIKEL 
LEFT JOIN ARTIKELWERTE ON ARTI_A_NR = ARWE_A_NR 
WHERE ARTI_A_NR NOT IN (SELECT DISTINCT ARLI_A_ARTIKELNR FROM LIEFERANTENARTIKEL) 
AND ARTI_L_INAKTIV = 'N' 
AND ARTI_L_LAGERFUEHR = 'Y' 
AND ARTI_L_DIENSTLEIST = 'N' 
AND ARTI_A_NR NOT IN ('" + String.Join("','", ignore.ToArray()) + @"') 
AND ARTI_A_NR NOT IN (SELECT DISTINCT BUNDLE_A_ARTINR FROM BUNDLES WHERE BUNDLE_A_ARTINR != 'CDT1600PH') AND ARWE_N_BESTAND <= 0");
            
            

            StringBuilder mailbuilder = new StringBuilder();
            int NOLines = 0;

            mailbuilder.AppendLine(@"Folgende Artikel haben keinen Lieferanten oder hat keinen Lieferanten mehr (ggf. ist dieser Artikel jetzt nicht mehr verfügbar?) - bitte im Shop und der W4 überprüfen und ggf. deaktivieren oder löschen: <br>Ausnahmen können in N:\\W4\\tmp\\IgnoreOhneLieferanten.txt hinzugefügt werden.<br><br>");
            
            int countSqlFehler = 0;
            using MySqlController2 mySqlController = new MySqlController2();
            foreach (DataRow Reihe in artikel_ohne_lieferanten.Rows)
            {
                //OnlineID für Löschlink holen 
                int product_id = 0;
                try
                {
                    object? id_obj = await mySqlController.FetchObjectAsync($"SELECT product_id FROM product WHERE model = '{Reihe["ARTI_A_NR"]}'");

                    if (id_obj is not null)
                    {
                        product_id = Convert.ToInt32(id_obj);
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error("#BEREINIGUNG2 Fehler beim laden der Produkt-ID. Fehlermeldung: {error}", ex);
                    countSqlFehler++;
                }

                if (Reihe["WK5_ARTI_L_HAUPTARTIKEL"].ToString() == "Y")
                {
                    mailbuilder.AppendLine("*** DIESER ARTIKEL IST EIN HAUPTARTIKEL *** MIT DEM VERTRIEB ABSPRECHEN BEVOR ER GELÖSCHT WIRD<br>");
                }

                mailbuilder.AppendLine($" Art-NR: <a href='http://wk5.local/Artikel/{Reihe["ARTI_A_NR"]}'>{Reihe["ARTI_A_NR"]}</a>  |  {Reihe["ARTI_A_BEZ1"]}{(product_id is 0 ? "" : ($"<br>Im OnlineShop löschen ? : <a href=\"http://www.karley.de/admin/delproduct.php?id={product_id}\">Online-Löschen</a>"))} <br>In der W4 löschen (Artikel mit Beleg werden deaktiviert) : <a href=\"karley:w4Entfernen;{Reihe["ARTI_A_NR"]}\">Offline-Löschen</a> (Achtung Artikel wird beim Klick direkt gelöscht/deaktiviert) <br><br>");
                NOLines++;
            }

            if (NOLines > 0)  //Mur eine Email senden, falls wir auch einen Inhalt haben!
            {
                await _emailController.SendenAsync(GlobalConfig.EmailShopverwalter, "Artikel ohne Lieferanten", mailbuilder.ToString());
            }
        }

        private async Task PreislistenUpdateAsync()
        {
            string PreislistePfad = @"\\srv01\Daten\attachements\KARLEY-PREISLISTE-ETIKETTEN.pdf"; // Aus sicht des Servers
            string bonrollenPfad = @"\\srv01\Daten\attachements\KARLEY-PREISLISTE-BONROLLEN.pdf"; // Aus sicht des Testrechners

            //Scholz 06.04.2020 - FTP Upload in Funktion ausgelagert
            FtpClient client = new FtpClient(GlobalConfig.Karley_FTP_SERVER, GlobalConfig.Karley_FTP_USER, GlobalConfig.Karley_FTP_PW);
            await client.UploadFileAsync(PreislistePfad, "httpdocs/download/KARLEY-PREISLISTE-ETIKETTEN.pdf", FtpRemoteExists.Overwrite);
            await client.UploadFileAsync(bonrollenPfad, "httpdocs/download/KARLEY-PREISLISTE-BONROLLEN.pdf", FtpRemoteExists.Overwrite);
        }
    }
}
