#if DEBUG
#define TESTE_ARTIKEL
#endif
using ArtikelUpdateOpencart.Import;
using ArtikelUpdateOpencart.Models;
using KarleyLibrary.Erweiterungen;
using Serilog;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
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 ArtikelUpdateOpencart
{
    internal class ArtikelImport
    {

        private EmailController _emailController;
        private readonly ILogger _logger;
        private DataTable _herstellerDaten = new DataTable();
        public ArtikelImport(ILogger logger)
        {
            _emailController = new EmailController();
            _logger = logger;
        }

        public async Task RunAsync()
        {

            using MySqlController2 mySqlController = new MySqlController2();
            using FbController2 fbController = new FbController2();


            await ImportiereHerstellerAsync(fbController, mySqlController);
            await ImportiereWarengruppenAsync(fbController, mySqlController);
            List<Artikel> neueArtikel = await ImportiereArtikelAsync(fbController, mySqlController);
            await ImportUnterwarengruppenAsync(fbController, mySqlController);
            await BereinigungAsync(fbController);


            if (neueArtikel.Any()) //Email mit neuen Artikel schreiben falls vorhanden
            {
                StringBuilder mailBuilder = new StringBuilder();
                mailBuilder.AppendLine(@"Arbeitsanleitung unter:<br />
<a href=""http://wikis.local/wiki/doku.php/wk5:stammdaten:artikel:artikelimport"">http://wikis.local/wiki/doku.php/wk5:stammdaten:artikel:artikelimport</a><br /><br />
Folgende Artikel wurden von Online in die WK5 übertragen:<br />");

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

                await _emailController.SendenAsync(GlobalConfig.EmailShopverwalter, "Neue Artikel in die WK5 importiert", mailBuilder.ToString());

                // TODO: Kann man den Import nur für bestimmte Artikel starten?
                _logger.Information($"Starte {nameof(LieferantenImportJarltech)}, da neue Produkte importiert worden sind...");
                LieferantenImportJarltech lieferantenImport = new LieferantenImportJarltech(String.Empty, _logger);
                await lieferantenImport.DownloadAsync();
                await lieferantenImport.RunAsync();
            }

            await _emailController.SendenAsync(GlobalConfig.EmailLogsEU, "W4ArtImport beendet", $"W4ArtImport importiert neue Artikel und Hersteller von Online.Warengruppen werden aktualisiert.Beendet um {DateTime.Now}");
        }
    
    
        private async Task ImportiereHerstellerAsync(FbController2 fbController, MySqlController2 mySqlController)
        {
            _logger.Information("Importiere Hersteller...");
            DataTable _herstellerDaten = new DataTable();
            try
            {

                //Etwas komplizierter die Abfrage, aber wir wollen auch nur importieren, was online auch Artikel hat!
                _herstellerDaten = await mySqlController.SelectDataAsync("SELECT DISTINCT(manufacturer.name), manufacturer.manufacturer_id FROM manufacturer left join product on manufacturer.manufacturer_id = product.manufacturer_id WHERE product.manufacturer_id in (select distinct manufacturer_id from product) ORDER BY manufacturer.name ASC");
            }
            catch (Exception ex)
            {
                _logger.Error("#ARTIKELIMPORT_HERSTELLER1 - Fehler beim Laden der Herstelelr von Online: {fehler}", ex);
                throw;
            }

            if (_herstellerDaten.Rows.Count > 0)
            {
                

                for (int i = 0; i < _herstellerDaten.Rows.Count; i++)
                {
                    string name = _herstellerDaten.Rows[i]["name"].ToString();
                    string shortaName = MakeShortName(name);
                    string url = _herstellerDaten.Rows[i]["manufacturer_id"].ToString();


                    fbController.AddParameter("@HEST_A_NR", shortaName);
                    DataRow? row = await fbController.SelectRowAsync("SELECT HEST_A_NR FROM HERSTELLER WHERE HEST_A_NR = @HEST_A_NR");

                    if (row is null)
                    {
                        fbController.AddParameter("@HEST_A_NR", shortaName);
                        fbController.AddParameter("@HEST_A_NAME1", name);
                        fbController.AddParameter("@HEST_A_HOMEPAGE", url);
                        await fbController.QueryAsync(@"INSERT INTO HERSTELLER 
(
HEST_A_NR,
HEST_A_NAME1,
HEST_A_HOMEPAGE,
HEST_TIMESTAMP,
HEST_N_LASTUSER
)
VALUES
(
@HEST_A_NR,
@HEST_A_NAME1,
@HEST_A_HOMEPAGE,
CURRENT_TIMESTAMP,
4
)");
                    }

                }
                
            }
            else
            {
                _logger.Information("Herstellerimport fehlgeschlagen. DataTable weist keine Daten auf.");
             
            }

            _logger.Information("Import der Hersteller abgeschlossen!");


        }
        private async Task ImportiereWarengruppenAsync(FbController2 fbController, MySqlController2 mySqlController)
        {
            _logger.Information("Importiere Warengruppen....");
            // Wir nehmen den Status mit, damit wir Status = 0 nicht einfügen!
            DataTable data = await mySqlController.SelectDataAsync("SELECT c.category_id, cd.name, c.status from category c left join category_description cd ON c.category_id = cd.category_id where c.parent_id = 0 AND cd.language_id = 2");


            if (data.Rows.Count > 0)
            {
                for (int i = 0; i < data.Rows.Count; i++)
                {
                    String WGName = data.Rows[i]["name"].ToString().Replace("&nbsp;", "").Replace("&amp;", " ");
                    String WGID = data.Rows[i]["category_id"].ToString();

                    
                    fbController.AddParameter("@WAGR_A_NR", WGID);
                    DataRow? row = await fbController.SelectRowAsync("SELECT WAGR_A_NR FROM WARENGRUPPE WHERE WAGR_A_NR  = @WAGR_A_NR");
                    if (row is not null)
                    {
                        fbController.AddParameter("@WAGR_A_BEZEICH", WGName);
                        fbController.AddParameter("@WAGR_A_NR", WGID);
                        await fbController.QueryAsync(@"UPDATE WARENGRUPPE SET WAGR_A_BEZEICH = @WAGR_A_BEZEICH WHERE WAGR_A_NR = @WAGR_A_NR");
                    }
                    else
                    {
                        try
                        {

                            fbController.AddParameter("@WARENGRUPPEN_ID", WGID);
                            fbController.AddParameter("BEZEICHNUNG", StringErweiterung.SafeSubstring(WGName,0, 40));
                            await fbController.QueryAsync(@"INSERT INTO WARENGRUPPE 
(
    WAGR_A_NR, 
    WAGR_A_BEZEICH, 
    WAGR_A_BESCH1, 
    WAGR_A_BESCH2, 
    WAGR_TIMESTAMP, 
    WAGR_N_LASTUSER
) 
VALUES
(
    @WARENGRUPPEN_ID,
    @BEZEICHNUNG,
    @BEZEICHNUNG,
    '',
    CURRENT_TIMESTAMP,
    2
)");
                            
                        }
                        catch (Exception ex)
                        {
                            _logger.Error("#ARTIKELIMPORT_WARENGRUPPE1 - Fehler: {fehler}", ex);
                            fbController.ClearParameters();
                        }

                    }
                }
                _logger.Information("Warengruppenimport abgeschlossen!");
            }
            else
            {
                _logger.Error("Warengruppenimport abgebrochen. DataTable ist leer!");
            }

        }

        private async Task ImportUnterwarengruppenAsync(FbController2 fbController, MySqlController2 mySqlController)
        {
            _logger.Information("Importiere Unterwarengruppen...");
            List<OnlineWarengruppe> onlineWarengruppen = await mySqlController.SelectDataAsync<OnlineWarengruppe>(@"SELECT * FROM 
(
    select distinct 
        p.product_id as ProductId, 
        p.model, 
        ptc.category_id AS CategoryId,
        (select path_id from category_path where category_path.level = 0 and category_path.category_id = ptc.category_id order by category_path.category_id limit 1) as Warengruppe,
        (select path_id from category_path where category_path.level = 1 and category_path.category_id = ptc.category_id order by category_path.category_id limit 1) as Unterwarengruppe,
        (select name from category_description where category_id = (select path_id from category_path where category_path.level = 0 and category_path.category_id = ptc.category_id order by category_path.category_id limit 1)) as WarengruppeName,
        (select name from category_description where category_id = (select path_id from category_path where category_path.level = 1 and category_path.category_id = ptc.category_id order by category_path.category_id limit 1)) as UnterwarengruppeName,                                                    
        ROW_NUMBER() OVER(PARTITION BY ProductId ORDER BY ProductId DESC) rn
    from product p 
    left join product_to_category ptc on p.product_id = ptc.product_id 
    left join category_path cpa on ptc.category_id = cpa.category_id
    order by unterwarengruppe
) a
WHERE rn = 1
ORDER BY model");

         
            int zaehler = 1;

            List<Unterwarengruppe> unterwarengruppen = await Unterwarengruppe.GetUnterwarengruppenAsync(fbController).ToListAsync();

            foreach (OnlineWarengruppe onlineWarengruppe in onlineWarengruppen)
            {
                Console.Write("[{0}/{1}]\r", zaehler, onlineWarengruppen.Count);
                zaehler++;

                
                if (!string.IsNullOrWhiteSpace(onlineWarengruppe.Unterwarengruppe))
                {  
                    Unterwarengruppe? sucheUnterwarengruppe = unterwarengruppen.FirstOrDefault(x => x.UNWG_A_NR == onlineWarengruppe.Unterwarengruppe);
                    
                    string sql = string.Empty;
                    if (sucheUnterwarengruppe is null)
                    {
                        // Die Unterwarengruppe gibt es noch nicht, also fügen wir diese ein
                        sql = "INSERT INTO UNTERWARENGRUPPE VALUES (@WARENGRUPPE, @UNTERWARENGRUPPE,@UNTERWARENGRUPPE_NAME, CURRENT_TIMESTAMP, 2)";
                    }
                    else
                    {
                       
                        // update
                        sql = "UPDATE UNTERWARENGRUPPE SET UNWG_A_WARENGR = @WARENGRUPPE, UNWG_A_BEZEICH = @UNTERWARENGRUPPE_NAME WHERE UNWG_A_NR = @UNTERWARENGRUPPE";
                    }


                    fbController.AddParameter("@WARENGRUPPE", onlineWarengruppe.Warengruppe);
                    fbController.AddParameter("@UNTERWARENGRUPPE_NAME", StringErweiterung.SafeSubstring(onlineWarengruppe.UnterwarengruppeName, 0, 40));
                    fbController.AddParameter("@UNTERWARENGRUPPE", onlineWarengruppe.Unterwarengruppe);

                    try
                    {
                        await fbController.QueryAsync(sql);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error("#ARTIKELIMPORT_UNTERWARENGRUPPEN1 - Fehler beim Import der Unterwarengruppen. Fehler: {ex}", ex);
                        fbController.ClearParameters();
                    }

                }

                // Warengruppen werden an anderer Stelle hinzugefügt
                fbController.AddParameter("@WARENGRUPPE", onlineWarengruppe.Warengruppe);
                fbController.AddParameter("@ARTI_A_UNTERWARENG", onlineWarengruppe.Unterwarengruppe);
                fbController.AddParameter("@MODEL", onlineWarengruppe.Model.ToUpper());


                try
                {
                    await fbController.QueryAsync($"UPDATE ARTIKEL SET ARTI_A_WARENGRUPPE = @WARENGRUPPE {(!string.IsNullOrWhiteSpace(onlineWarengruppe.Unterwarengruppe) ? ", ARTI_A_UNTERWARENG = @ARTI_A_UNTERWARENG" : String.Empty)} WHERE UPPER(ARTI_A_NR) = @MODEL");
                }
                catch (Exception ex)
                {
                    _logger.Error("#ARTIKELIMPORT_UNTERWARENGRUPPEN2 - Fehler beim Setzen der Artikelwarengruppen. Artikelnummer: {artikelnummer} Fehler: {ex}", onlineWarengruppe.Model, ex);
                }

            }

            _logger.Information("Import der Unterwarengruppen abgeschlossen!");
        }
        private async Task<List<Artikel>> ImportiereArtikelAsync(FbController2 fbController, MySqlController2 mySqlController)
        {
            _logger.Information("Importiere Artikel...");
            //Händler und Staffelpreise fehlen noch, weil aus anderer Tabelle
            List<OnlineArtikel> ArtikelTabelle = await mySqlController.SelectDataAsync<OnlineArtikel>(@"SELECT DISTINCT 
p.product_id as ProductId, 
UPPER(p.model) as model, 
pd.name, 
p.price, 
p.weight, 
p.weight_class_id AS WeightClassId, 
p.status, 
p.manufacturer_id as ManufacturerId, 
p.mpn, 
p.ean, 
p.minimum, 
MIN(c.category_id) AS CategoryId,
p.length, 
p.width, 
p.height, 
p.length_class_id AS LenghtClassId,
m.name AS ManufacturerName
FROM product p 
LEFT JOIN product_description pd ON p.product_id = pd.product_id 
LEFT JOIN product_to_category c ON p.product_id = c.product_id 
LEFT JOIN manufacturer m ON m.manufacturer_id = p.manufacturer_id
WHERE pd.language_id = '2' 
AND p.model != '' 
AND c.category_id != 2425 
GROUP BY p.product_id 
ORDER BY `p`.`model` ASC");

            ArtikelService artikelService = new ArtikelService();
            int bearbeitet = 0;
            Mehrwertsteuer mehrwertsteuer = await Mehrwertsteuer.GetMehrwertsteuerAsync(1, fbController) ?? throw new ArgumentNullException(nameof(mehrwertsteuer));
            List<Artikel> neueArtikel = new();
            OnlineKategorien onlineKategorien = await OnlineKategorien.CreateAsync(mySqlController);
            HerstellerErsetzen ersetzen = await HerstellerErsetzen.CreateAsync();
            foreach (OnlineArtikel onlineArtikel in ArtikelTabelle)
            {
#if TESTE_ARTIKEL
                if(onlineArtikel.Model.ToUpper() != "SUNP2MINI")
                {
                    continue;
                }
#endif
                bearbeitet++;
                Console.Write("[{0}/{1}]\r", bearbeitet, ArtikelTabelle.Count);
                Artikel? artikel = await artikelService.GetAsync(onlineArtikel.Model, fbController);
                Artikel importArtikel = onlineArtikel.ToImportArtikel(mehrwertsteuer, onlineKategorien);
                importArtikel.Hersteller = MakeShortName(importArtikel.Hersteller);
                //Wenn der Datensatz existiert müssen wir nichts machen, weil die Preise aus der WK5 kommen
                if (artikel is null)
                {
                    // 12.07.2018 - Wir ersetzen den hersteller außerhalb des Webartikels, damit wir die Klasse HerstellerErsetzen nicht jedesmal neu instanziieren müssen in Webartikel -MK
                    

                    importArtikel.Hersteller = ersetzen.GetHerstellerErsetzt(importArtikel.Hersteller);
                    // Artikel existiert nicht - wir müssen ihn nun einfügen!
                    try
                    {
                        await artikelService.CreateAsync(importArtikel, fbController);
                    }
                    catch (Exception ex)
                    {
                        Log.Error("#ARTIKELIMPORT_ANLAGE1 - Fehler bei Artikelanlage. Artikelnummer: {artikelnummer}; Fehler: {fehler}", importArtikel.Artikelnummer, ex);
                        continue;
                    }
         
                    neueArtikel.Add(importArtikel);
                }
                else
                {
                    if (!String.IsNullOrWhiteSpace(importArtikel.Warengruppe) && !String.IsNullOrWhiteSpace(importArtikel.Unterwarengruppe))
                    {
                        // Update String zusammensetzen
                        artikel.Warengruppe = importArtikel.Warengruppe;
                        artikel.Unterwarengruppe = importArtikel.Unterwarengruppe;
                        await artikelService.UpdateAsync(artikel, fbController);
                    }
                }
            }
            _logger.Information("Import der Artikel abgeschlossen!");
            return neueArtikel;
        }
       
        private async Task BereinigungAsync(FbController2 fbController)
        {
            _logger.Information("Starte bereinigung...");
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'N' WHERE ARTI_A_NR IN (SELECT DISTINCT ARST_A_HAUPTARTI FROM ARTIKELSTUECKLISTE GROUP BY ARST_A_HAUPTARTI)");
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_LAGERFUEHR = 'N' WHERE ARTI_L_DIENSTLEIST = 'Y'");
            
            // Bereinigen der Warengruppen, die nicht vorhanden sind:
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_A_WARENGRUPPE = '', ARTI_A_UNTERWARENG = '' WHERE ARTI_A_WARENGRUPPE NOT IN (SELECT DISTINCT(WAGR_A_NR) FROM WARENGRUPPE)");
            await fbController.QueryAsync("DELETE FROM WARENGRUPPE WHERE WAGR_A_NR NOT IN (SELECT DISTINCT ARTI_A_WARENGRUPPE FROM ARTIKEL)");
            
            // Bereinigen der Unterwarengruppen, die nicht zu einer Oberwarengruppe gehören, aber in den Artikeln drin sind.
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_A_UNTERWARENG = '' WHERE ARTI_A_UNTERWARENG NOT IN (SELECT DISTINCT(UNWG_A_NR) FROM UNTERWARENGRUPPE WHERE UNWG_A_WARENGR = ARTI_A_WARENGRUPPE)");
            await fbController.QueryAsync("DELETE FROM UNTERWARENGRUPPE WHERE UNWG_A_NR NOT IN (SELECT DISTINCT ARTI_A_UNTERWARENG FROM ARTIKEL)");
            _logger.Information("Bereinigung beendet!");
        }
        public static string MakeShortName(string Name)
        {
            Name = RemoveTags(Name).Replace("&nbsp;", "").Replace("&amp;", ""); ;
            if (Name.Length > 10)
            {
                Name = Name.Trim().ToUpper().Substring(0, 10);
            }
            else
            {
                Name = Name.ToUpper();
            }

            return Name;
        }



        private static string RemoveTags(string Text)
        {
            Regex.Replace(Text, @"<'(.|\n)*?>", string.Empty);
            Text = Text.Replace(",", "").Replace("&nbsp;", "").Replace("&", "").Replace(";", "").Replace(" ", "");
            return Text.Trim();
        }
    }
}
