using KarleyLibrary.Attributes;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core.Basis.Filter;
using WK5.Core.Models;
using WK5.Core.PageModels.Stammdaten.Kunden;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionalitäten zum Umgang mit Kunden zur Verfügung.
    /// </summary>
    public class KundenService
    {
        /// <summary>
        /// Erhöht die Wichtigkeit des Kunden um 1.
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <returns></returns>
        public async Task UpdateWichtigkeitAsync(string kundennummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@INP_KUNDENNUMMER", kundennummer);
            await fbController.RunProcedureAsync("UPDATE_WICHTIGKEIT_KUNDEN");
        }
        /// <summary>
        /// Gibt auf Basis des Suchbegriffs die Anzahl aller gefunden Kunden zurück.
        /// </summary>
        /// <param name="suchbegriff">Ein optionales suchkriterium</param>
        public async Task<int> GetAnzahlKundenAsync(KundenFilter filter, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return 0;
            }

            using FbController2 fbController = new FbController2();
            var anzahlObj = await fbController.FetchObjectAsync(filter.ToCountQuery(fbController), cancellationToken);

            if (anzahlObj is null)
            {
                return 0;
            }

            _ = int.TryParse(anzahlObj.ToString(), out int anzahl);

            return anzahl;
        }
        /// <summary>
        /// Sucht für einen Kunden nach ähnlichen Kunden in der Datenbank.
        /// </summary>
        /// <param name="vergleich"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Kunde> GetÄhnlicheKundenAsync(Kunde vergleich)
        {

            using FbController2 fbController = new FbController2();
            StringBuilder sqlBuilder = new StringBuilder();
            List<string> @params = new List<string>();

            sqlBuilder.AppendLine("SELECT * FROM KUNDEN WHERE (");


            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_NAME1))
            {
                @params.Add("KUND_A_NAME1 = @KUND_A_NAME1");
                @params.Add("KUND_A_NAME2 = @KUND_A_NAME1");
                fbController.AddParameter("@KUND_A_NAME1", vergleich.KUND_A_NAME1);

            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_NAME2))
            {
                @params.Add("KUND_A_NAME1 = @KUND_A_NAME2");
                @params.Add("KUND_A_NAME2 = @KUND_A_NAME2");
                fbController.AddParameter("@KUND_A_NAME2", vergleich.KUND_A_NAME2);
            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_TEL1))
            {
                @params.Add("KUND_A_TEL1 =  @KUND_A_TEL1");
                @params.Add("KUND_A_TEL2 =  @KUND_A_TEL1");
                @params.Add("KUND_A_HANDY = @KUND_A_TEL1");
                fbController.AddParameter("@KUND_A_TEL1", vergleich.KUND_A_TEL1);

            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_TEL2))
            {
                @params.Add("KUND_A_TEL1 =  @KUND_A_TEL2");
                @params.Add("KUND_A_TEL2 =  @KUND_A_TEL2");
                @params.Add("KUND_A_HANDY = @KUND_A_TEL2");
                fbController.AddParameter("@KUND_A_TEL2", vergleich.KUND_A_TEL2);
            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_HANDY))
            {
                @params.Add("KUND_A_TEL1 =  @KUND_A_HANDY");
                @params.Add("KUND_A_TEL2 =  @KUND_A_HANDY");
                @params.Add("KUND_A_HANDY = @KUND_A_HANDY");
                fbController.AddParameter("@KUND_A_HANDY", vergleich.KUND_A_HANDY);
            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_FAX))
            {
                @params.Add("KUND_A_FAX =  @KUND_A_FAX");
                fbController.AddParameter("@KUND_A_FAX", vergleich.KUND_A_FAX);
            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_SUCHCODE))
            {
                @params.Add("KUND_A_SUCHCODE =  @KUND_A_SUCHCODE");
                fbController.AddParameter("@KUND_A_SUCHCODE", vergleich.KUND_A_SUCHCODE);
            }

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_URL))
            {
                @params.Add("KUND_A_URL =  @KUND_A_URL");
                fbController.AddParameter("@KUND_A_URL", vergleich.KUND_A_URL);
            }

            foreach (var param in @params)
            {
                if (param != @params.LastOrDefault())
                {
                    sqlBuilder.AppendLine($"{param} OR");
                }
                else
                {
                    sqlBuilder.AppendLine($"{param}");
                }
            }

            bool isFreemail = false;
            foreach (string freemail in GlobalConfig.Freemails)
            {
                if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_EMAIL))
                {
                    if (vergleich.KUND_A_EMAIL.Contains(freemail))
                    {
                        isFreemail = true;
                    }
                }
            }


            if (!isFreemail)
            {
                string domain = Regex.Match(vergleich.KUND_A_EMAIL ?? "", "(?<=@).*").Value;

                sqlBuilder.AppendLine($"OR KUND_A_EMAIL LIKE '%@{domain}'");
            }


            sqlBuilder.AppendLine(")");

            if (!String.IsNullOrWhiteSpace(vergleich.KUND_A_NR))
            {
                sqlBuilder.Append(" AND KUND_A_NR != @KUND_A_NR");
                fbController.AddParameter("@KUND_A_NR", vergleich.KUND_A_NR);
            }



            DataTable data = await fbController.SelectDataAsync(sqlBuilder.ToString());


            foreach (DataRow row in data.Rows)
            {
                yield return ObjectErweiterung.DataRowZuObjekt(new Kunde(), row);
            }
        }
        /// <summary>
        /// Sucht in der Datenbank auf Basis des <see cref="KundenFilter"/>  nach Kunden.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Kunde> GetKundenAsync(KundenFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();
            var data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController), cancellationToken);

            foreach (DataRow row in data.Rows)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
                yield return ObjectErweiterung.DataRowZuObjekt(new Kunde(), row);
            }

        }
        /// <summary>
        /// Lädt für eine Kundennummer die Kundendetails aus der Datenbank
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <returns></returns>
        public async Task<KundenDetails?> GetKundenDetailsAsync(string kundennummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@YEAR_START", new DateTime(DateTime.Now.Year, 1, 1));
            fbController.AddParameter("@YEAR_END", new DateTime(DateTime.Now.Year, 12, 31));
            fbController.AddParameter("@KUNDENNUMMER", kundennummer);
            DataRow? row = await fbController.SelectRowAsync(@"SELECT
KUND_A_EMAIL AS EMAIL,
KUND_A_FAX AS FAX,
KUND_A_TEL1 AS TEL,
KUND_D_ERFASSDATUM AS ERFASSDATUM,
ZABD_A_TEXT1 AS ZAHLUNGSBEDINGUNG,
PRLI_A_BEZEICH AS PREISLISTE,
VERT_A_NAME AS VERTRETER,
KUND_D_WIEDERVORL AS WIEDERVORLAGE,
(SELECT SUM(BELE_N_NETTO) AS JAHRESUMSATZ FROM BELEGE WHERE BELE_A_TYP = 'RE' AND BELE_A_KUNDENNR = @KUNDENNUMMER AND BELE_D_DATE > @YEAR_START AND BELE_D_DATE < @YEAR_END AND UPPER(BELE_A_STATUSFELD) = 'BEZAHLT'),
(SELECT SUM(BELE_N_NETTO) AS GESAMTUMSATZ FROM BELEGE WHERE BELE_A_TYP = 'RE' AND BELE_A_KUNDENNR = @KUNDENNUMMER AND UPPER(BELE_A_STATUSFELD) = 'BEZAHLT'),
(SELECT FIRST 1 BELE_D_DATE AS LETZTE_RECHNUNG FROM BELEGE WHERE BELE_A_TYP = 'RE' AND BELE_A_KUNDENNR = @KUNDENNUMMER ORDER BY BELE_D_DATE DESC),
(SELECT MAX(KUKO_D_DATE) AS LETZERKONTAKT FROM KUNDENKONTAKTE WHERE KUKO_A_KUNDNR = @KUNDENNUMMER),
(SELECT SUM(OP) AS OFFENEPOSTEN FROM
(
select
BELE_A_TYP, 
CASE WHEN BELE_A_TYP = 'GU' THEN
     -COALESCE(SUM(BELE_N_BRUTTO), 0) - coalesce(SUM(BezahltBetrag), 0)
ELSE
     COALESCE(SUM(BELE_N_BRUTTO), 0) - coalesce(SUM(BezahltBetrag), 0)
END AS OP
from
  KUNDENBELEGE
where
  (
    (
      BELE_A_TYP ='RE'
    and BELE_L_BEZAHLT = 'N'
    ) or
   (BELE_A_TYP ='GU' and BELE_L_VERRECHNET = 'N' )
  )
 and BELE_A_KUNDENNR = @KUNDENNUMMER  
 GROUP BY BELE_A_TYP)
),
(SELECT SUM((SELECT SUM(BPOS_N_NETTO) FROM BELEGPOS WHERE BPOS_A_TYP = 'AU' AND BPOS_N_NR = BELE_N_NR)) + SUM(BELE_N_FRACHTVK) AS OFFENEAUFTRAEGE FROM BELEGE WHERE BELE_A_TYP = 'AU' AND BELE_A_KUNDENNR = @KUNDENNUMMER  AND UPPER(BELE_A_STATUSFELD) = 'AKTIV'),
(SELECT SUM(BELE_N_BRUTTO) AS NICHTBERECHNET FROM BELEGE WHERE BELE_A_TYP = 'LS' AND BELE_A_KUNDENNR = @KUNDENNUMMER  AND BELE_L_BERECHNET = 'N')

FROM KUNDEN 
LEFT JOIN ZAHLUNGSBEDINGUNG ON (ZABD_N_NR = KUND_N_ZAHLUNG)
LEFT JOIN PREISLISTE ON (PRLI_N_NR = KUND_N_PREISLISTNR)
LEFT JOIN VERTRETER ON (VERT_N_NR = KUND_N_VERTRETNUMM)
WHERE KUND_A_NR = @KUNDENNUMMER");

            return row is null ? null : ObjectErweiterung.DataRowZuObjekt<KundenDetails>(new KundenDetails(), row);
        }
        /// <summary>
        /// Lädt für einen Kunden den gesamten Umsatz innerhalb des angegeben Jahres
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <param name="jahr"></param>
        /// <returns></returns>
        public async Task<Jahresumsatz> GetKundenJahresUmsatzAsync(string kundennummer, int jahr)
        {
            using FbController2 fbController = new FbController2();
            Jahresumsatz rechnung = await GetKundenJahresBelegWertAsync(BelegTyp.Rechnung, kundennummer, jahr, fbController,false);
            Jahresumsatz gutschrift = await GetKundenJahresBelegWertAsync(BelegTyp.Gutschrift, kundennummer, jahr, fbController,false);

            return rechnung - gutschrift;
        }

        public async Task<decimal> GetKundenGesamtUmsatzAsync(string kundennummer, CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();

            cancellationToken.ThrowIfCancellationRequested();
            DateTime? früh = await GetFrühestesBelegDatumAsync(BelegTyp.Rechnung, kundennummer, fbController, false);
            
            DateTime? spätesteRechnung = await GetSpätestesBelegDatumAsync(BelegTyp.Rechnung, kundennummer, fbController, false);
            DateTime? spätesteGutschrift = await GetSpätestesBelegDatumAsync(BelegTyp.Gutschrift, kundennummer, fbController, false);

            DateTime? spät = spätesteGutschrift > spätesteRechnung ? spätesteGutschrift : spätesteRechnung;

            if (spät is null && früh is null)
            {
                return 0.0m;
            }

            if (spät is null && früh is not null)
            {
                spät = früh;
            }

            if (früh is null && spät is not null)
            {
                früh = spät;
            }

            int startJahr = ((DateTime)früh!).Year;
            int endJahr = ((DateTime)spät!).Year;


            decimal wert = 0.0m;
            for(int i = startJahr; i<=endJahr; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Jahresumsatz umsatz = await GetKundenJahresUmsatzAsync(kundennummer, i);
                wert += umsatz.Total;
            }
            return wert;
        }

        public async IAsyncEnumerable<Jahresumsatz> GetAlleKundenJahresUmsätzeAsync(string kundennummer,[EnumeratorCancellation] CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();

            cancellationToken.ThrowIfCancellationRequested();
            DateTime? früh = await GetFrühestesBelegDatumAsync(BelegTyp.Rechnung, kundennummer, fbController, false);

            DateTime? spätesteRechnung = await GetSpätestesBelegDatumAsync(BelegTyp.Rechnung, kundennummer, fbController, false);
            DateTime? spätesteGutschrift = await GetSpätestesBelegDatumAsync(BelegTyp.Gutschrift, kundennummer, fbController, false);

            DateTime? spät = spätesteGutschrift > spätesteRechnung ? spätesteGutschrift : spätesteRechnung;

            if (spät is null && früh is null)
            {
                yield break;
            }

            if (spät is null && früh is not null)
            {
                spät = früh;
            }

            if (früh is null && spät is not null)
            {
                früh = spät;
            }

            int startJahr = ((DateTime)früh!).Year;
            int endJahr = ((DateTime)spät!).Year;

            
            for (int i = startJahr; i <= endJahr; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();
                yield return await GetKundenJahresUmsatzAsync(kundennummer, i);                
            }            
        }

        public async Task<DateTime?> GetFrühestesBelegDatumAsync(BelegTyp belegTyp, string kundennummer,FbController2 fbController, bool nurAbgeschlossene)
        {
            string sql = $"SELECT MIN(BELE_D_DATE) FROM BELEGE WHERE BELE_A_TYP = @BELEGTYP AND BELE_A_KUNDENNR = @KUND_A_NR {(nurAbgeschlossene ? " AND (BELE_L_ERLEDIGT = 'Y' OR BELE_L_VERRECHNET = 'Y' OR BELE_L_BERECHNET = 'Y' OR BELE_L_BEZAHLT = 'Y') " : String.Empty)}";
            fbController.AddParameter("@BELEGTYP", EnumHelper.GetBelegTypString(belegTyp));
            fbController.AddParameter("@KUND_A_NR", kundennummer);

            object? datetimeObject = await fbController.FetchObjectAsync(sql);

            return datetimeObject is null ? null : Convert.ToDateTime(datetimeObject);
        }

        public async Task<DateTime?> GetSpätestesBelegDatumAsync(BelegTyp belegTyp, string kundennummer, FbController2 fbController, bool nurAbgeschlossene)
        {
            string sql = $"SELECT MAX(BELE_D_DATE) FROM BELEGE WHERE BELE_A_TYP = @BELEGTYP AND BELE_A_KUNDENNR = @KUND_A_NR {(nurAbgeschlossene ? " AND (BELE_L_ERLEDIGT = 'Y' OR BELE_L_VERRECHNET = 'Y' OR BELE_L_BERECHNET = 'Y' OR BELE_L_BEZAHLT = 'Y') " : String.Empty)}";
            fbController.AddParameter("@BELEGTYP", EnumHelper.GetBelegTypString(belegTyp));
            fbController.AddParameter("@KUND_A_NR", kundennummer);

            object? datetimeObject = await fbController.FetchObjectAsync(sql);

            return datetimeObject is null or DBNull ? null : Convert.ToDateTime(datetimeObject);
        }

        public async Task<Jahresumsatz> GetKundenJahresBelegWertAsync(BelegTyp belegTyp, string kundennummer, int jahr, FbController2 fbController, bool nurAbgeschlossene)
        {
            string sql = $@"SELECT SUM((COALESCE(BELE_N_BRUTTO,0)-COALESCE(BELE_N_MWST,0)) / IIF(COALESCE(BELE_N_KURS,0)=0,1,BELE_N_KURS))  as umsatz,
EXTRACT(month from BELE_D_DATE) as monat
FROM BELEGE
WHERE BELE_A_KUNDENNR = @KUND_A_NR
AND extract(year from BELE_D_DATE) = @YEAR
AND BELE_A_TYP = @BELEGTYP
{(nurAbgeschlossene ? " AND (BELE_L_ERLEDIGT = 'Y' OR BELE_L_VERRECHNET = 'Y' OR BELE_L_BERECHNET = 'Y' OR BELE_L_BEZAHLT = 'Y') " : String.Empty)}
GROUP BY monat";
            fbController.AddParameter("@KUND_A_NR", kundennummer);
            fbController.AddParameter("@BELEGTYP", EnumHelper.GetBelegTypString(belegTyp));
            fbController.AddParameter("@YEAR", jahr);

            DataTable data = await fbController.SelectDataAsync(sql);
            Dictionary<int, decimal> werte = new Dictionary<int, decimal>();
            foreach (DataRow row in data.Rows)
            {
                werte.Add(row.Field<short>("monat"), row.Field<decimal>("umsatz"));
            }
            return new Jahresumsatz(werte) { Jahr = jahr };

        }
      

        public async IAsyncEnumerable<KundenÜbersicht> GetKundenÜbersichtAsync(KundenÜbersichtFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            //TODO: Refactor
            if (!cancellationToken.IsCancellationRequested)
            {
                using FbController2 fbController = new FbController2();
                if (!cancellationToken.IsCancellationRequested)
                {
                    List<KundenÜbersicht> suchCache = new List<KundenÜbersicht>();
                    int addedItems = 0;
                    for (int i = KundenÜbersichtFilter.MinPhase; i <= KundenÜbersichtFilter.MaxPhase; i++)
                    {


                        filter.Phase = i;
                        DataTable data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController), cancellationToken);

                        foreach (DataRow row in data.Rows)
                        {
                            if (addedItems >= filter.Limit)
                            {
                                break;
                            }

                            if (cancellationToken.IsCancellationRequested)
                            {
                                break;
                            }

                            KundenÜbersicht tmp = ObjectErweiterung.DataRowZuObjekt(new KundenÜbersicht(), row);

                            if (!suchCache.Where(x => x.KUNU_A_NR == tmp.KUNU_A_NR).Any())
                            {
                                suchCache.Add(tmp);
                                addedItems++;
                                yield return tmp;
                            }
                        }

                        if (suchCache.Count >= filter.Limit)
                        {
                            break;
                        }

                        if (!filter.DoPhaseSearch)
                        {
                            break;
                        }

                        if (i <= KundenÜbersichtFilter.AbortableUntilPhase && addedItems > 0)
                        {
                            break;
                        }
                    }
                }
            }
        }

        public async Task<int> GetKundenÜbersichtAnzahlAsync(KundenÜbersichtFilter filter, CancellationToken cancellationToken)
        {
            if (!cancellationToken.IsCancellationRequested)
            {
                using FbController2 fbController = new FbController2();
                if (!cancellationToken.IsCancellationRequested)
                {
                    int tmpcount = 0;
                    for (int i = KundenÜbersichtFilter.MinPhase; i <= KundenÜbersichtFilter.MaxPhase; i++)
                    {
                        filter.Phase = i;
                        object? cObj = await fbController.FetchObjectAsync(filter.ToCountQuery(fbController), cancellationToken);
                        int count = Convert.ToInt32(cObj);
                        tmpcount = count;
                        if (!filter.DoPhaseSearch)
                        {
                            return count;
                        }

                        if (i <= KundenÜbersichtFilter.AbortableUntilPhase && count > 0)
                        {
                            return count;
                        }
                    }
                    return tmpcount;
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;
            }
        }

        public async IAsyncEnumerable<KundenÜbersicht> GetKundenZuTelefonnummerAsync(string telefonnummer, [EnumeratorCancellation] CancellationToken cancellationToken, FbController2 fbController)
        {
            if (!cancellationToken.IsCancellationRequested)
            {
                while (telefonnummer.StartsWith("+") || telefonnummer.StartsWith("0"))
                {
                    telefonnummer = telefonnummer.TrimStart('+', '0');
                }

                telefonnummer = telefonnummer.Replace("(0)", String.Empty);
                telefonnummer = telefonnummer.Replace("(", String.Empty);
                telefonnummer = telefonnummer.Replace(")", String.Empty);

                telefonnummer = new Regex("\\D").Replace(telefonnummer, "");

                List<string> compareColumns = new List<string>()
            {
                "KURE_A_TEL",
                "KULA_A_TEL",
                "PART_A_TELEFON",
                "KUND_A_TEL1",
                "KUND_A_TEL2"
            };

                string replaceTemplate = " REPLACE(REPLACE(REPLACE(TRIM(leading '0' from TRIM(leading '+' from {0})),'(0)',''),'(',''),')','') ";

                string sql = @$"SELECT KUND_A_NR, KUND_A_NAME1, KUND_A_NAME2, KUND_A_NAME3, KUND_A_STRASSE, KUND_A_LAND, KUND_A_PLZ, KUND_A_ORT, KUND_A_USTIDNR, KUND_L_SPERRE,
(SELECT SUM(OP) AS OFFENEPOSTEN FROM
(
select
BELE_A_TYP,
CASE WHEN BELE_A_TYP = 'GU' THEN
     - COALESCE(SUM(BELE_N_BRUTTO), 0) - coalesce(SUM(BezahltBetrag), 0)
ELSE
     COALESCE(SUM(BELE_N_BRUTTO), 0) - coalesce(SUM(BezahltBetrag), 0)
END AS OP
from
  KUNDENBELEGE
where
  (
    (
      BELE_A_TYP = 'RE'
    and BELE_L_BEZAHLT = 'N'
    ) or
   (BELE_A_TYP = 'GU' and BELE_L_VERRECHNET = 'N')
  )
 and BELE_A_KUNDENNR = KUND_A_NR
 GROUP BY BELE_A_TYP)) AS OP FROM KUNDEN 
LEFT JOIN ANSPRECHPARTNER ON KUND_A_NR = PART_A_KUNDNR
LEFT JOIN LIEFERANSCHRIFTEN ON KUND_A_NR = KULA_A_KUNDNR
LEFT JOIN KUNDENRECHNANSCHR ON KUND_A_NR = KURE_A_KUNDNR
WHERE {String.Join("OR", compareColumns.Select(x => $"{String.Format(replaceTemplate, x)} = @NR "))}";
                fbController.AddParameter("@NR", telefonnummer);
                DataTable data = await fbController.SelectDataAsync(sql);

                foreach (DataRow row in data.Rows)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new KundenÜbersicht(), row);
                }
            }
        }

        public async IAsyncEnumerable<KundenArtikelHistorie> GetKundenArtikelHistorieAsync(KundenArtikelHistorieFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            if (!cancellationToken.IsCancellationRequested)
            {
                using FbController2 fbController = new FbController2();
                DataTable data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController), cancellationToken);
                foreach (DataRow row in data.Rows)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    yield return ObjectErweiterung.DataRowZuObjekt(new KundenArtikelHistorie(), row);
                }
            }
        }

        public async Task<int> GetKundenArtikelHistorieCountAsync(KundenArtikelHistorieFilter filter, CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();
            object? idObj = await fbController.FetchObjectAsync(filter.ToCountQuery(fbController), cancellationToken);

            return Convert.ToInt32(idObj);
        }

        public Task UpdateLastschriftKonditionenAsync(FbController2 fbController, LastschriftKonditionenInput konditionen)
        {
            fbController.AddParameter("@KUND_A_IBAN", konditionen.IBAN);
            fbController.AddParameter("@KUND_A_BIC", konditionen.BIC);
            fbController.AddParameter("@KUND_WK5_D_AUSSTELLUNG_MANDAT", konditionen.Ausstellungsdatum);
            fbController.AddParameter("@KUND_A_NR", konditionen.Kundennummer);
            return fbController.QueryAsync("UPDATE KUNDEN SET KUND_A_IBAN = @KUND_A_IBAN, KUND_A_BIC = @KUND_A_BIC, KUND_WK5_D_AUSSTELLUNG_MANDAT = @KUND_WK5_D_AUSSTELLUNG_MANDAT WHERE KUND_A_NR = @KUND_A_NR");
        }





        public async IAsyncEnumerable<Jahresumsatz> GetGeworbeneKundenJahresumsätze(string Kundennummer, int jahr)
        {
            await foreach (string kunde in Kunde.GetGeworbeneKunden(Kundennummer))
            {
                yield return await GetKundenJahresUmsatzAsync(kunde, jahr);
            }

        }

        #region Kundensachnummern
        /// <summary>
        /// Löscht alle Kundensachnummern für eine Kundennummer
        /// </summary>
        /// <param name="Kundennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public Task DeleteKundensachnummerAsync(string Kundennummer, FbController2 fbController)
        {
            fbController.AddParameter("@KUSA_A_KUNDE", Kundennummer);
            return fbController.QueryAsync("DELETE FROM KUNDENSACHNUMMER WHERE KUSA_A_KUNDE = @KUSA_A_KUNDE");
        }
        /// <summary>
        /// Löscht eine bestimmte Kundensachnummer
        /// </summary>
        /// <param name="kusa"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public Task DeleteKundensachnummerAsync(string artikelnummer, string kundennummer, FbController2 fbController)
        {
            fbController.AddParameter("@KUSA_A_ARTNUMMEIG", artikelnummer);
            fbController.AddParameter("@KUSA_A_KUNDE", kundennummer);
            return fbController.QueryAsync("DELETE FROM KUNDENSACHNUMMER WHERE KUSA_A_ARTNUMMEIG = @KUSA_A_ARTNUMMEIG AND KUSA_A_KUNDE = @KUSA_A_KUNDE");
        }


        public Task UpdateKundensachnummerAsync(KundenrabattInput input, FbController2 fbController, int userId)
        {
            fbController.AddParameter("@KUSA_A_ARTNUMMEIG", input.Artikelnummer);
            fbController.AddParameter("@KUSA_A_KUNDE", input.Kundennummer);
            fbController.AddParameter("@KUSA_A_ARTNUMMKUND", input.Kundenartikelnummer);
            fbController.AddParameter("@KUSA_A_WAEHRUNG", "EUR");
            fbController.AddParameter("@KUSA_N_RABATT", input.Rabatt1);
            fbController.AddParameter("@KUSA_N_RABATT1", input.StaffelRabatt1);
            fbController.AddParameter("@KUSA_N_RABATT2", input.StaffelRabatt2);
            fbController.AddParameter("@KUSA_N_RABATT3", input.StaffelRabatt3);
            fbController.AddParameter("@KUSA_N_RABATT4", input.StaffelRabatt4);
            fbController.AddParameter("@KUSA_N_MENGEVON1", input.StaffelMenge1);
            fbController.AddParameter("@KUSA_N_MENGEVON2", input.StaffelMenge2);
            fbController.AddParameter("@KUSA_N_MENGEVON3", input.StaffelMenge3);
            fbController.AddParameter("@KUSA_N_MENGEVON4", input.StaffelMenge4);
            fbController.AddParameter("@WK5_KUSA_L_ZEITLICH_BEGRENZT", input.ZeitlichBegrenzen);
            fbController.AddParameter("@WK5_KUSA_D_GUELTIG_BIS", input.GültigBis);
            fbController.AddParameter("@KUSA_N_LASTUSER", userId);


            return fbController.QueryAsync(@"UPDATE KUNDENSACHNUMMER SET
KUSA_A_ARTNUMMKUND = @KUSA_A_ARTNUMMKUND,
KUSA_A_WAEHRUNG = @KUSA_A_WAEHRUNG,
KUSA_N_RABATT = @KUSA_N_RABATT,
KUSA_N_RABATT1 = @KUSA_N_RABATT1,
KUSA_N_RABATT2 = @KUSA_N_RABATT2,
KUSA_N_RABATT3 = @KUSA_N_RABATT3,
KUSA_N_RABATT4 = @KUSA_N_RABATT4,
KUSA_N_MENGEVON1 = @KUSA_N_MENGEVON1,
KUSA_N_MENGEVON2 = @KUSA_N_MENGEVON2,
KUSA_N_MENGEVON3 = @KUSA_N_MENGEVON3,
KUSA_N_MENGEVON4 = @KUSA_N_MENGEVON4,
KUSA_N_LASTUSER = @KUSA_N_LASTUSER,
WK5_KUSA_L_ZEITLICH_BEGRENZT = @WK5_KUSA_L_ZEITLICH_BEGRENZT,
WK5_KUSA_D_GUELTIG_BIS = @WK5_KUSA_D_GUELTIG_BIS,
KUSA_TIMESTAMP = CURRENT_TIMESTAMP
WHERE KUSA_A_ARTNUMMEIG = @KUSA_A_ARTNUMMEIG 
AND KUSA_A_KUNDE = @KUSA_A_KUNDE");
        }
        public Task CreateKundensachnummerAsync(KundenrabattInput input, FbController2 fbController, int userId)
        {
            fbController.AddParameter("@KUSA_A_ARTNUMMEIG", input.Artikelnummer);
            fbController.AddParameter("@KUSA_A_KUNDE", input.Kundennummer);
            fbController.AddParameter("@KUSA_N_NR", 0);
            fbController.AddParameter("@KUSA_A_ARTNUMMKUND", input.Kundenartikelnummer);
            fbController.AddParameter("@KUSA_A_WAEHRUNG", "EUR");
            fbController.AddParameter("@KUSA_N_RABATT", input.Rabatt1);
            fbController.AddParameter("@KUSA_N_RABATT1", input.StaffelRabatt1);
            fbController.AddParameter("@KUSA_N_RABATT2", input.StaffelRabatt2);
            fbController.AddParameter("@KUSA_N_RABATT3", input.StaffelRabatt3);
            fbController.AddParameter("@KUSA_N_RABATT4", input.StaffelRabatt4);
            fbController.AddParameter("@KUSA_N_MENGEVON1", input.StaffelMenge1);
            fbController.AddParameter("@KUSA_N_MENGEVON2", input.StaffelMenge2);
            fbController.AddParameter("@KUSA_N_MENGEVON3", input.StaffelMenge3);
            fbController.AddParameter("@KUSA_N_MENGEVON4", input.StaffelMenge4);
            fbController.AddParameter("@WK5_KUSA_L_ZEITLICH_BEGRENZT", input.ZeitlichBegrenzen);
            fbController.AddParameter("@WK5_KUSA_D_GUELTIG_BIS", input.GültigBis);
            fbController.AddParameter("@KUSA_N_LASTUSER", userId);

            return fbController.QueryAsync(@"INSERT INTO KUNDENSACHNUMMER 
(
KUSA_A_ARTNUMMEIG,
KUSA_A_KUNDE,
KUSA_N_NR,
KUSA_A_ARTNUMMKUND,
KUSA_A_WAEHRUNG,
KUSA_N_RABATT,
KUSA_N_RABATT1, KUSA_N_RABATT2, KUSA_N_RABATT3, KUSA_N_RABATT4,
KUSA_N_MENGEVON1, KUSA_N_MENGEVON2, KUSA_N_MENGEVON3, KUSA_N_MENGEVON4,
KUSA_N_LASTUSER,
WK5_KUSA_L_ZEITLICH_BEGRENZT, WK5_KUSA_D_GUELTIG_BIS,
KUSA_TIMESTAMP
) 
VALUES
(
@KUSA_A_ARTNUMMEIG,
@KUSA_A_KUNDE,
@KUSA_N_NR,
@KUSA_A_ARTNUMMKUND,
@KUSA_A_WAEHRUNG,
@KUSA_N_RABATT,
@KUSA_N_RABATT1, @KUSA_N_RABATT2, @KUSA_N_RABATT3, @KUSA_N_RABATT4,
@KUSA_N_MENGEVON1, @KUSA_N_MENGEVON2, @KUSA_N_MENGEVON3, @KUSA_N_MENGEVON4,
@KUSA_N_LASTUSER,
@WK5_KUSA_L_ZEITLICH_BEGRENZT, @WK5_KUSA_D_GUELTIG_BIS,
CURRENT_TIMESTAMP
)");
        }



        #endregion


    }
}
