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;
using WK5.Core.Basis.Filter;
using WK5.Core.Models;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionen zum Anlegen und Abrufen von Wartungen zur Verfügung.
    /// </summary>
    public class WartungsService : IModelService<Wartung>
    {
        /// <summary>
        /// Erstellt eine neue Wartung
        /// <para>
        /// Der Anlageuser ist hierbei die aktive UserId des FbController2.
        /// </para>
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task CreateAsync(Wartung input, FbController2 fbController)
        {
            input.Anlagedatum = DateTime.Now;
            input.Timestamp = input.Anlagedatum;
            input.AnlageuserId = fbController.UserId;
            input.LetzterBearbeiter = fbController.UserId;

            string sql = @"INSERT INTO WARTUNGEN
(
WART_N_ANLAGEUSER,
WART_D_DATE,
WART_A_KUNDENNR,
WART_A_ARTIKELNR,
WART_A_SN,
WART_L_ANGENOMMEN,
WART_D_ANGENOMMEN,
WART_L_STORNO,
WART_D_STORNO,
WART_L_ERLEDIGT,
WART_D_ERLEDIGT,
WART_L_MANUELL,
WART_L_BENACHRICHTIGT,
WART_B_NOTIZ,
WART_N_LASTUSER,
WART_TIMESTAMP
)
VALUES
(
@WART_N_ANLAGEUSER,
@WART_D_DATE,
@WART_A_KUNDENNR,
@WART_A_ARTIKELNR,
@WART_A_SN,
@WART_L_ANGENOMMEN,
@WART_D_ANGENOMMEN,
@WART_L_STORNO,
@WART_D_STORNO,
@WART_L_ERLEDIGT,
@WART_D_ERLEDIGT,
@WART_L_MANUELL,
@WART_L_BENACHRICHTIGT,
@WART_B_NOTIZ,
@WART_N_LASTUSER,
@WART_TIMESTAMP
) 
RETURNING WART_N_NR";

            fbController.AddParameter("@WART_N_ANLAGEUSER", input.AnlageuserId);
            fbController.AddParameter("@WART_D_DATE", input.Anlagedatum);
            fbController.AddParameter("@WART_A_KUNDENNR", input.Kundennummer);
            fbController.AddParameter("@WART_A_ARTIKELNR", input.Artikelnummer);
            fbController.AddParameter("@WART_A_SN", input.Seriennummer);
            fbController.AddParameter("@WART_L_ANGENOMMEN", input.Angenommen);
            fbController.AddParameter("@WART_D_ANGENOMMEN", input.AngenommenDatum);
            fbController.AddParameter("@WART_L_STORNO", input.Storniert);
            fbController.AddParameter("@WART_D_STORNO", input.StorniertDatum);
            fbController.AddParameter("@WART_L_ERLEDIGT", input.Erledigt);
            fbController.AddParameter("@WART_D_ERLEDIGT", input.ErledigtDatum);
            fbController.AddParameter("@WART_L_MANUELL", input.ManuelleWartung);
            fbController.AddParameter("@WART_L_BENACHRICHTIGT", input.Benachrichtigt);
            fbController.AddParameter("@WART_B_NOTIZ", input.Notiz);
            fbController.AddParameter("@WART_N_LASTUSER", input.LetzterBearbeiter);
            fbController.AddParameter("@WART_TIMESTAMP", input.Timestamp);

            input.WartungsNr = Convert.ToInt32(await fbController.FetchObjectAsync(sql));
        }
        /// <summary>
        /// Aktualisiert eine bestehende Wartung.
        /// <para>
        /// Der Letzte Bearbeiter ist hierbei die aktive UserId des FbController2.
        /// </para>
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task UpdateAsync(Wartung input, FbController2 fbController)
        {
            input.Timestamp = DateTime.Now;
            input.LetzterBearbeiter = fbController.UserId;

            string sql = @"
UPDATE WARTUNGEN SET
    WART_L_ANGENOMMEN = @WART_L_ANGENOMMEN,
    WART_D_ANGENOMMEN = @WART_D_ANGENOMMEN,
    WART_L_STORNO = @WART_L_STORNO,
    WART_D_STORNO = @WART_D_STORNO,
    WART_L_ERLEDIGT = @WART_L_ERLEDIGT,
    WART_D_ERLEDIGT = @WART_D_ERLEDIGT,
    WART_L_BENACHRICHTIGT = @WART_L_BENACHRICHTIGT,
    WART_B_NOTIZ = @WART_B_NOTIZ,
    WART_N_LASTUSER = @WART_N_LASTUSER,
    WART_TIMESTAMP = @WART_TIMESTAMP,
    WART_N_ANSPRECHPARTNER = @WART_N_ANSPRECHPARTNER
WHERE WART_N_NR = @WART_N_NR";

            fbController.AddParameter("@WART_L_ANGENOMMEN", input.Angenommen);
            fbController.AddParameter("@WART_D_ANGENOMMEN", input.AngenommenDatum);
            fbController.AddParameter("@WART_L_STORNO", input.Storniert);
            fbController.AddParameter("@WART_D_STORNO", input.StorniertDatum);
            fbController.AddParameter("@WART_L_ERLEDIGT", input.Erledigt);
            fbController.AddParameter("@WART_D_ERLEDIGT", input.ErledigtDatum);
            fbController.AddParameter("@WART_L_BENACHRICHTIGT", input.Benachrichtigt);
            fbController.AddParameter("@WART_B_NOTIZ", input.Notiz);
            fbController.AddParameter("@WART_N_LASTUSER", input.LetzterBearbeiter);
            fbController.AddParameter("@WART_TIMESTAMP", input.Timestamp);
            fbController.AddParameter("@WART_N_ANSPRECHPARTNER", input.AnsprechpartnerId);
            fbController.AddParameter("@WART_N_NR", input.WartungsNr);
            await fbController.QueryAsync(sql);
        }
        /// <summary>
        /// Lädt die Wartung für die entsprechende Wartungsnummer.
        /// </summary>
        /// <param name="wartungsnummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<Wartung?> GetWartungAsync(int wartungsnummer, FbController2 fbController)
        {
            fbController.AddParameter("@WART_N_NR", wartungsnummer);
            DataRow? row = await fbController.SelectRowAsync(@"SELECT 
W.*, 
KUND_A_NAME1, KUND_L_KEINE_WARTUNGEN 
FROM WARTUNGEN W
LEFT JOIN KUNDEN K ON K.KUND_A_NR = W.WART_A_KUNDENNR
WHERE WART_N_NR = @WART_N_NR");

            return row is null ? null : ObjectErweiterung.DataRowZuObjekt(new Wartung(), row);
        }
        /// <summary>
        /// Setzt die Verknüpfung eines AUftrages für eine Wartung.
        /// </summary>
        /// <param name="wartungsnummer"></param>
        /// <param name="auftragsnummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task SetAuftragVerknüpfungAsync(int wartungsnummer, int auftragsnummer, FbController2 fbController)
        {
            fbController.AddParameter("@WART_N_AUFTRAG", auftragsnummer);
            fbController.AddParameter("@WART_N_NR", wartungsnummer);
            await fbController.QueryAsync("UPDATE WARTUNGEN SET WART_N_AUFTRAG = @WART_N_AUFTRAG WHERE WART_N_NR = @WART_N_NR");
        }
        /// <summary>
        /// Prüft ob für eine bestimmte Seriennummer eines Kunden die Wartungen noch aktiviert sind.
        /// </summary>
        /// <param name="kundennnummer"></param>
        /// <param name="seriennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<bool> WartungenFürSeriennummerEnabled(string kundennnummer, string seriennummer, FbController2 fbController)
        {
            fbController.AddParameter("@STWA_A_KUNDENNR", kundennnummer);
            fbController.AddParameter("@STWA_A_SN", seriennummer);
            DataRow? row = await fbController.SelectRowAsync("SELECT * FROM STOP_WARTUNG WHERE STWA_A_KUNDENNR = @STWA_A_KUNDENNR AND STWA_A_SN = @STWA_A_SN");
            return row is null;
        }
        /// <summary>
        /// Deaktiviert die automatische Anlage von zukünftigen Wartungen einer Seriennummer für einen bestimmten Kunden
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <param name="seriennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task DeaktiviereWartungenFürSeriennummer(string kundennummer, string seriennummer, FbController2 fbController)
        {
            fbController.AddParameter("@STWA_A_KUNDENNR", kundennummer);
            fbController.AddParameter("@STWA_A_SN", seriennummer);
            await fbController.QueryAsync("UPDATE OR INSERT INTO STOP_WARTUNG (STWA_A_KUNDENNR, STWA_A_SN) VALUES (@STWA_A_KUNDENNR, @STWA_A_SN)");
        }
        /// <summary>
        /// Aktiviert die automatische Erstellung von neuen Wartungen für eine bestimmte Seriennummer eines Kunden.
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <param name="seriennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task EnableWartungenFürSeriennummer(string kundennummer, string seriennummer, FbController2 fbController)
        {
            fbController.AddParameter("@STWA_A_KUNDENNR", kundennummer);
            fbController.AddParameter("@STWA_A_SN", seriennummer);
            await fbController.QueryAsync("DELETE FROM STOP_WARTUNG WHERE STWA_A_KUNDENNR = @STWA_A_KUNDENNR AND STWA_A_SN = @STWA_A_SN");
        }
        /// <summary>
        /// Setzt das Flag im Kunden, das angibt, ob der Kunde über Wartungen informiert werden möchte oder nicht.
        /// </summary>
        /// <param name="enabled">true = keine Wartungen</param>
        /// <param name="kundennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task UpdateKeineKundenWartungen(bool enabled, string kundennummer, FbController2 fbController)
        {
            fbController.AddParameter("@KUND_L_KEINE_WARTUNGEN", enabled);
            fbController.AddParameter("@KUND_A_NR", kundennummer);
            await fbController.QueryAsync("UPDATE KUNDEN SET KUND_L_KEINE_WARTUNGEN = @KUND_L_KEINE_WARTUNGEN WHERE KUND_A_NR = @KUND_A_NR");
        }
        /// <summary>
        /// Sucht alle Wartungen anhand eines <see cref="WartungFilter"/>
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="fbController"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Wartung> GetWartungenAsync(WartungFilter filter, FbController2 fbController, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            DataTable data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController), cancellationToken);

            foreach (DataRow row in data.Rows)
            {
                cancellationToken.ThrowIfCancellationRequested();
                yield return ObjectErweiterung.DataRowZuObjekt(new Wartung(), row);
            }
        }
        /// <summary>
        /// Gibt die Anzahl aller Ergebnisse für <see cref="GetWartungenAsync(WartungFilter, FbController2, CancellationToken)"/> zurück
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="fbController"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<int> GetAnzahlWartungenAsync(WartungFilter filter, FbController2 fbController, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            int anzahl = Convert.ToInt32(await fbController.FetchObjectAsync(filter.ToCountQuery(fbController), cancellationToken));
            return anzahl;
        }
    }
}
