using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Win32Mapi;
using WK5.Core;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Services;

namespace KarleyBrowserInterface
{
    internal class Program
    {
        private static List<string> _errors = new List<string>();

        private static FbController2 _fbController = new FbController2();

        private static async Task Main(string[] args)
        {

            _fbController.AddParameter("@USERNAME", Environment.UserName.ToUpper());
            int userId = Convert.ToInt32(await _fbController.FetchObjectAsync("SELECT PERS_N_NR FROM PERSONAL WHERE UPPER(PERS_A_USERNAME) = @USERNAME"));
            if (userId > 0)
            {
                _fbController.Dispose();
                _fbController = new FbController2(userId);
            }

            //1 Arg wird übergeben - Funktionen mit : trennen und unter argumente für die funktionen mit ;
            // Beispiel karley:w4Entfernen;CDR80
            string[] karleyArgs = args[0].Split(':'); // karleyArgs[0] = karley (da darüber das Protokoll aufgerufen wird)
#if DEBUG
            foreach (var arg in karleyArgs)
            {
                Console.WriteLine(arg);
            }
#endif

            //Funktionen müssen hier als argFunktion definiert werden
            bool first = true;
            foreach (string karleyArg in karleyArgs)
            {
                #region function helper
                if (first)
                {
                    first = false;
                    continue;
                }
                string argFunktion = "";
                List<string> funktionArgs = new List<string>();

                string[] tmpArgs = karleyArg.Split(';');
                if (tmpArgs.Length > 1)
                {
                    argFunktion = tmpArgs[0];

                    for (int i = 1; i < tmpArgs.Length; i++)
                    {
                        funktionArgs.Add(tmpArgs[i]);
                    }
                }
                #endregion

                switch (argFunktion)
                {
                    case "internetArtikel":
                        await InternetArtikel(funktionArgs);
                        break;
                    case "w4Entfernen":
                        await W4Entfernen(funktionArgs);
                        break;
                    case "davidMail":
                        string xml = await File.ReadAllTextAsync(Path.Combine(GlobalConfig.Configuration.OutputPfad, funktionArgs[0]));
                        var (success, element, message) = KarleyLibrary.Serialization.XMLWriter.Deserialize<KarleyBrowserInterfaceEmail>(xml);
                        if (success)
                        {
                            DavidMail(element);
                        }
                        break;
                    default:
                        break;
                }
            }

            #region error helper
            if (_errors.Any())
            {
                foreach (string error in _errors)
                {
                    Console.WriteLine(error);
                }
                Console.ReadKey();
            }

            #endregion
        }


        #region funktionen  

        private static void DavidMail(KarleyBrowserInterfaceEmail email)
        {
            var mail = new SimpleMapi();
            mail.AddRecipient(name: email.Empfänger, addr: null, cc: false);
            foreach (var anhang in email.Anhänge)
            {
                mail.Attach(anhang);
            }
            mail.Send(email.Betreff, email.Content);
        }

        //Funktionen hier; 
        //List<string> funktionArgs = parameter für Funktion      

        /// <summary>
        /// funktionArgs[0] = ArtikelNr
        /// </summary>
        /// <param name="funktionArgs"></param>
        private static async Task InternetArtikel(List<string> funktionArgs)
        {
            //InternetArtikel entfernen

            _fbController.AddParameter("@ARTI_A_NR", funktionArgs[0].ToUpper());
            try
            {
                await _fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_INTERNET = 'N' WHERE Upper(ARTI_A_NR) = @ARTI_A_NR");

            }
            catch (Exception ex)
            {
                _errors.Add("internetArtikel Artikel: " + funktionArgs[0] + " " + ex.Message);

            }
        }

        /// <summary>
        /// funktionArgs[0] = ArtikelNr
        /// </summary>
        /// <param name="funktionArgs"></param>
        private static async Task W4Entfernen(List<string> funktionArgs)
        {
            string ARTI_A_NR = funktionArgs[0].ToUpper();
            ArtikelService artikelService = new ArtikelService();
            Artikel? artikel = await artikelService.GetAsync(ARTI_A_NR, _fbController);

            if(artikel is not null)
            {
                var deletePipeline = await SetupDeletePipelineAsync();
                if (!await deletePipeline.RunUntilFailureAsync(artikel))
                {
                    artikel.ARTI_L_INAKTIV = true;
                    await artikelService.UpdateAsync(artikel, _fbController);
                    _errors.Add($"Artikel {ARTI_A_NR} konnte nicht gelöscht werden, wurde auf inaktiv gestellt!");
                }                
            }
            else
            {
                _errors.Add($"Artikel {ARTI_A_NR} konnte nicht gefunden werden!");
            }

            
        }


        private static async Task<Pipeline<Artikel>> SetupDeletePipelineAsync()
        {
            Pipeline<Artikel> DeletePipeline = new Pipeline<Artikel>();
            await DeletePipeline.HardReset();

            DeletePipeline.Add(async (input) =>
            {
                List<Artikel> parentStücklisten = (await Artikel.GetParentStücklisten(input.Artikelnummer).ToListAsync()).ToList();
                StringBuilder sb = new StringBuilder();
                if (parentStücklisten.Any())
                {
                    foreach (var item in parentStücklisten)
                    {
                        _fbController.AddParameter("@ARTI_A_NR", item.Artikelnummer);
                        await _fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_L_INAKTIV = 'Y' WHERE ARTI_A_NR = @ARTI_A_NR");
                        sb.AppendLine($"{item.Artikelnummer}<br />");
                    }

                    if(sb.Length > 0)
                    {
                        await EmailController.FehlerMailSendenAsync("Stücklisten auf inaktiv gestellt", @$"
Bitte Stücklisten überprüfen und entsprechend korrigieren.<br /><br />

Folgende Stücklisten wurden auf inaktiv gestellt, da ein Artikel innerhalb der Stückliste auf inaktiv gestellt worden ist.<br /><br />
{sb}
<br />
", "info@karley.eu");
                    }
                    _errors.Add($"Artikel {input.Artikelnummer} ist noch in {parentStücklisten.Count} Stücklisten hinterlegt!");
                    return false;
                }

                return true;
            });


            DeletePipeline.Add(async (input) =>
            {
                using FbController2 fbController = new FbController2();
                string suchSql = @"SELECT DISTINCT BPOS_N_NR, BPOS_A_TYP FROM BELEGSTUECKLISTE
LEFT JOIN BELEGPOS ON BPOS_N_POSID = BSTU_N_POSID
WHERE BSTU_A_UNTERARTI = @ARTINR
AND(COALESCE(BPOS_A_TYP, '') != '' AND COALESCE(BPOS_N_NR, 0) != 0)
AND COALESCE(BPOS_A_TYP,'') != 'AN'";

                fbController.AddParameter("@ARTINR", input.Artikelnummer);
                DataTable data = await fbController.SelectDataAsync(suchSql);

                if (data.Rows.Count > 0)
                {
                    _errors.Add($"Artikel {input.Artikelnummer} ist noch in {data.Rows.Count} Belegen hinterlegt die keine Angebote sind!");
                    return false;
                }
                else
                {
                    // Wir haben vorher festgestellt dass der Artikel nicht in anderen Belegtypen auftritt
                    string updateSql = @"UPDATE BELEGSTUECKLISTE SET BSTU_A_UNTERARTI = 'DIVERS' WHERE BSTU_A_UNTERARTI = @ARTINR";
                    fbController.AddParameter("@ARTINR", input.Artikelnummer);
                    await fbController.QueryAsync(updateSql);
                    return true;
                }
            });

            DeletePipeline.Add(async (input) =>
            {
                using FbController2 fbController = new FbController2();
                string sql = "SELECT * FROM BELEGPOS WHERE BPOS_A_ARTIKELNR = @ARTIKELNR AND BPOS_A_TYP != 'AN'";

                fbController.AddParameter("@ARTIKELNR", input.Artikelnummer);
                DataTable data = await fbController.SelectDataAsync(sql);

                if (data.Rows.Count > 0)
                {
                    _errors.Add($"Artikel {input.Artikelnummer} ist noch in {data.Rows.Count} Belegen hinterlegt die keine Angebote sind!");
                    return false;
                }
                else
                {
                    string updateSql = "UPDATE BELEGPOS SET BPOS_A_ARTIKELNR = 'DIVERS' WHERE BPOS_A_ARTIKELNR = @ARTIKELNR AND BPOS_A_TYP = 'AN'";
                    fbController.AddParameter("@ARTIKELNR", input.Artikelnummer);
                    await fbController.QueryAsync(updateSql);
                    return true;
                }
            });

            DeletePipeline.Add((input) =>
            {
                if (input.Bestand > 0)
                {
                    _errors.Add($"Artikel {input.Artikelnummer} hat noch {input.Bestand} Bestand!");
                    return false;
                }
                else
                {
                    return true;
                }
            });

            DeletePipeline.Add(async (input) =>
            {
                BestellService bestellService = new BestellService();
                List<int> OffeneBestellungen = await bestellService.GetOffeneBestellungenFürArtikelAsync(input.Artikelnummer).ToListAsync();
                if (OffeneBestellungen.Count > 0)
                {
                    _errors.Add($"Artikel {input.Artikelnummer} hat noch {OffeneBestellungen.Count} offene Bestellungen!");
                    return false;
                }
                else
                {
                    return true;
                }
            });

            DeletePipeline.Add(async (input) =>
            {
                using FbController2 fbController = new FbController2();
                List<Charge> chargen = await Charge.GetChargenAsync(input.Artikelnummer, fbController).ToListAsync();
                if (chargen.Count > 0)
                {
                    _errors.Add($"Artikel {input.Artikelnummer} hat {chargen.Count} Chargen");
                    return false;
                }
                else
                {
                    return true;
                }
            });            

            DeletePipeline.Add(async (input) =>
            {
                ArtikelService artikelService = new ArtikelService();
                using FbController2 fbController = new FbController2();
                await fbController.StartTransactionAsync();
                try
                {
                    await artikelService.DeleteArtikel(input.Artikelnummer, fbController);
                    await fbController.CommitChangesAsync();                    
                }
                catch (Exception ex)
                {
                    _errors.Add($"Fehler beim löschen des Artikel {input.Artikelnummer}. Fehler: {ex.Message}");
                    return false;
                }
                return true;
            });

            return DeletePipeline;
        }
        #endregion
    }
}
