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

namespace WK5.Core.Services
{
    public class LagerregalService
    {
        public async Task<int> GetAnzahlAufträgeZuPackenAsync(FbController2 fbController, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            int anzahl = Convert.ToInt32(await fbController.FetchObjectAsync(@"SELECT COUNT(*) FROM WK5_AUFTRAGSFREIGABE WKA 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WKA.FREI_N_BELENR) 
LEFT JOIN LIEFERBEDINGUNG ON LIBD_N_NR = BELE_N_LIEFERUNG
WHERE BELE_L_ERLEDIGT = 'N' AND BELE_L_STORNO = 'N' AND FREI_D_PACKENAB <= CURRENT_DATE AND LIBD_L_ABHOLUNG = 'N'", cancellationToken));

            return anzahl;
        }

        public async Task<int> GetAnzahlAufträgeGepacktAsync(FbController2 fbController, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            int anzahl = Convert.ToInt32(await fbController.FetchObjectAsync(@"SELECT COUNT(*) FROM WK5_GEPACKT WGP 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WGP.GEPACKT_N_BELENR) 
and EXTRACT(day FROM GEPACKT_TIMESTAMP) = EXTRACT(day FROM CURRENT_TIMESTAMP) and EXTRACT(month FROM GEPACKT_TIMESTAMP) = EXTRACT(month FROM CURRENT_TIMESTAMP) and EXTRACT(year FROM GEPACKT_TIMESTAMP) = EXTRACT(year FROM CURRENT_TIMESTAMP)", cancellationToken));

            return anzahl;
        }

        public async Task<int> GetAnzahlAbholaufträgeZuPackenAsync(FbController2 fbController, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            int anzahl = Convert.ToInt32(await fbController.FetchObjectAsync(@"SELECT COUNT(*) FROM WK5_AUFTRAGSFREIGABE WKA 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WKA.FREI_N_BELENR) 
LEFT JOIN LIEFERBEDINGUNG ON LIBD_N_NR = BELE_N_LIEFERUNG
WHERE BELE_L_ERLEDIGT = 'N' AND BELE_L_STORNO = 'N' AND FREI_D_PACKENAB <= CURRENT_DATE AND LIBD_L_ABHOLUNG = 'Y'", cancellationToken));

            return anzahl;
        }
        public async IAsyncEnumerable<PackAuftrag> GetAufträgeZuPackenAsync(FbController2 fbController, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var data = await fbController.SelectDataAsync(@"SELECT B.*, 'Y' AS AUFTRAGINFREIGABE 
FROM WK5_AUFTRAGSFREIGABE WKA 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WKA.FREI_N_BELENR) 
LEFT JOIN LIEFERBEDINGUNG ON LIBD_N_NR = BELE_N_LIEFERUNG
WHERE BELE_L_ERLEDIGT = 'N' AND BELE_L_STORNO = 'N' AND FREI_D_PACKENAB <= CURRENT_DATE AND LIBD_L_ABHOLUNG = 'N'
ORDER BY BELE_N_NR");

            int zähler = 0;
            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                PackAuftrag packauftrag = ObjectErweiterung.DataRowZuObjekt(new PackAuftrag(), row);
                packauftrag.Id = ++zähler;
                await packauftrag.LadePositionenAsync(fbController);
                yield return packauftrag;
            }

        }
        /// <summary>
        /// Liefert alle Aufträge, die bereits gepackt wurden.
        /// </summary>
        /// <returns></returns>
        public async IAsyncEnumerable<AuftragGepackt> GetAufträgeGepacktAsync(FbController2 fbController, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            DataTable data = await fbController.SelectDataAsync(@"
SELECT WGP.*, B.BELE_A_NAME1, B.BELE_A_NAME2, B.BELE_D_DATE
FROM WK5_GEPACKT WGP 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WGP.GEPACKT_N_BELENR) 
and EXTRACT(day FROM GEPACKT_TIMESTAMP) = EXTRACT(day FROM CURRENT_TIMESTAMP) and EXTRACT(month FROM GEPACKT_TIMESTAMP) = EXTRACT(month FROM CURRENT_TIMESTAMP) and EXTRACT(year FROM GEPACKT_TIMESTAMP) = EXTRACT(year FROM CURRENT_TIMESTAMP)
ORDER BY BELE_N_NR");

            int zähler = 0;
            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                AuftragGepackt packauftrag = ObjectErweiterung.DataRowZuObjekt(new AuftragGepackt(), row);
                packauftrag.Id = ++zähler;
                yield return packauftrag;
            }
        }
        public async IAsyncEnumerable<PackAuftrag> GetAbholaufträgeZuPackenAsync(FbController2 fbController, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var data = await fbController.SelectDataAsync(@"SELECT B.*, 'Y' AS AUFTRAGINFREIGABE 
FROM WK5_AUFTRAGSFREIGABE WKA 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WKA.FREI_N_BELENR) 
LEFT JOIN LIEFERBEDINGUNG ON LIBD_N_NR = BELE_N_LIEFERUNG
WHERE BELE_L_ERLEDIGT = 'N' AND BELE_L_STORNO = 'N' AND FREI_D_PACKENAB <= CURRENT_DATE AND LIBD_L_ABHOLUNG = 'Y'
ORDER BY BELE_N_NR");
            int zähler = 0;
            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                PackAuftrag packauftrag = ObjectErweiterung.DataRowZuObjekt(new PackAuftrag(), row);
                packauftrag.Id = ++zähler;
                await packauftrag.LadePositionenAsync(fbController);
                yield return packauftrag;
            }

        }
        public async Task<List<EmailVersandResponse>> ÜberAbholungInformierenAsync(PackLieferschein packLieferschein, FbController2 fbController)
        {

            VersandMailer versandMailer = await VersandMailer.CreateAsync(packLieferschein, new List<string>(), new VersandOption(packLieferschein), fbController.UserId, fbController);
            List<EmailVersandResponse> result = await versandMailer.EmailSendenAsync();

            if (!result.Any(x => !x.Success))
            {
                fbController.AddParameter("@BELE_N_NR", packLieferschein.Belegnummer);
                await fbController.QueryAsync("UPDATE BELEGE SET BELE_L_ABHOLUNG_INFORMIERT = 'Y' WHERE BELE_A_TYP = 'LS' AND BELE_N_NR = @BELE_N_NR");
            }

            return result;
        }


        /// <summary>
        /// Lädt sich alle gepackten Aufträge eines bestimmten Datums
        /// </summary>
        /// <param name="date">Das Datum von dem sich die gepackten Aufträge geladen werden sollen</param>
        /// <returns></returns>
        public async IAsyncEnumerable<PackAuftrag> GetAufträgeGepacktAsync(DateTime date)
        {
            using FbController2 _fbController = new FbController2();
            _fbController.AddParameter("@DATE", date);
            DataTable data = await _fbController.SelectDataAsync(@"SELECT 
B.*, 'N' AS AUFTRAGINFREIGABE 
FROM WK5_GEPACKT WGP 
INNER JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = WGP.GEPACKT_N_BELENR)
and CAST(GEPACKT_TIMESTAMP as date) = @DATE");
            int zähler = 0;
            foreach (DataRow row in data.Rows)
            {
                PackAuftrag packauftrag = ObjectErweiterung.DataRowZuObjekt(new PackAuftrag(), row);
                packauftrag.Id = ++zähler;
                await packauftrag.LadePositionenAsync(_fbController);
                yield return packauftrag;
            }
        }
    
        public async Task InsertGepacktAsync(PackAuftrag auftrag, PackLieferschein lieferschein, Rechnung? rechnung, FbController2 fbController)
        {
            // Es wird ein Vermerk in WK5_GEPACKT hinterlegt, dass der Auftrag gepackt worden ist
            fbController.AddParameter("@BELEGNUMMER_AUFTRAG", auftrag.Belegnummer);
            fbController.AddParameter("@BELEGNUMMER_LIEFERSCHEIN", lieferschein.Belegnummer);
            fbController.AddParameter("@BELEGNUMMER_RECHNUNG", rechnung?.Belegnummer ?? 0);
            await fbController.QueryAsync(@"INSERT INTO WK5_GEPACKT
(
GEPACKT_N_BELENR, 
GEPACKT_N_LS_NR, 
GEPACKT_N_RE_NR, 
GEPACKT_TIMESTAMP
) 
VALUES 
(
@BELEGNUMMER_AUFTRAG, 
@BELEGNUMMER_LIEFERSCHEIN, 
@BELEGNUMMER_RECHNUNG, 
CURRENT_TIMESTAMP
)");
        }
    }
}
