using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core.Basis.Filter;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.Models.Tools.Lagerregal;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionen für die Packfreigabe zur Verfügung.
    /// </summary>
    public class AuftragsfreigabeService
    {
        /// <summary>
        /// Liefert alle derzeit noch offenen Aufträge in der WK5
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<AuftragFreigegeben> GetOffeneAufträgeAsync(AuftragsFreigabeFilter? filter,[EnumeratorCancellation] CancellationToken cancellationToken)
        {

            cancellationToken.ThrowIfCancellationRequested();
            

            if(filter is null)
            {
                filter = new AuftragsFreigabeFilter();
            }

            using FbController2 fbController = new FbController2();
            

            string sql = filter.ToSqlQuery(fbController);
            var data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                AuftragFreigegeben auftrag = ObjectErweiterung.DataRowZuObjekt(new AuftragFreigegeben(), row);
                cancellationToken.ThrowIfCancellationRequested();
                await auftrag.LadePositionenAsync(fbController);
                cancellationToken.ThrowIfCancellationRequested();
                yield return auftrag;
            }


        }
        /// <summary>
        /// Liefert alle derzeit zum packen freigegeben Aufträge in der WK5.
        /// </summary>
        /// <returns></returns>
        public async IAsyncEnumerable<AuftragFreigegeben> GetFreigegebeneAufträgeAsync()
        {
            using FbController2 fbController = new FbController2();
            var data = await fbController.SelectDataAsync(@"SELECT B.*, FREI_D_PACKENAB FROM WK5_AUFTRAGSFREIGABE AF
INNER JOIN BELEGE B ON (AF.FREI_N_BELENR = B.BELE_N_NR AND B.BELE_A_TYP = 'AU')
ORDER BY BELE_N_NR DESC");

            foreach (DataRow row in data.Rows)
            {
                AuftragFreigegeben auftrag = ObjectErweiterung.DataRowZuObjekt(new AuftragFreigegeben(), row);
                await auftrag.LadePositionenAsync(fbController);
                yield return auftrag;
            }
        }
        /// <summary>
        /// Liefert alle Aufträge, die vom Vertrieb noch geprüft werden müssen.
        /// <para>
        /// Ein Auftrag landet in der Prüfung, wenn seit 30 Tagen nichts mit diesem geschehen ist, oder der Letzte Abruf überschritten wurde.
        /// </para>
        /// </summary>
        /// <param name="fbController"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Auftrag> GetZuPrüfenAsync(FbController2 fbController, [EnumeratorCancellation] CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();
            DataTable data = await fbController.SelectDataAsync(@"SELECT B.* FROM BELEGE B
LEFT JOIN ZAHLUNGSBEDINGUNG ZB ON ZB.ZABD_N_NR = B.BELE_N_ZAHLUNG
WHERE
BELE_A_TYP = 'AU'
AND BELE_L_ERLEDIGT = 'N'
AND BELE_L_STORNO = 'N'
AND (BELE_N_NR NOT IN (SELECT FREI_N_BELENR FROM WK5_AUFTRAGSFREIGABE) OR BELE_N_NR = 42718)
AND (ZB.ZABD_L_VORKASSE = 'N' OR B.BELE_L_BEZAHLT = 'Y')
AND coalesce(B.BELE_D_LIEFERDATE, '01.01.0001') < CURRENT_DATE
AND (B.BELE_L_ABRUF = 'N' OR (BELE_L_ABRUF = 'Y' AND coalesce(B.BELE_D_LETZTERABRUF, '01.01.0001') < CURRENT_DATE))
AND dateadd(30 day to B.BELE_TIMESTAMP) < CURRENT_TIMESTAMP
AND B.BELE_A_KUNDENNR <> '10100'", token);

            foreach (DataRow row in data.Rows)
            {
                token.ThrowIfCancellationRequested();
                yield return ObjectErweiterung.DataRowZuObjekt(new Auftrag(), row);
            }
        }
        /// <summary>
        /// Entfernt die Packfreigabe für einen Auftrag
        /// </summary>
        /// <param name="auftragsnummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task FreigabeEntfernenAsync(int auftragsnummer, FbController2 fbController)
        {
            fbController.AddParameter("@AUFTRAGSNUMMER", auftragsnummer);
            await fbController.QueryAsync("DELETE FROM WK5_AUFTRAGSFREIGABE WHERE FREI_N_BELENR = @AUFTRAGSNUMMER");
            fbController.AddParameter("@BELENR", auftragsnummer);
            await fbController.QueryAsync("UPDATE BELEGE SET WK5_BELE_L_PAUSIERT = 'Y' WHERE BELE_A_TYP = 'AU' AND BELE_N_NR = @BELENR");
        }
        /// <summary>
        /// Gibt einen Auftrag zum packen frei.
        /// </summary>
        /// <param name="auftragsnummer"></param>
        /// <param name="date"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task AuftragFreigebenAysnc(int auftragsnummer, DateTime date, FbController2 fbController)
        {
            fbController.AddParameter("@AUFTRAGSNUMMER", auftragsnummer);
            fbController.AddParameter("@PACKENAB", date.Date);
            fbController.AddParameter("@PERSONALNUMMER", fbController.UserId);
            await fbController.QueryAsync("UPDATE OR INSERT INTO WK5_AUFTRAGSFREIGABE (FREI_N_BELENR, FREI_D_PACKENAB, FREI_N_LASTUSER) VALUES (@AUFTRAGSNUMMER, @PACKENAB, @PERSONALNUMMER)");

            Auftrag? auftrag = await Auftrag.GetAuftragAsync(auftragsnummer, fbController);
            if (auftrag is not null)
            {
                List<string> MieteArtikel = new List<string> { "RMA_MIETE", "MIETE_ETIKETTENAPPLIKATOR", "MIETROBOT", "MIETE_DISCPUBLISHER", "MIETE_FARBETIKETTENDRUCKER" };
                foreach (Belegposition bpos in auftrag.GetEndPositionen())
                {
                    if (MieteArtikel.Contains(bpos.Artikelnummer))
                    {
                        await EmailController.FehlerMailSendenAsync("Auftragsfreigabe mit Miete", $@"
<p>Der Auftrag <a href=""https://wk5.local/Auftraege/{auftrag.Belegnummer}"">AU-{auftrag.Belegnummer}</a> wurde freigegeben und enthält eine Miete.</p>
<p>Kümmert euch bitte darum dass ihr das Mietgerät fertig macht und verpackt.</p>", "support@karley.eu");
                        break;
                    }
                }

                BelegChange change = new BelegChange
                {
                    BCNG_A_BELEGTYP = "AU",
                    BCNG_N_ART = 1239,
                    BCNG_N_USER = fbController.UserId,
                    BCNG_N_BELEGNR = auftragsnummer.ToString(),
                    BCNG_A_WERTALT = "Packfreigabe"
                };

                await BelegChange.InsertBelegChangeAsync(fbController, change);
            }

            

        }
        /// <summary>
        /// Pausiert einen Auftrag
        /// <para>
        /// Pausierte Aufträge werden nicht automatisch zum packen freigegeben. Ferner erhalten die Kunden keine automatischen Benachrichtigungen
        /// </para>
        /// </summary>
        /// <param name="auftrag"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task AuftragPausierenAsync(PackAuftrag auftrag, int userId)
        {
            using FbController2 fbController = new FbController2(userId);
            auftrag.WK5_BELE_L_PAUSIERT = !auftrag.WK5_BELE_L_PAUSIERT;

            fbController.AddParameter("@PAUSIERT", auftrag.WK5_BELE_L_PAUSIERT);
            fbController.AddParameter("@AUFTRAGSNUMMER", auftrag.Belegnummer);
            await fbController.QueryAsync("UPDATE BELEGE SET WK5_BELE_L_PAUSIERT = @PAUSIERT WHERE BELE_A_TYP = 'AU' AND BELE_N_NR = @AUFTRAGSNUMMER");
        }
        /// <summary>
        /// Setzt den Liefertermin für einen AUftrag auf den aktuellen Tag.
        /// </summary>
        /// <param name="BELE_N_NR"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task SetLieferterminHeuteAsync(int BELE_N_NR, int userId)
        {
            using FbController2 fbController = new FbController2(userId);
            fbController.AddParameter("@BELE_N_NR", BELE_N_NR);
            await fbController.QueryAsync("UPDATE BELEGE SET BELE_D_LIEFERDATE = CURRENT_DATE WHERE BELE_A_TYP = 'AU' AND BELE_N_NR = @BELE_N_NR");
        }
    }
}
