using FluentValidation;
using FluentValidation.Results;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Models;
using WK5.Core.PageModels.Verkauf;

namespace WK5.Core.Validators.Verkauf
{
    public class BelegpositionValidator : AbstractValidator<Belegposition>
    {
        private static List<string> positionenOhneEk = new List<string>
        {
            "TEXT",
            "T1",
            "MIETE_VER"
        };
        public BelegpositionValidator()
        {
            RuleFor(pos => pos.Artikelnummer)
                .NotEmpty()
                .MaximumLength(30)
                .ISO88591();


            RuleFor(pos => pos.Bezeichnung1)
                .MaximumLength(60)
                .ISO88591();

            RuleFor(pos => pos.Bezeichnung2)
               .MaximumLength(60)
               .ISO88591();

            RuleFor(pos => pos.Bezeichnung3)
               .MaximumLength(60)
               .ISO88591();

            RuleFor(pos => pos.Bezeichnung4)
               .MaximumLength(60)
               .ISO88591();

            RuleFor(pos => pos.Bezeichnung5)
               .MaximumLength(80)
               .ISO88591();


            RuleFor(pos => pos.Menge)
                .Must((pos, menge) => ValidateMenge(pos))
                .WithMessage("Bitte geben Sie eine Menge an.");

            //RuleFor(pos => pos.Menge)
            //    .Must((pos, menge) => ValidateVPE(pos))
            //    .WithMessage("Es kann nur ein Vielfaches der VPE verkauft werden!!!");



            RuleFor(pos => pos.Rabattbezeichnung)
               .MaximumLength(15)
               .ISO88591();

            RuleFor(pos => pos.Rabattbezeichnung)
                .NotNull()
                .NotEmpty()
                .WithMessage("Es muss eine Rabattbezeichnung angegeben werden")
                .When(x => x.Rabatt1 > 0);

            RuleFor(pos => pos.Kundensachnummer)
               .MaximumLength(30)
               .ISO88591();

            RuleFor(pos => pos.Langtext)
                .Must((langtext) => HasNoRtf(langtext))
                .WithMessage("Langtext ist noch im alten Format. Bitte prüfen und korrigieren.");

            RuleFor(pos => pos.Rabatt1)
                .InclusiveBetween(0, 100);

            RuleFor(pos => pos.Rabatt2)
                .InclusiveBetween(0, 100);


            RuleFor(pos => pos.Preis)
                .ScalePrecision(2, int.MaxValue)
                .WithMessage("Bei Mengen unter 10000 darf der Preis maximal 2 Nachkommastellen haben.")
                .When(pos => pos.Menge < 10000 && !pos.Artikelnummer.Equals("T1"))
                ;

            RuleFor(pos => pos.Preis)
                .ScalePrecision(4, int.MaxValue)
                .WithMessage("Der Preis darf maximal 4 Nachkommastellen haben.")
                .When(pos => pos.Menge >= 10000);



            RuleFor(pos => pos.Option)
               .MaximumLength(1)
               .ISO88591();

            RuleFor(x => x.PosEinkaufspreis)
                .GreaterThan(0)
                .WithMessage(x => $"Bitte geben Sie einen EK für die Position {x.PosNr} an.")
                .When(x => !positionenOhneEk.Contains(x.Artikelnummer) && x.BundleId == 0);

            RuleFor(x => x.BPOS_D_MIETE_START)
                .Must((x, y) => x.BPOS_D_MIETE_START <= x.BPOS_D_MIETE_ENDE)
                .WithMessage("Das Startdatum der Miete kann nicht größer sein als das Enddatum")
                .When(x => x.ARTI_L_MIETE);

            RuleFor(x => x.BPOS_D_MIETE_START)
                .Must(x => x != default)
                .WithMessage("Bitte geben Sie für die Miete ein Startdatum an")
                .When(x => x.ARTI_L_MIETE);

            RuleFor(x => x.BPOS_D_MIETE_ENDE)
                .Must(x => x != default)
                .WithMessage("Bitte geben Sie für die Miete ein Enddatum an")
                .When(x => x.ARTI_L_MIETE);

            //TODO: Async Validation funktioniert noch nicht!!https://github.com/Blazored/FluentValidation/issues/38
            RuleFor(x => x)
                .Must((pos) => ValidateTermin(pos, true))
                .WithMessage("Der Mietzeitraum ist nicht verfügbar")
                .When(x => x.ARTI_L_MIETE && x.BPOS_A_TYP == "AU");

            RuleFor(x => x)
                .Must((pos) => ValidateTermin(pos, false))
                .WithMessage("Der Mietzeitraum ist nicht verfügbar")
                .When(x => x.ARTI_L_MIETE && x.BPOS_A_TYP == "AN");

        }

        private bool ValidateTermin(Belegposition pos, bool istAuftrag)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@START", pos.BPOS_D_MIETE_START);
            fbController.AddParameter("@ENDE", pos.BPOS_D_MIETE_ENDE);
            fbController.AddParameter("@BPOS_A_ARTIKELNR", pos.Artikelnummer);
            string sql = @"SELECT 1 FROM BELEGPOS
LEFT JOIN BELEGE B ON(BELE_A_TYP = BPOS_A_TYP AND BELE_N_NR = BPOS_N_NR)
WHERE(BPOS_D_MIETE_START BETWEEN @START AND @ENDE OR BPOS_D_MIETE_ENDE BETWEEN @START AND @ENDE)
AND BPOS_A_TYP IN('AU', 'LS')
AND BPOS_A_ARTIKELNR = @BPOS_A_ARTIKELNR
AND BELE_L_ERLEDIGT = 'N' 
AND BELE_L_STORNO = 'N'";

            if (istAuftrag && pos.BPOS_N_NR is not 0)
            {
                sql += " AND BPOS_N_NR != @BPOS_N_NR AND BELE_N_NR_AU != @BPOS_N_NR";
                fbController.AddParameter("@BPOS_N_NR", pos.BPOS_N_NR);
            }
            DataRow? row = fbController.SelectRow(sql);
            return row == null;
        }

        private bool ValidateVPE(Belegposition pos)
        {
            if(pos.Artikelnummer.Equals("TEXT", StringComparison.Ordinal))
            {
                return true;
            }

            if(pos.Vpe is 0)
            {
                pos.Vpe = 1;
            }

            if (pos.Menge % pos.Vpe != 0)
            {
                return false;
            }

            return true;
        }
        private bool ValidateMenge(Belegposition pos)
        {
            return pos.Artikelnummer.Equals("TEXT", StringComparison.Ordinal) || pos.Menge > 0;
        }

        private bool HasNoRtf(string text)
        {
            return !text.StartsWith(@"{\rtf1");
        }
    }
}
