#if DEBUG
#define TestBesonderenArtikel
//#define SKIP_DOWNLOAD
#endif
using ArtikelUpdateOpencart.Import.Models;
using CsvHelper;
using CsvHelper.Configuration;
using KarleyLibrary.Erweiterungen;
using Serilog;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using WK5.Core;
using WK5.Core.Email;
using WK5.Core.Models;

namespace ArtikelUpdateOpencart.Import
{
    public class LieferantenImportJarltech : LieferantenImportBase<JarltechArtikel>
    {
        public const int LIEFERANTENNUMMER = 70003;
        public LieferantenImportJarltech(string downloadUrl, ILogger logger) : base(LIEFERANTENNUMMER, downloadUrl, logger)
        {

        }
        public override async Task DownloadAsync()
        {

            string datei = Path.Combine(GlobalConfig.W4TmpFolderSrv01, "jtimport.csv");
#if !SKIP_DOWNLOAD
            using HttpClient client = new HttpClient();
            string daten = string.Empty;
            for (int i = 0; i < 20; i++)
            {
                try
                {
                    var response = await client.GetByteArrayAsync("https://www.jarltech.com/customer_pricelist/43338_10334.csv");
                    var responseString = Encoding.GetEncoding("ISO-8859-1").GetString(response, 0, response.Length - 1);


                    await File.WriteAllTextAsync(datei, responseString, Encoding.GetEncoding("ISO-8859-1"));
                    i = 20;
                }
                catch (Exception)
                {
                    if (i == 19)
                    {
                        await EmailController.FehlerMailSendenAsync("Jarltech Download Fehler", "Fehler beim runterladen der Datei, Lieferantenupdate wurde abgebrochen.");
                        Environment.Exit(0);
                    }
                    else
                    {
                        await Task.Delay(60000); // 1 Minute warten
                    }
                }
            }
#endif

            using (TextReader reader = new StreamReader(datei, Encoding.GetEncoding("ISO-8859-1")))
            {
                CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
                configuration.BadDataFound = null;
                configuration.Encoding = Encoding.GetEncoding("ISO-8859-1");
                using (var csv = new CsvReader(reader, configuration))
                {
                    ArtikeldatenLieferant = csv.GetRecords<JarltechArtikel>().ToList();
                }
            }

   



        }

        public override async Task RunAsync()
        {
            using FbController2 fbController = new FbController2();

            await UpdateCurrencyAsync(fbController);
            
            List<string> vorhanden_hersteller = await GetVorhandeneHerstellerAsync(fbController).ToListAsync();
            HerstellerErsetzen ersetzen = await HerstellerErsetzen.CreateAsync();

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

            //String mailtext = "";
            List<string> BlockHersteller = await FileIO.LeseListe(Path.Combine(GlobalConfig.W4TmpFolderSrv01, "HerstellerBlocked.txt"));
            List<string> ignoriereArtikel = new List<string>();
            try
            {
                ignoriereArtikel = await FileIO.LeseListe(Path.Combine(GlobalConfig.W4TmpFolderSrv01, $"{LIEFERANTENNUMMER}_IgnoreArtikel.txt"));
            }
            catch (Exception)
            {
                // 17.08.2020 - MK: Ley schreibt: Bitte dran denken - ist file_io .. wenn die Liste nicht existiert darf es nicht abstürzen, denn nimmt es halt alle Artikel
            }

            List<Preisgruppe> preisgruppen = await Preisgruppe.GetPreisgruppenAsync(fbController).ToListAsync();

            EmailController emailController = new EmailController();

            int zähler = 0;

            foreach (var artikel in ArtikeldatenLieferant)
            {
                ++zähler;
                Console.Write("\r{0}/{1}\t", zähler, ArtikeldatenLieferant.Count);
#if TestBesonderenArtikel
                if (!artikel.ARTNUM.Equals("XXX", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
#endif


                //Preise nach Stueckzahl/VPE aus Datei berechnen 70007_VPEStueck.txt
                artikel.YOUR_PRICE_NET = ersetzen.GibStueckzahlVPEPreis(artikel.YOUR_PRICE_NET, LIEFERANTENNUMMER, artikel.ARTNUM);

                //Erst den Lieferantenartikel updaten damit wir mit aktuellen Daten weiter arbeiten

                GlobalLieferantenArtikel lieferantenArtikel = new GlobalLieferantenArtikel()
                {
                    LieferantenId = LIEFERANTENNUMMER,
                    Bestellnummer = artikel.ARTNUM,
                    NettoEinkaufspreis = artikel.YOUR_PRICE_NET,
                    Hersteller = artikel.MANUFACTURER,
                    Herstellernummer = ersetzen.HerstellerNummerErsetzen(artikel.MANUFACTURER, artikel.ORIGINAL_ART_NO), //jetzt mit substitute
                    Kurzbezeichnung = artikel.SHORT_DE,
                    Lagerbestand = artikel.STOCK_QTY,
                    EAN = artikel.EAN,
                    Gewicht = artikel.WEIGHT,
                    Mindestbestellmenge = artikel.MOQ,
                    Versandkosten = 4.90m
                };

                try
                {
                    await LieferantenUpdateGlobalAsync(lieferantenArtikel, ersetzen, fbController, _logger);
                }
                catch (Exception ex)
                {

                    throw new Exception($"Fehler beim Update Bestellnummer: {lieferantenArtikel.Bestellnummer}",ex);
                }


                if (ignoriereArtikel.Contains(lieferantenArtikel.Bestellnummer.ToUpper()))
                {
                    continue;
                }

                string Lang = $"{artikel.ARTNUM} {artikel.LONG_DE}";
                Lang = Lang.Replace("'", "").Trim();
                Lang = Lang.Replace("Jarltech", "Karley");
                Lang += $"Garantie: {artikel.WRRNTY_MON} Monate";

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

                NamensKlasse ArtikelBEZ = new NamensKlasse(Lang, 60); //Langen Namen Aufteilen in 60 Zeichen

                fbController.AddParameter("@ARTI_A_NR", artikel.ARTNUM.ToUpper());
                DataRow? row = fbController.SelectRow(@"SELECT 
ARTI_A_NR,
ARTI_A_EAN,
ARTI_A_PREISGRUPPE, 
ARTI_N_EK, 
ARTI_N_BRUTTO, 
ARTI_N_VK1BRUTTO, 
ARTI_N_VK1, 
ARTI_N_VK2, 
ARTI_N_VK3, 
ARTI_N_VK4, 
ARTI_N_VK5, 
MWST_N_PROZENT, 
ARTI_L_FIXPREIS, 
ARTI_L_INAKTIV, 
ARTI_A_HERSTELLER, 
ARTI_A_HERST_NR, 
ARTI_A_SELEKTION1, 
ARTI_A_SELEKTION2, 
ARTI_A_SELEKTION3, 
ARWE_N_BESTAND
FROM ARTIKELFULL WHERE ARTI_A_NR = @ARTI_A_NR");

                if (row is not null) //Schritt 1  Prüfen ob Artikel vorhande! Nur wenn ARtikel vorhanden dann -
                {
                    Wk5ArtikelObject wk5Artikel = ObjectErweiterung.DataRowZuObjekt(new Wk5ArtikelObject(artikel.ARTNUM, artikel.YOUR_PRICE_NET), row);
                    //geblockte Hersteller wollen wir nicht... ggf. Hersteller Substitube beachten. !!                         
                    if (BlockHersteller.Contains(wk5Artikel.ARTI_A_HERSTELLER))
                    {
                        continue;
                    }

                    //Herausfinden ob FixpreisArtikel und der Preisgruppe, Hersteller
                    if (string.IsNullOrWhiteSpace(wk5Artikel.ARTI_A_PREISGRUPPE))
                    {
                        wk5Artikel.ARTI_A_PREISGRUPPE = "STANDARD";
                    }

                    Preisgruppe? suchePreisgruppe = preisgruppen.FirstOrDefault(x => x.PRGR_A_NR.ToUpper() == wk5Artikel.ARTI_A_PREISGRUPPE.ToUpper());
                    if (suchePreisgruppe is null)
                    {
                        if (!string.IsNullOrWhiteSpace(wk5Artikel.ARTI_A_PREISGRUPPE))
                        {
                            string blockedPreisgruppen = "Ledercases;Hardcases;Softcases;Externe Fe;Diverses;In-Ear;Stylus;FM-Transmi;KFZ-Ladead;Ladeger;Outdoor;Docking-St;Audio-Syst;Healthcare;DVD+RW;Blu-ray Ro;Docking-St;Zusatzakku;SSD Solid;Audio;Schutzfoli;Halterunge;MAC Festpl;Gadgets;Mediakits;Farbpatron;On-Ear;CD-Label &;Audio Tape;Reinigung;Batterien;Over-Ear;Knopfzelle;Trackpads;Sonstige;Sleeves;DVD+R Doub;MS Memory;Ladegeräte;DVD-RW;CD-R 90 80;DAT Stream;Flash-Read;Mäuse;KFZ-Halter;Multimedia;Brenner;Akkus;Interne FE;Kopfhörer;Video;Sportarmbä;TV-Tuner;Video;Tastaturen;Sonderpost;Universalf;Flash-Read;Disc Repai;MO / UDO M;Video Tape;Disketten;Druckerpap;DVD Sonder;LTO-Stream;AIT-Stream;Jewel-, Sl;DLT Stream;DAT Stream;DVD-RAM;Dupliziers;Taschen &;Farbbänder;Headsets;Druckmodul;HDD Intern;Festplatten extern;Toner;Printer Supplies;BluRay / HD-DVD;SSD Speicher;Multimedia HDD;Personalisierte Artikel;Farbpatronen;HDD für MACs;LTO-Streamerbänder;Aufbewahrung;Kopier- und Fotopapier;Versand-Verpackungen;DAT Streamerbänder;DLT Streamerbänder;Flash Reader;";
                            if (!blockedPreisgruppen.ToUpper().Contains(wk5Artikel.ARTI_A_PREISGRUPPE.Trim().ToUpper()))
                            {
                                string preisgruppeFehltBetreff = $"Folgende Preiskategorie existiert nicht: {wk5Artikel.ARTI_A_PREISGRUPPE} Bitte überprüfen!";
                                preisgruppeFehltBetreff += $" zu Artikelnummer: {wk5Artikel.ARTI_A_NR}";

                                await emailController.SendenAsync(GlobalConfig.EmailShopverwalter, preisgruppeFehltBetreff, "Preiskategorie existiert nicht");
                            }
                        }

                        suchePreisgruppe = preisgruppen.First(x => x.PRGR_A_NR.ToUpper() == "STANDARD");
                    }
                    // Laut Jarltech ist REC_EUP_PLUS_VAT der Listenpreis
                    await wk5Artikel.CalcVKMitPreisgruppeAsync(suchePreisgruppe, artikel.REC_EUP_PLUS_VAT);

                    decimal Colli = 1;
                    decimal anlager = 0;
                    decimal jahresverbrauch = 0;

                    //(! deprecated !)Colli vom Günstigsten Lieferanten ansonsten Jahrltech
                    //Neu 13.05.2015 : Wir übergeben nur Mindestabnahmen von Jarltech automatisch, also beachten wir auch nur den Wert von Jarltech                                
                    Lieferantenartikel? lieferantenartikel = await Lieferantenartikel.GetLieferantenartikelAsync(wk5Artikel.ARTI_A_NR, LIEFERANTENNUMMER, fbController);
                    if (lieferantenartikel is null)
                    {
                        await Lieferantenartikel.UpdateOrCreateLieferantenArtikelAsync(new Lieferantenartikel
                        {
                            ARLI_A_ARTIKELNR = wk5Artikel.ARTI_A_NR,
                            ARLI_A_EINHEIT = "Stk",
                            ARLI_A_WAEHRUNG = "EUR",
                            ARLI_N_KURS = 1,
                            ARLI_N_LIEFNR = LIEFERANTENNUMMER,
                            ARLI_N_MINDESTABNAHME = artikel.MOQ,
                            ARLI_N_PREIS = artikel.YOUR_PRICE_NET,
                            ARLI_N_VERSANDKOST = 4.9m,
                            ARLI_A_BESTELLNR = artikel.ARTNUM.ToUpper(),
                            WK5_ARLI_N_LIEFBESTAND = artikel.STOCK_QTY
                        }, fbController); 
                    }

                    fbController.AddParameter("@ARLI_A_ARTIKELNR", wk5Artikel.ARTI_A_NR);
                    decimal tmpColli = Convert.ToDecimal(await fbController.FetchObjectAsync("select ARLI_N_MINDESTABNAHME FROM LIEFERANTENARTIKEL WHERE LIEFERANTENARTIKEL.arli_a_artikelnr = @ARLI_A_ARTIKELNR"));
                    if (tmpColli > 0)
                    {
                        Colli = tmpColli;
                    }

                    //Wenn Artikel an Lager oder Jahresverbrauch > Mindestmenge Colli = 1 
                    anlager = wk5Artikel.Bestand;

                    //Jahresverbrauch holen
                    fbController.AddParameter("@BPOS_A_ARTIKELNR", wk5Artikel.ARTI_A_NR);
                    object? tmp = await fbController.FetchObjectAsync("SELECT SUM(BPOS_N_MENGE) FROM belegpos WHERE BPOS_A_ARTIKELNR = @BPOS_A_ARTIKELNR AND BPOS_TIMESTAMP > dateadd(-12 month to current_date) AND BPOS_A_TYP = 'RE'");
                    if (tmp is not DBNull)
                    {
                        jahresverbrauch = Convert.ToDecimal(tmp);
                    }


                    if (anlager > 0)
                    {
                        Colli = 1;
                    }


                    if (artikel.WARRANTY_EXTENSION == "1")
                    {
                        ArtikelBEZ.Name5 = "Garantie:" + artikel.WRRNTY_MON + " Monate";
                    }

                    StringBuilder updatebuilder = new StringBuilder();
                    updatebuilder.Append(@"UPDATE ARTIKEL SET 
ARTI_TIMESTAMP = CURRENT_TIMESTAMP,
ARTI_N_VK4 = @ARTI_N_VK4,
ARTI_L_FIXVK4 = 'Y',
ARTI_N_COLLI = @ARTI_N_COLLI,
ARTI_L_FIXPREIS = @ARTI_L_FIXPREIS,
ARTI_L_INAKTIV = 'N'");

                    if (string.IsNullOrWhiteSpace(wk5Artikel.ARTI_A_EAN) && artikel.EAN.All(char.IsDigit) && StringErweiterung.IsValidEan(artikel.EAN))
                    {
                        updatebuilder.Append(", ARTI_A_EAN = @ARTI_A_EAN");
                        fbController.AddParameter("@ARTI_A_EAN", StringErweiterung.ParseEan(artikel.EAN));
                    }

                    if (!wk5Artikel.KeinTextUpdate)
                    {
                        updatebuilder.Append(@", ARTI_A_BEZ1 = @Name1, ARTI_A_BEZ2 = @Name2, ARTI_A_BEZ3 = @Name3, ARTI_A_BEZ4 = @Name4, ARTI_A_BEZ5 = @Name5");
                        fbController.AddParameter("@Name1", ArtikelBEZ.Name1);
                        fbController.AddParameter("@Name2", ArtikelBEZ.Name2);
                        fbController.AddParameter("@Name3", ArtikelBEZ.Name3);
                        fbController.AddParameter("@Name4", ArtikelBEZ.Name4);
                        fbController.AddParameter("@Name5", ArtikelBEZ.Name5);
                    }

                    if (artikel.WEIGHT > 0)
                    {
                        updatebuilder.Append(", ARTI_N_GEWICHT = @ARTI_N_GEWICHT");
                        fbController.AddParameter("@ARTI_N_GEWICHT", artikel.WEIGHT);
                    }

                    updatebuilder.Append(" WHERE ARTI_A_NR = @ARTI_A_NR");


                    fbController.AddParameter("@ARTI_N_VK4", artikel.REC_EUP_PLUS_VAT);
                    fbController.AddParameter("@ARTI_N_COLLI", Colli);
                    fbController.AddParameter("@ARTI_L_FIXPREIS", wk5Artikel.ARTI_L_FIXPREIS);
                    fbController.AddParameter("@ARTI_A_NR", wk5Artikel.ARTI_A_NR.ToUpper());


                    try
                    {
                        await fbController.QueryAsync(updatebuilder.ToString());
                    }
                    catch (Exception ex)
                    {
                        _logger.Error($"#jarltech1 - {ex}");
                        _logger.Error($"#jarltech1B - {updatebuilder}");
                    }
                    finally
                    {
                        // Bei Fehlern werden die Parameter nicht gelöscht, daher müssen wir das hier per hand machen
                        fbController.ClearParameters();
                    }





                }
            }
            await DeleteInaktiveLieferantenartikelAsync(LIEFERANTENNUMMER, fbController);



        }


        private async Task UpdateCurrencyAsync(FbController2 fbController)
        {
            _logger.Information("jarltech-währungsupdate");
            string url = "https://www.ecb.int/stats/eurofxref/eurofxref-daily.xml";
            DateTime UpdateDatum;// = DateTime.Now;

            XDocument doc = XDocument.Load(url);

            XNamespace gesmes = "http://www.gesmes.org/xml/2002-08-01";
            XNamespace ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";
#nullable disable
            var cubes = doc.Descendants(ns + "Cube")
                           .Where(x => x.Attribute("currency") != null)
                           .Select(x => new
                           {
                               Currency = (string)x.Attribute("currency"),
                               Rate = (decimal)x.Attribute("rate")
                           });
            var cubeTime = doc.Descendants(ns + "Cube")
                           .Where(x => x.Attribute("time") != null)
                           .Select(x => new
                           {
                               Datum = (string)x.Attribute("time")
                           });
#nullable enable
            DateTime.TryParse(cubeTime.First().Datum, out UpdateDatum);
            //UpdateDatum = cubeTime.First().Datum;

            foreach (var result in cubes)
            {
                if (result.Currency == "CHF" || result.Currency == "USD")
                {
                    double Waehrung1 = Convert.ToDouble(result.Rate);
                    double Waehrung2 = 1 / Waehrung1;

                    string updateSql = "UPDATE WAEHRUNG SET WAEH_N_KURS = @Waehrung1, WAEH_N_WECHSELKURS = @Waehrung2, WAEH_D_KURSVOM = @Datum, WAEH_TIMESTAMP = CURRENT_TIMESTAMP WHERE WAEH_A_ZEICHEN = @WAEHZEICHEN";
                    
                    fbController.AddParameter("@Waehrung1", Convert.ToDecimal(Waehrung1));
                    fbController.AddParameter("@Waehrung2", Convert.ToDecimal(Waehrung2));
                    fbController.AddParameter("@Datum", UpdateDatum);
                    fbController.AddParameter("@WAEHZEICHEN", result.Currency);
                    await fbController.QueryAsync(updateSql);
                    _logger.Information("{Currency}: {Rate}", result.Currency, result.Rate);
                }
            }

            _logger.Information("jarltech-währungsupdate beendet");
        }

    }
}
