using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WK5.Core.Basis;
using WK5.Core.Models;

namespace WK5.Core.Services
{
    /// <summary>
    /// Stellt Funktionen zum Umgang für <see cref="Artikeltyp"/> zur Verfügung.
    /// </summary>
    public class ArtikeltypService : IModelService<Artikeltyp, int>
    {
        /// <summary>
        /// Lädt einen bestimmten <see cref="Artikeltyp"/>
        /// </summary>
        /// <param name="identifier">ID des Artikeltypen</param>
        /// <param name="fbController"></param>
        /// <returns>Wird für die ID kein Artikeltyp gefunden, dann liefert diese Funktion null zurück.</returns>
        public async Task<Artikeltyp?> GetAsync(int identifier, FbController2 fbController)
        {
            fbController.AddParameter("@ARTY_N_NR", identifier);
            DataRow? row = await fbController.SelectRowAsync("SELECT * FROM ARTIKELTYPEN WHERE ARTY_N_NR = @ARTY_N_NR");

            if (row is null)
            {
                return null;
            }

            Artikeltyp artikeltyp = ObjectErweiterung.DataRowZuObjekt(new Artikeltyp(), row);
            fbController.AddParameter("@AZUO_N_ARTIKELTYP", artikeltyp.Id);
            DataTable optionenData = await fbController.SelectDataAsync(@"SELECT AO.*, AZO.AZUO_L_REQUIRED 
FROM ARTIKELTYP_ZU_OPTION AZO
INNER JOIN ARTIKEL_OPTIONEN AO ON AO.AROP_N_NR = AZO.AZUO_N_OPTION
WHERE AZO.AZUO_N_ARTIKELTYP = @AZUO_N_ARTIKELTYP");

            foreach (DataRow optionenRow in optionenData.Rows)
            {
                ArtikelOption artikelOption = ObjectErweiterung.DataRowZuObjekt(new ArtikelOption(), optionenRow);
                artikeltyp.Optionen.Add(artikelOption);
            }

            IEnumerable<int> idsVonOptionenMitValues = artikeltyp.Optionen.Where(x => x.Typ == "select").Select(x => x.Id);
            if (idsVonOptionenMitValues.Any())
            {
                DataTable valueData = await fbController.SelectDataAsync($"SELECT * FROM ARTIKEL_OPTIONEN_VALUE WHERE AROV_N_NR IN ({string.Join(",", idsVonOptionenMitValues)})");

                foreach (DataRow valueRow in valueData.Rows)
                {
                    ArtikelOptionValue optionValue = ObjectErweiterung.DataRowZuObjekt(new ArtikelOptionValue(), valueRow);
                    var sucheOption = artikeltyp.Optionen.FirstOrDefault(x => x.Id == optionValue.OptionId);
                    if (sucheOption is not null)
                    {
                        sucheOption.OptionValues.Add(optionValue);
                    }
                }
            }

            return artikeltyp;

        }
        /// <summary>
        /// Lädt alle verfügbaren <see cref="Artikeltyp"/> Datensätze.
        /// </summary>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Artikeltyp> GetAsync(FbController2 fbController)
        {
            DataTable data = await fbController.SelectDataAsync("SELECT * FROM ARTIKELTYPEN");

            foreach (DataRow row in data.Rows)
            {
                Artikeltyp artikeltyp = ObjectErweiterung.DataRowZuObjekt(new Artikeltyp(), row);
                fbController.AddParameter("@AZUO_N_ARTIKELTYP", artikeltyp.Id);
                DataTable optionenData = await fbController.SelectDataAsync(@"SELECT AO.*, AZO.AZUO_L_REQUIRED 
FROM ARTIKELTYP_ZU_OPTION AZO
INNER JOIN ARTIKEL_OPTIONEN AO ON AO.AROP_N_NR = AZO.AZUO_N_OPTION
WHERE AZO.AZUO_N_ARTIKELTYP = @AZUO_N_ARTIKELTYP");

                foreach (DataRow optionenRow in optionenData.Rows)
                {
                    ArtikelOption artikelOption = ObjectErweiterung.DataRowZuObjekt(new ArtikelOption(), optionenRow);
                    artikeltyp.Optionen.Add(artikelOption);
                }

                IEnumerable<int> idsVonOptionenMitValues = artikeltyp.Optionen.Where(x => x.Typ == "select").Select(x => x.Id);
                if (idsVonOptionenMitValues.Any())
                {
                    DataTable valueData = await fbController.SelectDataAsync($"SELECT * FROM ARTIKEL_OPTIONEN_VALUE WHERE AROV_N_NR IN ({string.Join(",", idsVonOptionenMitValues)})");

                    foreach (DataRow valueRow in valueData.Rows)
                    {
                        ArtikelOptionValue optionValue = ObjectErweiterung.DataRowZuObjekt(new ArtikelOptionValue(), valueRow);
                        var sucheOption = artikeltyp.Optionen.FirstOrDefault(x => x.Id == optionValue.OptionId);
                        if (sucheOption is not null)
                        {
                            sucheOption.OptionValues.Add(optionValue);
                        }
                    }
                }

                yield return artikeltyp;
            }


        }
        /// <summary>
        /// Speichert einen <see cref="Artikeltyp"/> in der Datenbank.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task CreateAsync(Artikeltyp input, FbController2 fbController)
        {
            fbController.AddParameter("@ARTY_A_NAME", input.Name);
            input.Id = Convert.ToInt32(await fbController.FetchObjectAsync(@"INSERT INTO ARTIKELTYPEN 
(
    ARTY_A_NAME  
)
VALUES
(
    @ARTY_A_NAME
) RETURNING ARTY_N_NR"));

            fbController.AddParameter("@AZUO_N_ARTIKELTYP", input.Id);
            await fbController.QueryAsync("DELETE FROM ARTIKELTYP_ZU_OPTION WHERE AZUO_N_ARTIKELTYP = @AZUO_N_ARTIKELTYP");

            await CreateOrUpdateZuordnungenAsync(input, fbController);
        }
        /// <summary>
        /// Aktualisiert einen bestehenden <see cref="Artikeltyp"/> in der Datenbank.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task UpdateAsync(Artikeltyp input, FbController2 fbController)
        {
            fbController.AddParameter("@ARTY_A_NAME", input.Name);
            fbController.AddParameter("@ARTY_N_NR", input.Id);
            await fbController.QueryAsync(@"UPDATE ARTIKELTYPEN SET 
ARTY_A_NAME = @ARTY_A_NAME
WHERE ARTY_N_NR = @ARTY_N_NR");

            fbController.AddParameter("@AZUO_N_ARTIKELTYP", input.Id);
            await fbController.QueryAsync("DELETE FROM ARTIKELTYP_ZU_OPTION WHERE AZUO_N_ARTIKELTYP = @AZUO_N_ARTIKELTYP");

            await CreateOrUpdateZuordnungenAsync(input, fbController);


        }
        /// <summary>
        /// Löscht einen <see cref="Artikeltyp"/> aus der Datenbank
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task DeleteAsync(Artikeltyp input, FbController2 fbController)
        {
            fbController.AddParameter("@AZUO_N_ARTIKELTYP", input.Id);
            await fbController.QueryAsync("DELETE FROM ARTIKELTYP_ZU_OPTION WHERE AZUO_N_ARTIKELTYP = @AZUO_N_ARTIKELTYP");

            fbController.AddParameter("@ARTY_N_NR", input.Id);
            await fbController.QueryAsync("DELETE FROM ARTIKELTYPEN WHERE ARTY_N_NR = @ARTY_N_NR");
        }
        /// <summary>
        /// Erstellt für einen <see cref="Artikeltyp"/> die dazugehörigen Zuordnungen zu den Optionen.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task CreateOrUpdateZuordnungenAsync(Artikeltyp input, FbController2 fbController)
        {
            foreach (var zuordnung in input.Optionen)
            {
                fbController.AddParameter("@AZUO_N_ARTIKELTYP", input.Id);
                fbController.AddParameter("@AZUO_N_OPTION", zuordnung.Id);
                fbController.AddParameter("@AZUO_L_REQUIRED", zuordnung.IsRequired);
                await fbController.QueryAsync(@"UPDATE OR INSERT INTO ARTIKELTYP_ZU_OPTION
(
AZUO_N_ARTIKELTYP,
AZUO_N_OPTION,
AZUO_L_REQUIRED
)
VALUES
(
@AZUO_N_ARTIKELTYP,
@AZUO_N_OPTION,
@AZUO_L_REQUIRED
)");
            }
        }
    }
}
