using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.OnlineShop;
using WK5.Core.OpenCart.Karley;
using WK5.Core.Services;
using WK5.Core.TodoService;

namespace TodoWk5
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly bool _debug;
        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
#if DEBUG
            _debug = true;
#endif
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                using FbController2 fbController = new FbController2();
                // Die Liste enthält alle Hauptdaten zu abgearbeiten Todos. Da wir die Todos sortiert auslesen, kann jedes Todo das danach folgt und gleich ist, einfach erledigt werden.
                List<ITodoAbgearbeitet> todosAbgearbeitet = new List<ITodoAbgearbeitet>();
                Todo[]? todos = await Todo.GetTodosAsync(fbController).ToArrayAsync(cancellationToken: stoppingToken);
               
                foreach (var todo in todos)
                {
                    ITodoAbgearbeitet todoAbgerabeitet = todo.ToAbgearbeitetTodo();

                    // Wir prüfen, ob wir bereits ein neueres Todo mit den selben Schlüsselwerten abgearbeitet haben.
                    // Wenn ja, dann handelt es sich um ein älteres Todo nur mit einem anderen Parameter. Dieses kann einfach auf erledigt gesetzt werden.
                    if (todosAbgearbeitet.Contains(todoAbgerabeitet))
                    {
                        await todo.CompleteTodoAsync();
                    }
                    else
                    {
                        todosAbgearbeitet.Add(todoAbgerabeitet);
                        if (todo.TODO_D_WANN == default || todo.TODO_D_WANN <= DateTime.Now)
                        {
                            TodoType todoType = todo.GetTodoType();

                            switch (todoType)
                            {
                                case TodoType.LieferdatumMailVersenden:
                                    // Wir wollen nur ab 20 Uhr die Kunden über ein geändertes Lieferdatum benachrichtigen
                                    if (DateTime.Now.Hour >= 20 || _debug)
                                    {
                                        await LieferdatumMailVersendenAbarbeitenAsync(todo);
                                    }
                                    break;
                                case TodoType.ZahlungFürOnlineAuftragErhalten:
                                    // 07.02.2022 MK: Dieses TODO macht keinen Sinn. Zahlungen werden bereits durch den 
                                    await todo.CompleteTodoAsync();
                                    break;
                                case TodoType.PreisÄnderung:
                                    await PreiseOnlineUpdaten(todo);
                                    break;
                                case TodoType.ArtikelInaktivStellen:
                                    await ArtikelInaktivNachAbverkauf(todo);
                                    break;
                                case TodoType.OnlineStornieren:
                                    await OnlineStornierenAsync(todo);
                                    break;
                                default:
                                    // Unbekannter Todo-Type, dieser muss noch in der Software hinterlegt werden
                                    await EmailController.FehlerMailSendenAsync(
                                        betreff: "#TodoWk5_UNKNOWN_TYPE - Fehlender TodoType in TodoWk5",
                                        body: $"Für die ID {todo.TODO_N_TYP} konnte nicht in ein {nameof(TodoType)} umgewandelt werden. Bitte den fehlenden Typ im Dienst ergänzen."
                                    );
                                    break;
                            }
                        }
                    }

                }

                // Bereinigung
                todosAbgearbeitet.Clear();
                todos = null;

                await Task.Delay(TimeSpan.FromMinutes(15), stoppingToken);
            }
        }

        #region Todo Typen abarbeiten
        private async Task LieferdatumMailVersendenAbarbeitenAsync(Todo todo)
        {
            static async Task<string> GetMailBodyAsync(Auftrag auftrag, DateTime lieferdatum)
            {
                var sb = new StringBuilder();

                var ansprechpartner = await Ansprechpartner.GetAnsprechpartnerByNameAsync(auftrag.Kundennummer, auftrag.Ansprechpartner);
                if (ansprechpartner != null && !String.IsNullOrWhiteSpace(ansprechpartner.PART_A_BRIEFANREDE))
                {
                    sb.AppendLine($"{ansprechpartner.PART_A_BRIEFANREDE} {ansprechpartner.PART_A_NAME}<br /><br />");
                }

                if (sb.Length == 0)
                {
                    sb.AppendLine("Sehr geehrte Damen und Herren,<br /><br />");
                }

                sb.AppendLine($"Wir möchten Sie kurz über eine Veränderung des voraussichtlichen Lieferdatums für Ihren Auftrag {auftrag.Belegnummer} informieren..<br />");
                sb.AppendLine($" Das neue Lieferdatum ist vorraussichtlich der {lieferdatum.ToShortDateString()}<br /><br />");
                sb.AppendLine($"<p>");
                sb.AppendLine($"Sollte der neue Liefertermin für Sie problematisch sein, kontaktieren Sie uns gerne per Email, Chat oder Telefon und wir werden versuchen eine Lösung zu finden.<br/>");
                sb.AppendLine($"Leider sind viele Produkte von Lieferengpässen betroffen. Wir halten regelmäßigen Kontakt zu unseren Lieferanten und fragen für Sie regelmäßig nach Bestätigungen der Liefertermine.<br/>");
                sb.AppendLine($"Ebenso halten wir Sie - also unseren geschätzten Kunden - immer auf dem Laufenden, wenn wir Veränderungen mitgeteilt bekommen, damit auch Sie gut informiert sind.<br/>");
                sb.AppendLine($"</p><br/>");                
                sb.AppendLine("Dies ist eine automatisch generierte Mail der Karley WK5 Warenwirtschaft.<br /><br />");
                sb.AppendLine(GlobalConfig.Configuration.FirmenDaten.ImpressumHTML());
                return sb.ToString();
            }

            using FbController2 fbController = new FbController2();

            EmailController email = new EmailController
            {
                Html = true
            };

            // Wir benötigen eine Belegnummer
            if (int.TryParse(todo.TODO_A_BELE_NR, out int BELE_N_NR))
            {

                Auftrag? auftrag = await Auftrag.GetAuftragAsync(BELE_N_NR, fbController);

                if (auftrag != null)
                {
                    // Erledigte Aufträge und Abrufaufträge dürfen nicht mehr angeschrieben werden. Todo einfach erledigen
                    if (auftrag.BELE_L_ERLEDIGT || auftrag.RechnungsnummerVerknüpfung > 0 || auftrag.BELE_L_ABRUF)
                    {
                        await todo.CompleteTodoAsync();
                        return;
                    }
                    string empfänger = await auftrag.GetVersandEmailAdresseAsync(fbController);
                    if (DateTime.TryParse(todo.TODO_A_PARAM.Split(':')[1], out DateTime lieferdatum))
                    {
                        var response = await email.SendenAsync(
                            empfängerEmail: empfänger,
                            betreff: "Änderung am voraussichtlichen Lieferdatum",
                            body: await GetMailBodyAsync(auftrag, lieferdatum)
                        );

                        if (response.Success)
                        {
                            todo.TODO_L_ERFOLGREICH = true;
                            await todo.CompleteTodoAsync();
                        }
                    }
                }
            }
        }
        private async Task PreiseOnlineUpdaten(Todo todo)
        {
            using FbController2 fbController = new FbController2();
            ArtikelService artikelService = new ArtikelService();
            var artikel = await artikelService.GetAsync(todo.TODO_A_PARAM, fbController);
            if (artikel != null)
            {
                ShopHelper shopHelper = new ShopHelper();
                try
                {
                    await shopHelper.UpdatePreiseAsync(
                        artikelnummer: artikel.Artikelnummer,
                        firmenPreis: artikel.ARTI_N_VK1,
                        directShopPrice: artikel.ARTI_N_VK5,
                        preisOption: artikel.PreisoptionOnline
                    );

                    todo.TODO_L_ERFOLGREICH = true;
                    await todo.CompleteTodoAsync();
                }
                catch (Exception ex)
                {
                    await EmailController.FehlerMailSendenAsync(
                        betreff: "#Wk5Todo_PreiseOnlineUpdaten_1 - Fehler beim Update der Preise",
                        body: ex.Message
                    );
                }


            }

        }
        
        private async Task ArtikelInaktivNachAbverkauf(Todo todo)
        {
            using FbController2 fbController = new FbController2(2);
            ArtikelService artikelService = new ArtikelService();
            string artikelnummer = todo.TODO_A_PARAM;

            Artikel? artikel = await artikelService.GetAsync(artikelnummer, fbController);
            if (artikel is not null)
            {

                if (artikel.Bestand <= 0 && artikel.ARTI_L_INAKT_ABVER && !artikel.ARTI_L_INAKTIV)
                {
                    artikel.ARTI_L_INAKTIV = true;
                    await artikelService.UpdateAsync(artikel, fbController);
                    KarleyProduct? ocProduct = await KarleyProduct.GetProductAsync(artikel.Artikelnummer);

                    if (ocProduct is not null)
                    {
                        ocProduct.Status = false;
                        ocProduct.Quantity = (int)artikel.Bestand;
                        await ocProduct.UpdateProductAsync();
                    }
                }
            }
            await todo.CompleteTodoAsync();
            #endregion
        }
    
        private async Task OnlineStornierenAsync(Todo todo)
        {
            using MySqlController2 mySqlController = new MySqlController2();
            using FbController2 fbController = new FbController2();
            if(int.TryParse(todo.TODO_A_BELE_NR, out int belegnummer))
            {
                Auftrag? auftrag = await Auftrag.GetAuftragAsync(belegnummer, fbController);
                if(auftrag is not null && auftrag.Bestellnummer.StartsWith("KL-"))
                {
                    string bestellnummerStr = auftrag.Bestellnummer[2..];

                    if(int.TryParse(bestellnummerStr, out int bestellnummer))
                    {
                        mySqlController.AddParameter("@ORDER_ID", bestellnummer);
                        await mySqlController.QueryAsync("UPDATE `order` SET `order_status_id` = 7  WHERE `order_id` = @ORDER_ID");
                    }
                }
            }


            await todo.CompleteTodoAsync();
        }
    }
}
