using ArtikelUpdateOpencart.Import.Models;
using ArtikelUpdateOpencart.Models;
using KarleyLibrary.Erweiterungen;
using Serilog;
using Serilog.Core;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Email;
using WK5.Core.Models;

namespace ArtikelUpdateOpencart
{
    public abstract class LieferantenImportBase<T>
    {
        public const int LIEFERANTEN_PREIS_GÜLTIGKEITS_TAGE = 7;
        protected readonly ILogger _logger;
        private static List<string> _usedEans = new List<string>();
        public int LieferantenId { get; }
        public string DownloadUrl { get; }
        public List<T> ArtikeldatenLieferant { get; set; } = new List<T>();
        public LieferantenImportBase(int lieferantenId, string dowloadUrl, ILogger logger)
        {
            LieferantenId = lieferantenId;
            DownloadUrl = dowloadUrl;
            _logger = logger;
        }

        public abstract Task DownloadAsync();

        public abstract Task RunAsync();

        /// <summary>
        /// Gibt eine Liste mit allen Herstellern die in der Tabelle Artikel vertreten sind zurück
        /// </summary>
        /// <returns>Gibt eine Liste <see cref="List{T}"/> wobei T <see cref="string"/> ist zurück, die alle Hersteller in Artikel beinhaltet</returns>
        protected static async IAsyncEnumerable<string> GetVorhandeneHerstellerAsync(FbController2 fbController)
        {
            DataTable data = await fbController.SelectDataAsync("SELECT DISTINCT UPPER(ARTI_A_HERSTELLER) AS HERSTELLER FROM ARTIKEL WHERE ARTI_A_HERSTELLER != ''");

            foreach (DataRow row in data.Rows)
            {
                yield return row.Field<string>("HERSTELLER")!;
            }
        }

        protected static async Task LieferantenUpdateGlobalAsync(GlobalLieferantenArtikel artikel, HerstellerErsetzen ersetzen, FbController2 fbController, ILogger _logger)
        {
            List<string> ignorierteArtikel = new();
            try
            {
                ignorierteArtikel = await FileIO.LeseListe(Path.Combine(GlobalConfig.W4TmpFolderSrv01, $"{artikel.LieferantenId}_IgnoreArtikel.txt"));
            }
            catch (Exception)
            {
                // 17.08.2020 - Klein: Anweisung von Ley. Wenn Datei nicht existiert, dann nicht abstürzen, dann nimmt er halt alle Artikel.
            }

            if (!ignorierteArtikel.Contains(artikel.Bestellnummer.ToUpper()))
            {

                if (artikel.Mindestbestellmenge is <= 0)
                {
                    artikel.Mindestbestellmenge = 1;
                }

                if(artikel.EAN == "5656565656562")
                {
                    return;
                }

                string eanLieferant = StringErweiterung.ParseEan(artikel.EAN).ToUpper();
                bool isValidEan = StringErweiterung.IsValidEan(eanLieferant);
                // 06.09.2021 MK: Ley sagt, wenn EAN schon benutzt wurde, dann nichts machen
                // Lieferanten übermitteln für mehrere Artikel die gleiche EAN. Das ist natürlich unsinn.
                if (!string.IsNullOrWhiteSpace(eanLieferant) && _usedEans.Contains(eanLieferant) && isValidEan)
                {
                    return;
                }

                if (!string.IsNullOrWhiteSpace(eanLieferant) && isValidEan)
                {
                    _usedEans.Add(eanLieferant);
                }

                artikel.Hersteller = ersetzen.GetHerstellerErsetzt(artikel.Hersteller);

                NamensKlasse artikelbezeichnung = new NamensKlasse(artikel.Kurzbezeichnung, 60); //Langen Namen Aufteilen in 60 Zeichen   

                //Erst prüfen ob LFA vorhanden
                fbController.AddParameter("@ARLI_A_BESTELLNR", artikel.Bestellnummer.ToUpper());
                fbController.AddParameter("@ARLI_N_LIEFNR", artikel.LieferantenId);
                string? artikelnummer = await fbController.FetchObjectAsync("SELECT ARLI_A_ARTIKELNR FROM LIEFERANTENARTIKEL WHERE UPPER(ARLI_A_BESTELLNR) = @ARLI_A_BESTELLNR AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR AND ARLI_A_ARTIKELNR  IN (SELECT DISTINCT ARTI_A_NR FROM ARTIKEL WHERE ARTI_L_INAKTIV = 'N')") as string;

                if (!string.IsNullOrWhiteSpace(artikelnummer))  //LFA vorhanden:
                {
                    string updateSql = @"UPDATE LIEFERANTENARTIKEL SET 
ARLI_L_HAUPTLIEFERANT = 'N', 
ARLI_N_PREIS = @ARLI_N_PREIS,
ARLI_N_WAEHRUNGSPREIS = @ARLI_N_WAEHRUNGSPREIS,
ARLI_N_MINDESTABNAHME = @ARLI_N_MINDESTABNAHME,
ARLI_N_VERSANDKOST = @ARLI_N_VERSANDKOST,
ARLI_N_KURS = @ARLI_N_KURS,
ARLI_A_WAEHRUNG = @ARLI_A_WAEHRUNG,
ARLI_N_VERPACKKOST = @ARLI_N_VERPACKKOST,
ARLI_A_BEZ1 = @Name1,
ARLI_A_BEZ2 = @Name2,
ARLI_A_BEZ3 = @Name3,
ARLI_A_BEZ4 = @Name4,
ARLI_A_BEZ5 = @Name5,
WK5_ARLI_N_LIEFBESTAND = @Menge,
ARLI_TIMESTAMP = CURRENT_TIMESTAMP,
ARLI_D_LETZAEND = CURRENT_TIMESTAMP
WHERE 
UPPER(ARLI_A_BESTELLNR) = @ARLI_A_BESTELLNR AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR";

                    try
                    {


                        fbController.AddParameter("@Name1", artikelbezeichnung.Name1);
                        fbController.AddParameter("@Name2", artikelbezeichnung.Name2);
                        fbController.AddParameter("@Name3", artikelbezeichnung.Name3);
                        fbController.AddParameter("@Name4", artikelbezeichnung.Name4);
                        fbController.AddParameter("@Name5", artikelbezeichnung.Name5);
                        fbController.AddParameter("@Menge", artikel.Lagerbestand);
                        fbController.AddParameter("@ARLI_N_PREIS", artikel.NettoEinkaufspreis);
                        fbController.AddParameter("@ARLI_N_WAEHRUNGSPREIS", artikel.NettoEinkaufspreis);
                        fbController.AddParameter("@ARLI_N_MINDESTABNAHME", artikel.Mindestbestellmenge);
                        fbController.AddParameter("@ARLI_N_VERSANDKOST", artikel.Versandkosten);
                        fbController.AddParameter("@ARLI_N_KURS", 1m);
                        fbController.AddParameter("@ARLI_A_WAEHRUNG", "EUR");
                        fbController.AddParameter("@ARLI_N_VERPACKKOST", 0m);
                        fbController.AddParameter("@ARLI_A_BESTELLNR", artikel.Bestellnummer.ToUpper());
                        fbController.AddParameter("@ARLI_N_LIEFNR", artikel.LieferantenId);

                        await fbController.QueryAsync(updateSql);
                        _logger.Information("Lieferantenartikel aktualisiert. Bestellnummer: {Bestellnummer}; Artikelnummer: {Artikelnummer}; LieferantenId: {LieferantenId}", artikel.Bestellnummer, artikelnummer, artikel.LieferantenId);

                    }
                    catch (Exception Exception)
                    {
                        Console.WriteLine("---------------------------------------------------------");
                        _logger.Error($"LieferantenUpdateGlobal {Exception}");
                        _logger.Error($"LieferantenUpdateGlobal SQL {updateSql}");
                        _logger.Error($"LieferantenUpdateGlobal Parameter {fbController.GetParametersWithValues(true)}");
                        Console.WriteLine("---------------------------------------------------------");
                    }


                    string updateExtras = "";
                    //Zusatzinformationen Updaten

                    updateExtras = updateExtras.TrimEnd(',');

                    bool extrasVorhanden = artikel.Gewicht > 0 || artikel.Höhe > 0 || artikel.Länge > 0 || artikel.Breite > 0;

                    if (extrasVorhanden)
                    {
                        StringBuilder extrasBuilder = new StringBuilder();
                        List<string> extras = new List<string>();
                        extrasBuilder.AppendLine("UPDATE ARTIKEL SET ");
                        if (artikel.Gewicht > 0)
                        {
                            extras.Add("ARTI_N_GEWICHT = @GEWICHT");
                            fbController.AddParameter("@GEWICHT", artikel.Gewicht);
                        }

                        if (artikel.Höhe > 0)
                        {
                            extras.Add("ARTI_N_HOEHE = @HOEHE");
                            fbController.AddParameter("@HOEHE", artikel.Höhe);
                        }

                        if (artikel.Länge > 0)
                        {
                            extras.Add("ARTI_N_LAENGE = @LAENGE");
                            fbController.AddParameter("@LAENGE", artikel.Länge);
                        }

                        if (artikel.Breite > 0)
                        {
                            extras.Add("ARTI_N_BREITE = @BREITE");
                            fbController.AddParameter("@BREITE", artikel.Breite);
                        }


                        extrasBuilder.Append(String.Join(",", extras));
                        extrasBuilder.AppendLine(@" WHERE ARTI_L_INAKTIV = 'N' 
AND ARTI_A_NR = 
(
    SELECT FIRST 1 ARLI_A_ARTIKELNR 
    FROM LIEFERANTENARTIKEL 
    WHERE UPPER(ARLI_A_ARTIKELNR) != 'DIVERS' 
        AND UPPER(ARLI_A_ARTIKELNR) != 'KARLEY' 
        AND UPPER(ARLI_A_BESTELLNR) = @ARLI_A_BESTELLNR 
        AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR
)");
                        fbController.AddParameter("@ARLI_A_BESTELLNR", artikel.Bestellnummer.ToUpper());
                        fbController.AddParameter("@ARLI_N_LIEFNR", artikel.LieferantenId);
                        await fbController.QueryAsync(extrasBuilder.ToString());
                    }



                    //Ean , Hersteller und Hersteller nummer holen
                    ArtikelInfo artikelInfo = await ArtikelInfo.GetArtikelInfoAsync(artikel.LieferantenId, artikel.Bestellnummer, fbController) ?? new ArtikelInfo();
                    String Abweichungen = "";
                    String AbweichungEmailSubject = "";


                    List<string> updateColumns = new List<string>();


                    

                    //JT liefert zum Teil falsche EANs darum müssen wir hier auf Zahlen Only prüfen.
                    if (string.IsNullOrWhiteSpace(artikelInfo.EAN) && eanLieferant.Length > 9 && isValidEan)
                    {
                        //noch keine EAN vorhanden also updaten.
                        updateColumns.Add("ARTI_A_EAN = @ARTI_A_EAN");
                        fbController.AddParameter("@ARTI_A_EAN", eanLieferant);
                    }
                    else if (!string.IsNullOrWhiteSpace(eanLieferant) && artikelInfo.EAN.ToUpper() != eanLieferant && isValidEan)
                    {
                        // EAN vorhanden also E-Mail benachrichtigung
                        AbweichungEmailSubject += artikel.EAN + " ";
                        Abweichungen += $"Folgende EAN weicht ab : {artikel.EAN}\r\n";

                    }

                    //Hersteller ggf. Updaten
                    if (string.IsNullOrEmpty(artikelInfo.Hersteller) && !string.IsNullOrEmpty(artikel.Hersteller))
                    {
                        updateColumns.Add("ARTI_A_HERSTELLER = @ARTI_A_HERSTELLER");
                        fbController.AddParameter("@ARTI_A_HERSTELLER", artikel.Hersteller);
                    }
                    else if (artikelInfo.Hersteller.ToUpper().Trim() != artikel.Hersteller.ToUpper().Trim() && artikel.Hersteller != "")
                    {
                        AbweichungEmailSubject += artikel.Hersteller + " ";
                        Abweichungen += $"Folgender Hersteller weicht ab : {artikel.Hersteller} - (WK5: {artikelInfo.Hersteller} , LF: " + artikel.Hersteller + ")\r\n";
                    }

                    //Hersteller-Nummer ggf. Updaten - Auf 30 kürzen weil die DB Max. 30 Zeichen nimmt
                    string checkHestellerNummer = artikel.Herstellernummer.ToUpper();
                    if (checkHestellerNummer.Length > 30)
                    {
                        checkHestellerNummer = checkHestellerNummer.Substring(0, 30);
                        var check = artikelInfo.Notiz.IndexOf(artikel.Herstellernummer);
                        if (check < 0)
                        {
                            updateColumns.Add("ARTI_B_NOTIZ = @ARTI_B_NOTIZ");
                            fbController.AddParameter("@ARTI_B_NOTIZ", $"Herstellernummer(n):{artikel.Herstellernummer}{Environment.NewLine}{Environment.NewLine}{artikelInfo.Notiz}");
                        }
                    }


                    if (string.IsNullOrWhiteSpace(artikelInfo.Herstellernummer) && !string.IsNullOrWhiteSpace(artikel.Herstellernummer))
                    {
                        updateColumns.Add("ARTI_A_HERST_NR = @ARTI_A_HERST_NR");
                        fbController.AddParameter("@ARTI_A_HERST_NR", artikel.Herstellernummer);
                    }
                    else if (!artikelInfo.Herstellernummer.Trim().Equals(checkHestellerNummer.Trim(), StringComparison.OrdinalIgnoreCase) && artikel.Herstellernummer != "")
                    {
                        AbweichungEmailSubject += artikel.Herstellernummer + " ";
                        Abweichungen += $"Folgende Hersteller-Nummer weicht ab : {artikel.Herstellernummer}\r\n";
                    }

                    //Updaten und/oder E-Mail schreiben
                    if (updateColumns.Any())
                    {


                        string sql = @$"UPDATE ARTIKEL SET {String.Join(",", updateColumns)}
WHERE 
    ARTI_L_INAKTIV = 'N' 
    AND ARTI_A_NR = (
                        SELECT FIRST 1 ARLI_A_ARTIKELNR 
                        FROM LIEFERANTENARTIKEL 
                        WHERE 
                            UPPER(ARLI_A_ARTIKELNR) != 'DIVERS' 
                            AND UPPER(ARLI_A_BESTELLNR) = @ARLI_A_BESTELLNR 
                            AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR
                    )";

                        fbController.AddParameter("@ARLI_A_BESTELLNR", artikel.Bestellnummer.ToUpper());
                        fbController.AddParameter("@ARLI_N_LIEFNR", artikel.LieferantenId);
                        await fbController.QueryAsync(sql);

                        _logger.Information("Artikel aktualisiert. Artikelnummer: {Artikelnummer}", artikelnummer);
                    }

                    if (Abweichungen.Length > 0)
                    {
                        EmailController emailController = new EmailController();
                        Abweichungen = $"Bei folgendem Artikel wurde beim Liefereant ({artikel.LieferantenId}) abweichungen in EAN und/oder Hersteller und/oder Herstellernr. gefunden - Artikel: <a href=\"http://wk5.local/Artikel/{artikelInfo.Artikelnummer}\">{artikelInfo.Artikelnummer}</a> \r\nBestellnummer: {artikel.Bestellnummer.ToUpper()}\r\nSiehe Wikieintrag http://wikis.local/wiki/doku.php/wk5:stammdaten:artikel:artikelimport:meldungen:au0006\r\n{Abweichungen}";
#if !DEBUG
                        await emailController.SendenAsync(GlobalConfig.EmailShopverwalter, $"Abweichende Lieferanten Daten {AbweichungEmailSubject.TrimEnd(' ')} {artikel.Bestellnummer}".Replace("\r\n", "<br />"), Abweichungen);
#endif
                    }


                }
                else
                {
                    //Wenn kein Lieferantenartikel gefunden wurde, dann wird nach MPN gesucht
                    string sql = @"SELECT 
ARTI_A_NR 
FROM ARTIKEL 
WHERE 
    (
        UPPER(ARTI_A_HERST_NR) = @ARTI_A_HERST_NR 
        AND UPPER(ARTI_A_HERSTELLER) LIKE @ARTI_A_HERSTELLER 
        AND COALESCE(ARTI_A_HERST_NR, '') != '' 
        AND COALESCE(ARTI_A_HERSTELLER, '') != '' 
        AND UPPER(ARTI_A_HERSTELLER) != 'KARLEY'
        AND UPPER(ARTI_A_HERSTELLER) != 'DIVERS' 
    ) 
    OR 
    (
        ARTI_A_EAN = @ARTI_A_EAN 
        AND COALESCE(ARTI_A_EAN, '') != ''
        
    )
    AND ARTI_L_INAKTIV = 'N'";

                    fbController.AddParameter("@ARTI_A_HERSTELLER", $"{artikel.Hersteller.ToUpper()}%");
                    fbController.AddParameter("@ARTI_A_HERST_NR", artikel.Herstellernummer.ToUpper().Length > 30
                                                                                    ? artikel.Herstellernummer.ToUpper().Remove(29)
                                                                                    : artikel.Herstellernummer.ToUpper());
                    fbController.AddParameter("@ARTI_A_EAN", eanLieferant);
                    artikelnummer = await fbController.FetchObjectAsync(sql) as string;

                    if (!string.IsNullOrWhiteSpace(artikelnummer))
                    {
                        //Wenn keinn LFA, aber MPN dann Inserten                   
                        artikelbezeichnung = new NamensKlasse(artikel.Kurzbezeichnung, 60);

                        Lieferantenartikel lieferantenartikel = new Lieferantenartikel
                        {
                            ARLI_A_ARTIKELNR = artikelnummer,
                            ARLI_A_BESTELLNR = artikel.Bestellnummer.ToUpper(),
                            ARLI_A_BEZ1 = artikelbezeichnung.Name1,
                            ARLI_A_BEZ2 = artikelbezeichnung.Name2,
                            ARLI_A_BEZ3 = artikelbezeichnung.Name3,
                            ARLI_A_BEZ4 = artikelbezeichnung.Name4,
                            ARLI_A_BEZ5 = artikelbezeichnung.Name5,
                            WK5_ARLI_N_LIEFBESTAND = artikel.Lagerbestand,
                            ARLI_N_PREIS = artikel.NettoEinkaufspreis,
                            ARLI_N_WAEHRUNGSPREIS = artikel.NettoEinkaufspreis,
                            ARLI_N_MINDESTABNAHME = artikel.Mindestbestellmenge,
                            ARLI_N_LIEFNR = artikel.LieferantenId,
                            ARLI_N_VERSANDKOST = artikel.Versandkosten,
                            ARLI_A_WAEHRUNG = "EUR",
                            ARLI_N_KURS = 1,
                            ARLI_D_LETZAEND = DateTime.Now,
                            ARLI_TIMESTAMP = DateTime.Now
                        };

                        await Lieferantenartikel.UpdateOrCreateLieferantenArtikelAsync(lieferantenartikel, fbController);
                        _logger.Information("Lieferantenartikel angelegt. Bestellnummer: {Bestellnummer}; Artikelnummer: {Artikelnummer}; LieferantenId: {LieferantenId}", artikel.Bestellnummer, artikelnummer, artikel.LieferantenId);
                    }

                }
            }
        }

        protected static async Task DeleteInaktiveLieferantenartikelAsync(int lieferantenId, FbController2 fbController)
        {
            fbController.AddParameter("@ARLI_N_LIEFNR", lieferantenId);
            await fbController.QueryAsync($"DELETE FROM LIEFERANTENARTIKEL WHERE ARLI_N_LIEFNR = @ARLI_N_LIEFNR AND datediff(day from ARLI_D_LETZAEND to current_date) >= {LIEFERANTEN_PREIS_GÜLTIGKEITS_TAGE}");
        }

    }
}
