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

namespace WK5.Core.Models
{
    public class Kundenrabatt : IPreisberechnung
    {
        private string _arti_a_bez1 = String.Empty;
        private string _arti_a_bez2 = String.Empty;
        #region Datenbankfelder
        public decimal KUSA_N_PREIS { get; set; }
        public decimal KUSA_N_LVP { get; set; }
        public decimal KUSA_N_RABATT { get; set; }
        public decimal KUSA_N_RABATT_2 { get; set; }
        public decimal KUSA_N_MENGEVON1 { get; set; }
        public decimal KUSA_N_PREIS1 { get; set; }
        public decimal KUSA_N_RABATT1 { get; set; }
        public decimal KUSA_N_MENGEVON2 { get; set; }
        public decimal KUSA_N_PREIS2 { get; set; }
        public decimal KUSA_N_RABATT2 { get; set; }
        public decimal KUSA_N_MENGEVON3 { get; set; }
        public decimal KUSA_N_PREIS3 { get; set; }
        public decimal KUSA_N_RABATT3 { get; set; }
        public decimal KUSA_N_MENGEVON4 { get; set; }
        public decimal KUSA_N_PREIS4 { get; set; }
        public decimal KUSA_N_RABATT4 { get; set; }
        public decimal KUSA_N_KARTONINHALT { get; set; }
        public int KUSA_N_NR { get; set; }
        public bool KUSA_L_PREISLISTE { get; set; }
        public bool KUSA_L_0PREIS { get; set; }
        public DateTime KUSA_D_PL_GUELTIG_VON { get; set; }
        public DateTime KUSA_D_PL_GUELTIG_BIS { get; set; }
        public DateTime KUSA_TIMESTAMP { get; set; }
        public int KUSA_N_LASTUSER { get; set; }
        public string KUSA_A_ARTNUMMEIG { get; set; } = String.Empty;
        public string KUSA_A_KUNDE { get; set; } = String.Empty;
        public string? KUSA_A_ARTNUMMKUND { get; set; }
        public string? KUSA_A_SACHNUMMBEM { get; set; }
        public string? KUSA_A_BEZ1 { get; set; }
        public string? KUSA_A_BEZ2 { get; set; }
        public string? KUSA_A_BEZ3 { get; set; }
        public string? KUSA_A_BEZ4 { get; set; }
        public string? KUSA_A_BEZ5 { get; set; }
        public string? KUSA_A_WAEHRUNG { get; set; }
        public string? KUSA_A_EAN { get; set; }

        public bool WK5_KUSA_L_ZEITLICH_BEGRENZT { get; set; }
        public DateTime WK5_KUSA_D_GUELTIG_BIS { get; set; }
        public decimal ARTI_N_VK1 { get; set; }
        public string ARTI_A_BEZ1 { get => _arti_a_bez1; set => _arti_a_bez1 = value is null ? String.Empty : value; }
        public string ARTI_A_BEZ2 { get => _arti_a_bez2; set => _arti_a_bez2 = value is null ? String.Empty : value; }

        #endregion
        public string GetBezeichnung() => Regex.Replace($"{ARTI_A_BEZ1} {ARTI_A_BEZ2}", "  +/g", " ").Trim();

        public static async IAsyncEnumerable<Kundenrabatt> GetKundensachnummernAsync(string KUSA_A_KUNDE)
        {
            using FbController2 fbController = new FbController2();
            string sql = "SELECT ARTI_N_VK1, ARTI_A_BEZ1, ARTI_A_BEZ2, KUSA.* FROM KUNDENSACHNUMMER KUSA LEFT JOIN ARTIKEL ARTI ON KUSA_A_ARTNUMMEIG = ARTI_A_NR WHERE KUSA_A_KUNDE = @KUSA_A_KUNDE";
            fbController.AddParameter("@KUSA_A_KUNDE", KUSA_A_KUNDE);
            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (row is not null)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new Kundenrabatt(), row);
                }
            }
        }


        public static async Task<Kundenrabatt?> GetKundenSachnummerAsync(string KUSA_A_KUNDE, string artikelnummer)
        {
            using FbController2 fbController = new FbController2();
            string sql = "SELECT * FROM KUNDENSACHNUMMER WHERE KUSA_A_KUNDE = @KUSA_A_KUNDE AND KUSA_A_ARTNUMMEIG = @KUSA_A_ARTNUMMEIG";
            fbController.AddParameter("@KUSA_A_KUNDE", KUSA_A_KUNDE);
            fbController.AddParameter("@KUSA_A_ARTNUMMEIG", artikelnummer);
            DataRow? row = await fbController.SelectRowAsync(sql);

            return row is null ? null : ObjectErweiterung.DataRowZuObjekt(new Kundenrabatt(), row);
        }
        public Task<KundenrabattInput> ToInputAsync()
        {
            var input = new KundenrabattInput(false, GetBezeichnung())
            {
                Artikelnummer = KUSA_A_ARTNUMMEIG,
                Artikelpreis = ARTI_N_VK1,
                Kundenartikelnummer = KUSA_A_ARTNUMMKUND,
                Kundennummer = KUSA_A_KUNDE,
                GültigBis = WK5_KUSA_D_GUELTIG_BIS,
                StaffelMenge1 = KUSA_N_MENGEVON1,
                StaffelMenge2 = KUSA_N_MENGEVON2,
                StaffelMenge3 = KUSA_N_MENGEVON3,
                StaffelMenge4 = KUSA_N_MENGEVON4,
                StaffelPreis1 = KUSA_N_PREIS1,
                StaffelPreis2 = KUSA_N_PREIS2,
                StaffelPreis3 = KUSA_N_PREIS3,
                StaffelPreis4 = KUSA_N_PREIS4,
                StaffelRabatt1 = KUSA_N_RABATT1,
                StaffelRabatt2 = KUSA_N_RABATT2,
                StaffelRabatt3 = KUSA_N_RABATT3,
                StaffelRabatt4 = KUSA_N_RABATT4,
                Preis = KUSA_N_PREIS,
                Rabatt1 = KUSA_N_RABATT,
                ZeitlichBegrenzen = WK5_KUSA_L_ZEITLICH_BEGRENZT
            };

            StaffelpreisCollection kundensachnummerStaffelpreis = new StaffelpreisCollection(4);
            kundensachnummerStaffelpreis.SetBezugspreis(input.Artikelpreis);
            kundensachnummerStaffelpreis.Add(input.StaffelMenge1, input.StaffelPreis1, input.StaffelRabatt1);
            kundensachnummerStaffelpreis.Add(input.StaffelMenge2, input.StaffelPreis2, input.StaffelRabatt2);
            kundensachnummerStaffelpreis.Add(input.StaffelMenge3, input.StaffelPreis3, input.StaffelRabatt3);
            kundensachnummerStaffelpreis.Add(input.StaffelMenge4, input.StaffelPreis4, input.StaffelRabatt4);
            kundensachnummerStaffelpreis.Sort();

            input.Staffelpreise = kundensachnummerStaffelpreis;

            return Task.FromResult(input);
        }




        public decimal GetPreis(decimal menge)
        {
            var (staffelMenge, staffelPreis, _) = GetStaffelpreis(menge);

            // Default von decimal ist 0, wenn also 0, dann gibt es keine Staffelmenge.
            return staffelMenge > 0 ? staffelPreis : KUSA_N_PREIS;
        }

        /// <summary>
        /// Prüft ob es für die übergebene Menge einen Staffelpreis gibt und gibt diesen zurück.
        /// </summary>
        /// <param name="menge"></param>
        /// <returns>Wenn kein Staffelpreis gefunden wurde, dann ist staffelMenge 0. Ansonsten liefert die Funktion ein Tuple mit der Menge, dem Preis und Rabatt zurück.</returns>
        public (decimal staffelMenge, decimal staffelPreis, decimal staffelRabatt) GetStaffelpreis(decimal menge)
        {
            // Die Staffelpreise können in der W4 in einer falschen Reihenfolge hinterlegt sein, daher packen wir alle Staffelpreise in ein Array und sortieren manuell
            (decimal staffelMenge, decimal staffelPreis, decimal staffelRabatt)[] staffelpreise = new (decimal, decimal, decimal)[]
            {
                (KUSA_N_MENGEVON1, KUSA_N_PREIS, KUSA_N_RABATT1),
                (KUSA_N_MENGEVON2, KUSA_N_PREIS, KUSA_N_RABATT2),
                (KUSA_N_MENGEVON3, KUSA_N_PREIS, KUSA_N_RABATT3),
                (KUSA_N_MENGEVON4, KUSA_N_PREIS, KUSA_N_RABATT4)
            };

            var sucheStaffelpreis = staffelpreise.Where(x => x.staffelMenge > 0 && x.staffelMenge <= menge).OrderByDescending(x => x.staffelMenge);
            return sucheStaffelpreis.FirstOrDefault();
        }

        /// <summary>
        /// Holt die Rabatte für den Lieferantenartikel in Abhängigkeit der Bestellmenge zur Staffelmenge
        /// </summary>
        /// <param name="menge"></param>
        /// <returns></returns>
        public (decimal rabatt1, decimal rabatt2) GetRabatte(decimal menge)
        {
            var (staffelMenge, _, staffelRabatt) = GetStaffelpreis(menge);
            // Wenn es einen Staffelpreis gibt, dann ist Rabatt2 immer 0, da wir auf den Staffelpreis keinen zweiten Rabatt gewähren.
            return staffelMenge > 0 ? (staffelRabatt, 0) : (KUSA_N_RABATT, KUSA_N_RABATT_2);
        }
    }
}
