using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WK5.Core.Models;

namespace WK5.Core.Basis.Filter
{
    public class ArtikelFilter : PageFilter
    {        
        private bool _lieferantenartikelnummer;
        private bool _kundenArtikelnummer;
        private bool _nurArtikelVomLieferantenAnzeigen;
        private string _warengruppe = string.Empty;
        private string _unterwarengruppe = string.Empty;        

        public bool ZeigeInaktive { get; set; }
        public int LieferantenId { get; set; }

        public bool NurArtikelVomLieferantenAnzeigen
        {
            get => _nurArtikelVomLieferantenAnzeigen;
            set
            {
                _nurArtikelVomLieferantenAnzeigen = value;
                if (NurArtikelVomLieferantenAnzeigen)
                {
                    Lieferantenartikelnummer = false;
                    KundenArtikelnummer = false;
                }
            }
        }

        public bool ZeigeEk { get; set; }
        public bool NurArtikelMitLagerführung { get; set; }
        public bool NurArtikelMitBestand { get; set; }
        public bool ZeigeBundles { get; set; }

        public bool KundenArtikelnummer
        {
            get => _kundenArtikelnummer;
            set
            {
                _kundenArtikelnummer = value;
                if (KundenArtikelnummer)
                {
                    NurArtikelVomLieferantenAnzeigen = false;
                    Lieferantenartikelnummer = false;
                }
            }
        }
        public bool Lieferantenartikelnummer
        {
            get => _lieferantenartikelnummer;
            set
            {
                _lieferantenartikelnummer = value;

                if (Lieferantenartikelnummer)
                {
                    KundenArtikelnummer = false;
                    NurArtikelVomLieferantenAnzeigen = false;
                }
            }
        }
        public string Warengruppe { get => _warengruppe; set => _warengruppe = value ?? string.Empty; }
        public string Unterwarengruppe { get => _unterwarengruppe; set => _unterwarengruppe = value ?? string.Empty; }

        public bool MussSeriennummerHaben { get; set; } = false;
        public bool DarfKeineSeriennummerHaben { get; set; } = false;
        public List<string> AusgeschlosseneArtikel { get; set; } = new List<string>();
        public Lieferant? SelectedLieferant { get; set; }

        public bool IsFilterActive
        {
            get
            {
                if (!String.IsNullOrWhiteSpace(Suchbegriff))
                {
                    return true;
                }

                if (!String.IsNullOrWhiteSpace(Warengruppe))
                {
                    return true;
                }

                if (!String.IsNullOrWhiteSpace(Unterwarengruppe))
                {
                    return true;
                }

                if (ZeigeInaktive)
                {
                    return true;
                }

                if (NurArtikelMitBestand)
                {
                    return true;
                }

                if (NurArtikelMitLagerführung)
                {
                    return true;
                }

                if (NurArtikelVomLieferantenAnzeigen)
                {
                    return true;
                }

                if (LieferantenId > 0)
                {
                    return true;
                }

                if (KundenArtikelnummer)
                {
                    return true;
                }

                if (Lieferantenartikelnummer)
                {
                    return true;
                }

                return false;
            }
        }

        public string? SuchAttribut { get; set; }
        public bool OrderDescending { get; set; } = true;
        private void Tokenizer(FbController2 fbController)
        {
            string[] atoms = Suchbegriff.Split(" ", StringSplitOptions.RemoveEmptyEntries);

            Dictionary<int, string> artikelnummern = new Dictionary<int, string>();
            Dictionary<int, string> breiteHöhe = new Dictionary<int, string>();
            Dictionary<int, string> breiteHöheLänge = new Dictionary<int, string>();
            Dictionary<int, string> normaleWörter = new Dictionary<int, string>();

            for (int i = 0; i < atoms.Length; i++)
            {
                string atom = atoms[i];
                if (atom.StartsWith("#"))
                {
                    artikelnummern.Add(i, atom);
                    continue;
                }

                if (atom.Count(x => x == '*') == 2)
                {
                    string[] bhl = atom.Split("*", StringSplitOptions.RemoveEmptyEntries);

                    if (bhl.Length == 3)
                    {

                        if (Decimal.TryParse(bhl[0], out decimal b) && Decimal.TryParse(bhl[1], out decimal h) && Decimal.TryParse(bhl[1], out decimal l))
                        {
                            breiteHöheLänge.Add(i, atom);
                            continue;
                        }
                    }
                }

                if (atom.Count(x => x == '*') == 1)
                {
                    string[] bh = atom.Split("*", StringSplitOptions.RemoveEmptyEntries);

                    if (bh.Length == 2)
                    {

                        if (Decimal.TryParse(bh[0], out decimal b) && Decimal.TryParse(bh[1], out decimal h))
                        {
                            breiteHöhe.Add(i, atom);
                            continue;
                        }
                    }
                }

                normaleWörter.Add(i, atom);

            }

            List<string> artikelnummerQueries = new List<string>();
            foreach (KeyValuePair<int, string> atom in artikelnummern)
            {
                artikelnummerQueries.Add($" ( CAST(UPPER(ARTI_A_NR) AS VARCHAR(255)) LIKE @ARTINR_TOKEN{atom.Key} ) ");
                fbController.AddParameter($"@ARTINR_TOKEN{atom.Key}", atom.Value.TrimStart('#'));
            }

            List<string> breiteHöheQueries = new List<string>();
            foreach (KeyValuePair<int, string> atom in breiteHöhe)
            {
                breiteHöheQueries.Add($" ( (ARTI_N_BREITE <= (@B{atom.Key} * 1.1) AND ARTI_N_BREITE >= (@B{atom.Key} * 0.9)  ) AND (ARTI_N_HOEHE <= (@H{atom.Key} * 1.1) AND ARTI_N_HOEHE >= (@H{atom.Key}*0.9)) ) ");

                string[] bh = atom.Value.Split("*", StringSplitOptions.RemoveEmptyEntries);

                fbController.AddParameter($"@B{atom.Key}", Convert.ToDecimal(bh[0]) / 10);
                fbController.AddParameter($"@H{atom.Key}", Convert.ToDecimal(bh[1]) / 10);

            }

            List<string> breiteHöheLängeQueries = new List<string>();
            foreach (KeyValuePair<int, string> atom in breiteHöheLänge)
            {
                breiteHöheQueries.Add($" ( (ARTI_N_BREITE <= (@B{atom.Key} * 1.1) AND ARTI_N_BREITE >= (@B{atom.Key} * 0.9)  ) AND (ARTI_N_HOEHE <= (@H{atom.Key} * 1.1) AND ARTI_N_HOEHE >= (@H{atom.Key}*0.9)) AND (ARTI_N_LAENGE<= (@L{atom.Key} *1.1) AND ARTI_N_LAENGE >= (@L{atom.Key} *0.9 )) ) ");

                string[] bhl = atom.Value.Split("*", StringSplitOptions.RemoveEmptyEntries);

                fbController.AddParameter($"@B{atom.Key}", Convert.ToDecimal(bhl[0]) / 10);
                fbController.AddParameter($"@H{atom.Key}", Convert.ToDecimal(bhl[1]) / 10);
                fbController.AddParameter($"@L{atom.Key}", Convert.ToDecimal(bhl[2]) / 10);
            }

            List<string> normaleWörterQueries = new List<string>();
            foreach (KeyValuePair<int, string> atom in normaleWörter)
            {
                List<string> searchKeys = new List<string>() { "ARTI_A_HERST_NR", "ARTI_A_EAN", "WK5_ARTI_A_SUCHBEGRIFF", "ARTI_A_BEZ1", "ARTI_A_BEZ2", "ARTI_A_BEZ3", "ARTI_A_HERSTELLER" };
                List<string> forceEscapeKeys = new List<string>() { "WK5_ARTI_A_SUCHBEGRIFF" };

                if (artikelnummern.Count <= 0)
                    searchKeys.Add("ARTI_A_NR");

                StringBuilder tmpBuilder = new StringBuilder();

                List<string> subQueries = new List<string>();
                foreach (string searchKey in searchKeys)
                {
                    if (forceEscapeKeys.Contains(searchKey))
                    {
                        subQueries.Add($" CAST(UPPER({searchKey}) AS VARCHAR(255)) LIKE @NORMAL_TOKEN{atom.Key}_LIKE ");
                    }
                    else
                    {
                        subQueries.Add($" CAST(UPPER({searchKey}) AS VARCHAR(255)) LIKE @NORMAL_TOKEN{atom.Key} ");
                    }
                }

                normaleWörterQueries.Add($" ( {String.Join(" OR ", subQueries) } ) ");



                fbController.AddParameter($"@NORMAL_TOKEN{atom.Key}", atoms.Length > 1 ? $"%{atom.Value}%" : atom.Value);
                fbController.AddParameter($"@NORMAL_TOKEN{atom.Key}_LIKE", $"%{atom.Value}%");
            }


            //(Artikelnummern) AND (BREITExHÖHE) AND (BREITExHÖHExLÄNGE) AND (NORMALE WÖRTER)

            string combinationOperator = " AND ";

            //if (artikelnummerQueries.Count > 0)
            //    combinationOperator = " AND ";

            List<string> queries = new List<string>();

            if (artikelnummerQueries.Count > 0)
            {
                queries.Add(String.Join(" OR ", artikelnummerQueries));
            }

            if (breiteHöheQueries.Count > 0)
            {
                queries.Add(String.Join(combinationOperator, breiteHöheQueries));
            }

            if (breiteHöheLängeQueries.Count > 0)
            {
                queries.Add(String.Join(combinationOperator, breiteHöheLängeQueries));
            }

            if (normaleWörterQueries.Count > 0)
            {
                queries.Add(String.Join(" AND ", normaleWörterQueries));
            }

            string prelimResult = $" ( {String.Join(combinationOperator, queries)} ) ";

            sqlBuilder.Append(prelimResult);
        }
        protected override void BuildQueryConditions(FbController2 fbController)
        {
            if (LieferantenId > 0 || Lieferantenartikelnummer)
            {
                sqlBuilder.Append(" INNER JOIN LIEFERANTENARTIKEL ON ARTI_A_NR = ARLI_A_ARTIKELNR ");
            }

            if (KundenArtikelnummer)
            {
                sqlBuilder.Append(" INNER JOIN KUNDENSACHNUMMER ON ARTI_A_NR = KUSA_A_ARTNUMMEIG ");
            }

            sqlBuilder.Append(" WHERE 1=1");

            if (LieferantenId > 0 && NurArtikelVomLieferantenAnzeigen)
            {
                sqlBuilder.Append(" AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR");
                fbController.AddParameter("@ARLI_N_LIEFNR", LieferantenId);
            }

            bool doKqlLogic = true;

            string filterPrefix = " AND ";
            if (Lieferantenartikelnummer && KundenArtikelnummer)
                filterPrefix = " OR ";

            if (Lieferantenartikelnummer)
            {
                sqlBuilder.Append($" AND CAST(UPPER(ARLI_A_BESTELLNR) AS VARCHAR(255)) LIKE '%{Suchbegriff}%'");
                doKqlLogic = false;
            }

            if (KundenArtikelnummer)
            {
                sqlBuilder.Append($"{filterPrefix}CAST(UPPER(KUSA_A_ARTNUMMKUND) AS VARCHAR(255)) LIKE '%{Suchbegriff}%'");
                doKqlLogic = false;
            }

            if (doKqlLogic)
            {

                if (!String.IsNullOrWhiteSpace(Suchbegriff))
                {
                    if (Suchbegriff.Length > 255)
                    {
                        throw new ArgumentOutOfRangeException("Der Suchbegriff darf nicht mehr als 255 Zeichen haben");
                    }

                    sqlBuilder.Append(" AND ( ");
                    Tokenizer(fbController);
                    sqlBuilder.Append(" ) ");
                }

            }

            if (!ZeigeInaktive)
            {
                sqlBuilder.Append(" AND ARTI_L_INAKTIV = 'N'");
            }

            if (NurArtikelMitLagerführung)
            {
                if (ZeigeBundles)
                {
                    sqlBuilder.Append(" AND (ARTI_L_LAGERFUEHR = 'Y' OR (SELECT COUNT(*) FROM BUNDLES WHERE BUNDLE_A_ARTINR = ARTI_A_NR) > 0)");
                }
                else
                {
                    sqlBuilder.Append(" AND ARTI_L_LAGERFUEHR = 'Y'");
                }
            }

            if (NurArtikelMitBestand)
            {
                sqlBuilder.Append(" AND ARWE_N_BESTAND > 0 ");
            }

            if (!String.IsNullOrWhiteSpace(Warengruppe))
            {
                sqlBuilder.Append(" AND ARTI_A_WARENGRUPPE = @WARENGRUPPE");
                fbController.AddParameter("@WARENGRUPPE", Warengruppe);
            }

            if (!String.IsNullOrWhiteSpace(Warengruppe) && !String.IsNullOrWhiteSpace(Unterwarengruppe))
            {
                sqlBuilder.Append(" AND ARTI_A_UNTERWARENG = @UNTERWARENGRUPPE");
                fbController.AddParameter("@UNTERWARENGRUPPE", Unterwarengruppe);
            }

            if (MussSeriennummerHaben)
            {
                sqlBuilder.Append(" AND ARTI_L_SN = 'Y'");
            }

            if (DarfKeineSeriennummerHaben)
            {
                sqlBuilder.Append(" AND ARTI_L_SN = 'N'");
            }

            if(AusgeschlosseneArtikel.Count > 0)
            {
                sqlBuilder.Append($" AND ARTI_A_NR NOT IN ('{String.Join("','", AusgeschlosseneArtikel)}')");
            }

        }

        public override string ToSqlQuery(FbController2 fbController)
        {

            
            sqlBuilder.Clear();

            sqlBuilder.Append(@$"SELECT FIRST {Limit} SKIP {(Seite - 1) * Limit} DISTINCT 
ARTI_A_NR, ARTI_A_BEZ1, ARTI_A_BEZ2, ARTI_A_BEZ3, ARWE_N_BEDARF, ARWE_N_BESTAND, ARWE_N_OFFBESTELL, ARTI_N_EK, ARTI_N_VK1, ARTI_A_EAN,
ARTI_A_HERST_NR, WK5_ARTI_A_SUCHBEGRIFF, ARTI_A_WARENGRUPPE, ARTI_A_UNTERWARENG, ARTI_L_INAKTIV, ARTI_L_LAGERFUEHR, WK5_ARTI_N_WICHTIGKEIT,
WK5_ARWE_N_BESTAND_STUECKLISTE, WK5_ARTI_N_ANGEBOTVORLAGE
FROM ARTIKEL LEFT JOIN ARTIKELWERTE ON ARWE_A_NR = ARTI_A_NR ");
            BuildQueryConditions(fbController);

            if (String.IsNullOrWhiteSpace(SuchAttribut))
            {
                sqlBuilder.Append(" ORDER BY WK5_ARTI_N_WICHTIGKEIT DESC");
            }
            else
            {
                sqlBuilder.Append($" ORDER BY {SuchAttribut} { (OrderDescending ? "DESC" : "ASC")}, WK5_ARTI_N_WICHTIGKEIT DESC ");
            }
            string sql = sqlBuilder.ToString();
            return sql;
        }

        public override string ToCountQuery(FbController2 fbController)
        {

            sqlBuilder.Clear();
            sqlBuilder.Append(@$"SELECT COUNT(DISTINCT ARTI_A_NR) FROM ARTIKEL LEFT JOIN ARTIKELWERTE ON ARWE_A_NR = ARTI_A_NR");
            BuildQueryConditions(fbController);

            return sqlBuilder.ToString();
        }
    }

}
