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.Models;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionen zum Umgang mit wiederkehrenden Rechnungen zur Verfügung
    /// </summary>
    public class WiederkehrendeRechnungenService
    {
        /// <summary>
        /// Lädt eine wiederkehrende Rechnung aus der Datenbank.
        /// </summary>
        /// <param name="WIED_N_NR"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<WiederkehrendeRechnung?> GetWiederkehrendeRechnungAsync(int WIED_N_NR, FbController2 fbController)
        {
            fbController.AddParameter("@WIED_N_NR", WIED_N_NR);
            var row = await fbController.SelectRowAsync(@"SELECT WR.*, 
K.KUND_A_NAME1, K.KUND_A_NAME2, K.KUND_A_LAND, K.KUND_A_STRASSE, K.KUND_A_PLZ, K.KUND_A_ORT,
B.BELE_N_NR_AU, B.BELE_N_RECHADRESSE
FROM WK5_WDH_RECHNUNGEN WR
LEFT JOIN BELEGE B ON(B.BELE_N_NR = WR.WIED_N_NR AND B.BELE_A_TYP = 'RE')
LEFT JOIN KUNDEN K ON(K.KUND_A_NR = B.BELE_A_KUNDENNR)
WHERE WIED_N_NR = @WIED_N_NR");

            return row is null ? null : ObjectErweiterung.DataRowZuObjekt(new WiederkehrendeRechnung(), row);
        }
        /// <summary>
        /// Lädt alle wiederkehrenden Rechnungen aus der Datenbank
        /// </summary>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<WiederkehrendeRechnung> GetWiederkehrendeRechnungenAsync(WiederkehrendeRechnungenFilter filter, FbController2 fbController, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController), cancellationToken);
            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                yield return ObjectErweiterung.DataRowZuObjekt(new WiederkehrendeRechnung(), row);
            }
        }
        /// <summary>
        /// Ruft die Anzahl aller Ergebnisse für <see cref="GetWiederkehrendeRechnungenAsync(WiederkehrendeRechnungenFilter, FbController2, CancellationToken)"/> ab
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="fbController"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<int> GetAnzahlWiederkehrendeRechnungenAsync(WiederkehrendeRechnungenFilter filter, FbController2 fbController, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            int anzahl = Convert.ToInt32(await fbController.FetchObjectAsync(filter.ToCountQuery(fbController), cancellationToken));
            return anzahl;
            
        }
        /// <summary>
        /// Aktualisiert eine wiederkehrende Rechnung in der Datenbank.
        /// <para>
        /// Hinsweis: Der übergebene <see cref="FbController2"/> sollte vor Aufruf der Methode eine Transaction gestartet haben
        /// </para>
        /// </summary>
        /// <param name="wdhRechnung"></param>
        /// <param name="userId"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<bool> UpdateWiederkehrendeRechnungAsync(WiederkehrendeRechnung wdhRechnung, int userId, FbController2 fbController)
        {

            fbController.AddParameter("@WIED_N_NR", wdhRechnung.WIED_N_NR);
            fbController.AddParameter("@WIED_N_INTERVALL", wdhRechnung.WIED_N_INTERVALL);
            fbController.AddParameter("@WIED_N_MINDESTLAUFZEIT", wdhRechnung.WIED_N_MINDESTLAUFZEIT);
            fbController.AddParameter("@WIED_D_PREISAENDERUNG_ZUM", wdhRechnung.WIED_D_PREISAENDERUNG_ZUM);
            fbController.AddParameter("@WIED_L_STATUS", wdhRechnung.WIED_L_STATUS.ToFirebirdBool());
            fbController.AddParameter("@WIED_N_LASTUSER", userId);
            fbController.AddParameter("@WIED_N_ID", wdhRechnung.WIED_N_ID);
            fbController.AddParameter("@WIED_D_START", wdhRechnung.WIED_D_START);
            await fbController.QueryAsync(@"UPDATE WK5_WDH_RECHNUNGEN SET
WIED_N_NR = @WIED_N_NR, WIED_N_INTERVALL = @WIED_N_INTERVALL, WIED_N_MINDESTLAUFZEIT = @WIED_N_MINDESTLAUFZEIT,
WIED_D_PREISAENDERUNG_ZUM = @WIED_D_PREISAENDERUNG_ZUM, WIED_L_STATUS = @WIED_L_STATUS, WIED_N_LASTUSER = @WIED_N_LASTUSER,
WIED_D_START = @WIED_D_START
WHERE WIED_N_ID = @WIED_N_ID");
            fbController.AddParameter("@BELE_N_NR", wdhRechnung.WIED_N_NR);
            await fbController.QueryAsync("UPDATE BELEGE SET WK5_BELE_L_WDH_RE = 'Y' WHERE BELE_A_TYP = 'RE' AND BELE_N_NR = @BELE_N_NR");

            return true;
        }
        public async Task<bool> WiederkehrendeRechnungExistsAsync(int rechnungsnummer, FbController2 fbController)
        {
            fbController.AddParameter("@RECHNUNGSNUMMER", rechnungsnummer);
            DataRow? row = await fbController.SelectRowAsync("SELECT * FROM WK5_WDH_RECHNUNGEN WHERE WIED_N_NR = @RECHNUNGSNUMMER");

            return row is not null;
        }
        /// <summary>
        /// Erstellt eine neue wiederkehrende Rechnung in der Datenbank.
        /// <para>
        /// Hinsweis: Der übergebene <see cref="FbController2"/> sollte vor Aufruf der Methode eine Transaction gestartet haben
        /// </para>
        /// <param name="wdhRechnung"></param>
        /// <param name="userId"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<bool> CreateWiederkehrendeRechnungAsync(WiederkehrendeRechnung wdhRechnung, int userId, FbController2 fbController)
        {

            fbController.AddParameter("@WIED_N_NR", wdhRechnung.WIED_N_NR);
            fbController.AddParameter("@WIED_N_INTERVALL", wdhRechnung.WIED_N_INTERVALL);
            fbController.AddParameter("@WIED_N_MINDESTLAUFZEIT", wdhRechnung.WIED_N_MINDESTLAUFZEIT);
            fbController.AddParameter("@WIED_D_PREISAENDERUNG_ZUM", wdhRechnung.WIED_D_PREISAENDERUNG_ZUM);
            fbController.AddParameter("@WIED_L_STATUS", wdhRechnung.WIED_L_STATUS.ToFirebirdBool());
            fbController.AddParameter("@WIED_D_START", wdhRechnung.WIED_D_START);
            fbController.AddParameter("@WIED_N_LASTUSER", userId);
            await fbController.QueryAsync(@"INSERT INTO WK5_WDH_RECHNUNGEN 
(WIED_N_NR, WIED_N_INTERVALL, WIED_N_MINDESTLAUFZEIT, WIED_D_PREISAENDERUNG_ZUM, WIED_L_STATUS, WIED_D_START, WIED_D_ANLAGEDATUM, WIED_N_LASTUSER)
VALUES
(@WIED_N_NR, @WIED_N_INTERVALL, @WIED_N_MINDESTLAUFZEIT, @WIED_D_PREISAENDERUNG_ZUM, @WIED_L_STATUS, @WIED_D_START, CURRENT_DATE, @WIED_N_LASTUSER)");

            fbController.AddParameter("@BELE_N_NR", wdhRechnung.WIED_N_NR);
            await fbController.QueryAsync("UPDATE BELEGE SET WK5_BELE_L_WDH_RE = 'Y' WHERE BELE_A_TYP = 'RE' AND BELE_N_NR = @BELE_N_NR");

            return true;
        }
        /// <summary>
        /// Kündigt eine wiederkehrende Rechnung zum angegeben Zeitraum.
        /// </summary>
        /// <param name="WIED_N_ID"></param>
        /// <param name="letzteRechnung">Nach diesem Datum werden keine weiteren Rechnungen mehr generiert.</param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<bool> WiederkehrendeRechnungKündigenAsync(int WIED_N_ID, DateTime letzteRechnung, FbController2 fbController)
        {
            var wdhRechnung = await GetWiederkehrendeRechnungAsync(WIED_N_ID, fbController);
            if (wdhRechnung is not null)
            {
                fbController.AddParameter("@WIED_N_ID", WIED_N_ID);
                fbController.AddParameter("@WIED_D_FINALERECHNUNG", letzteRechnung);
                await fbController.QueryAsync("UPDATE WK5_WDH_RECHNUNGEN SET WIED_D_KUENDIGUNGSDATUM = CURRENT_DATE, WIED_D_FINALERECHNUNG = @WIED_D_FINALERECHNUNG WHERE WIED_N_NR = @WIED_N_ID");
            }

            return true;
        }
        /// <summary>
        /// Kündigt eine Wiederkehrende Rechnung pünktlich zum Vertragsende.
        /// </summary>
        /// <param name="WIED_N_ID"></param>
        /// <returns></returns>
        public async Task<bool> WiederkehrendeRechnungKündigenAsync(int WIED_N_ID, FbController2 fbController)
        {
            var wdhRechnung = await GetWiederkehrendeRechnungAsync(WIED_N_ID, fbController);
            if (wdhRechnung != null)
            {
                // Das Datum der letzten Rechnung berechnen
                DateTime endDatum = wdhRechnung.WIED_D_START.AddMonths(wdhRechnung.LaufzeitMenge * wdhRechnung.WIED_N_MINDESTLAUFZEIT);
                return await WiederkehrendeRechnungKündigenAsync(WIED_N_ID, endDatum, fbController);
            }

            return true;
        }
    }
}
