#if DEBUG
#define PREVENT_COMMIT
#endif
using ecoDMS.Library;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Basis.Filter;
using WK5.Core.Models;
using WK5.Core.Models.Lager;
using WK5.Core.PageModels.Tools;
using WK5.Core.Validators.Tools;
using WK5_Blazor.CoreExtensions;

namespace WK5_Blazor.Pages.Bestellungen
{
    public partial class DatevExport
    {
        private List<RechnungsPrüfungInput> _zugänge = new List<RechnungsPrüfungInput>();
        private CancellationTokenSource _cts = new CancellationTokenSource();
        private bool _showLieferantenKontakteModal;
        private int lieferantenId;
#nullable disable
        private EditForm _editForm;
        [CascadingParameter] public AppMitarbeiter Mitarbeiter { get; set; }
#nullable enable

        private bool _showHilfeModal;
        private Zugang? _selectedZugang;
        private List<string> _ecoVorschauBilder = new List<string>();
        private ZugangZahlungskonditionenValidator _zahlungskonditionenValidator = new ZugangZahlungskonditionenValidator();
        private LieferantenkontaktFilter _filterLieferantenKontakte = new LieferantenkontaktFilter
        {
            Typ = LieferantenKontaktTyp.Buchhaltung
        };

        private bool _loadingEcoDokument;
        protected override async Task OnInitializedAsync()
        {
            _cts.Cancel();
            _cts = new CancellationTokenSource();
            using FbController2 fbController = new FbController2();
            await foreach (var zugang in lagerService.GetZugängeZuExportierenAsync(fbController, _cts.Token))
            {
                _zugänge.Add(new RechnungsPrüfungInput(zugang));
                StateHasChanged();
            }
        }

        private Task ShowLieferantenKontakte(int LIEF_N_NR)
        {
            lieferantenId = LIEF_N_NR;
            _filterLieferantenKontakte.LieferantenId = LIEF_N_NR;
            _showLieferantenKontakteModal = true;
            return Task.CompletedTask;
        }
        private bool _exportiereDaten = false;
        private async Task ExportierenAsync()
        {
            _exportiereDaten = true;
            await InvokeAsync(StateHasChanged);
            if (_editForm.EditContext is not null && _editForm.EditContext.Validate())
            {

                using FbController2 fbController = new FbController2();
                await fbController.StartTransactionAsync();
                try
                {
                    var exportZugänge = _zugänge.Where(x => x.Exportieren).ToList();

                    StringBuilder sb = new StringBuilder();
                    //Beschreibung in erste Zeile:
                    sb.Append("Belegfeld1\t"); //Rechnungsnummer
                    sb.Append("Belegdatum\t"); //TT.MM.JJJJ
                    sb.Append("Belegtext\t"); //GU ( + Kundenname)) //Buchungstext
                    sb.Append("Umsatz\t"); // Umsatz mit +- Kennzeichen
                    sb.Append("Gegenkonto\t"); // Gegenkont (8400/8250...)
                    sb.Append("Lieferantennummer\t");
                    sb.Append("WKZ Umsatz\t");//EUR
                    sb.Append("EU-Land\t");
                    sb.Append("EU-Ust\t"); //(abzl. Land)
                    sb.Append("Belegfeld2\t"); //Fälligkeitsdatum
                    sb.Append("Zahlweise\t");
                    sb.Append("KOST1 - Kostenstelle\t");
                    sb.Append($"Festschreibekennzeichen{Environment.NewLine}"); //Festreibezeichen (1 = ja | 0 = nein)



                    foreach (var input in exportZugänge)
                    {

                        bool success = false;
                        try
                        {
                            success = await SetEcoZugangStatus(input);
                        }
                        catch (Exception ex)
                        {
                            Log.Logger.Error("[DATEV-EXPORT] ERROR {error}", ex);
                            await AddAlertAsync(new AlertBox
                            {
                                AlertType = AlertType.Danger,
                                Message = $"Der Status von der Rechnungsnummer {input.Zugang.ZUGA_A_RE_NR} konnte nicht in ecoDMS umgestellt werden. Bitte manuell umstellen.\r\nFehler: {ex.Message}"
                            });
                            success = false;
                        }

                        if (success)
                        {
                            sb.Append(await GetCSVData(input));

                            await lagerService.SetDatevExportiert(fbController, input.Zugang.ZUGA_N_NR);

                            if (input.Zugang.WeitereZugangsnummern.Any())
                            {
                                foreach (int weitereZugangsnummer in input.Zugang.WeitereZugangsnummern)
                                {
                                    await lagerService.SetDatevExportiert(fbController, weitereZugangsnummer);
                                }
                            }

                            _zugänge.Remove(input);
                        }
                    }
                    await SetAlerts();
                    string tmp = sb.ToString();
                    await downloadService.DownloadFileFromText("LieferantenRechnungen.csv", tmp, Encoding.ASCII,"text/plain");

#if !PREVENT_COMMIT
                    await fbController.CommitChangesAsync();
#else
                    await fbController.RollbackChangesAsync();
#endif
                }
                catch (Exception)
                {
                    await fbController.RollbackChangesAsync();
                    throw;

                }

            }

            await SetAlerts();
            _exportiereDaten = false;
        }


        private async Task<string> GetCSVData(RechnungsPrüfungInput input)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append($"{input.Zugang.ZUGA_A_RE_NR}\t");
            sb.Append($"{input.Zugang.ZUGA_D_RE_DATUM.ToShortDateString()}\t");
            sb.Append($"{input.Bemerkung}\t"); // Notiz von Annett hier rein
            sb.Append($"S{input.Zugang.Brutto}\t");

            // Lieferanten land prüfen

            Lieferant lieferant = await Lieferant.GetLieferantAsync(input.Zugang.ZUGA_N_LIEF) ?? throw new ArgumentNullException(nameof(lieferant));

            string erlöskonto = "3400";
            string land = lieferant.LIEF_A_LAND;
            if (land == "DE")
            {
                erlöskonto = "3400";
            }
            else if (Program.AppDaten.Länder.Any(x => x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == land) && !land.Equals("DE", StringComparison.OrdinalIgnoreCase))
            {
                erlöskonto = "3425";
            }
            else
            {
                erlöskonto = "3200";
            }

            sb.Append($"{erlöskonto}\t");
            sb.Append($"{input.Zugang.ZUGA_N_LIEF}\t"); // LieferantenId
            sb.Append("EUR\t");
            KarleyLibrary.Attributes.UstIdAttribute ustIdAttribute = new KarleyLibrary.Attributes.UstIdAttribute();
            ustIdAttribute.IsValid(lieferant.LIEF_A_USTIDNR);
            if (Program.AppDaten.Länder.Any(x => x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == land) && land != "DE"
                && ustIdAttribute.IsValid(lieferant.LIEF_A_USTIDNR)
                && lieferant.LIEF_A_USTIDNR is not null)
            {
                sb.Append($"{lieferant.LIEF_A_USTIDNR[0..2]}\t");
                sb.Append($"{lieferant.LIEF_A_USTIDNR[2..]}\t");
            }
            else
            {
                sb.Append("\t\t");
            }

            /* Nur wenn ein EU Land, ansonsten \t\t

            // Landkennzeichen des Lieferanten
            // GGf. UstID des Lieferenaten
            */


            //Belegefeld 2 füllen: Fälligkeitsdatum
            //Wenn er hier raus knallt, kann es sein, dass kein richtiges Zahlungsziel gesetzt wurde in der Rechnung

            Zahlungsbedingung? zahlungsbedingung = Program.AppDaten.Zahlungsbedingungen[input.Zugang.ZUGA_N_ZABD];


            int plusTage = zahlungsbedingung?.ZABD_N_NETTOTAGE ?? throw new ArgumentNullException(nameof(zahlungsbedingung), $"Die Zahlungsbedingung {input.Zugang.ZUGA_N_ZABD} konnte nicht gefunden werden");



            sb.Append($"{input.Zugang.ZUGA_D_RE_DATUM.AddDays(plusTage):ddMMyy}\t");

            //Zahlungsweise
            sb.Append($"{input.Zugang.ZUGA_N_ZABD}\t");

            //Kostenstelle
            int kostenstelle = input.Zugang.Positionen.Select(x => x.ARTI_N_ERLOESKONTO).FirstOrDefault();

            if (kostenstelle > 0)
            {
                sb.Append($"{kostenstelle}\t");
            }
            else
            {
                sb.Append("\t");
            }

            //Festschreibekennzeichen
            sb.Append($"0\t{Environment.NewLine}");
            return sb.ToString();
        }
        private async Task<bool> SetEcoZugangStatus(RechnungsPrüfungInput input)
        {
            if (String.IsNullOrWhiteSpace(input.Zugang.ZUGA_A_RE_NR))
            {
                return false;
            }
            EcoDmsController ecoDmsController = await EcoDmsController.CreateAsync(new Uri(GlobalConfig.ECODMS_BASIS_URL), GlobalConfig.ECODMS_DEFAULT_USER, Log.Logger);
            EcoDMSdocInfoCL? sucheDokument = (await ecoDmsController.EcoSucheDoksAsync(new List<EcoSearchFilter>
            {
                new EcoSearchFilter
                {
                    ClassifyAttribut = ecoDmsController.ClassifyAttributes.GetKeyByValue("Belegnummer")!,
                    SearchOperator = SuchOperator.Gleich,
                    SearchValue = input.Zugang.ZUGA_A_RE_NR.Trim()
                },
                new EcoSearchFilter
                {
                    ClassifyAttribut = "docart",
                    SearchOperator = SuchOperator.Gleich,
                    SearchValue = "15"
                }
            })).FirstOrDefault();

            if (sucheDokument is not null)
            {
                string erledigtStatusText = "Erledigt";
                string bearbeitenStatusText = "Zu Bearbeiten";
                EcoDMSStatiCL? erledigtStatus = ecoDmsController.EcoDmsStatusListe?.Where(x => x.Name.Equals(erledigtStatusText, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                EcoDMSStatiCL? bearbeitenStatus = ecoDmsController.EcoDmsStatusListe?.Where(x => x.Name.Equals(bearbeitenStatusText, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                string nichtsToDo = String.Empty;
                string zahlenToDo = "Zu zahlen";
                string datevToDo = "Datev verbuchen";
                string datevZahlenToDo = "Datev & zu zahlen";

                if (input.Zugang.WK5_ZUGA_L_BEZAHLT || Program.AppDaten.Zahlungsbedingungen.IstLastschrift(input.Zugang.ZUGA_N_ZABD))
                {
                    sucheDokument.ClassifyAttributes[ecoDmsController.ClassifyAttributes.GetKeyByValue("ToDo")!] = nichtsToDo;
                    if (erledigtStatus is not null)
                    {
                        sucheDokument.ClassifyAttributes[ecoDmsController.ClassifyAttributes.GetKeyByValue("Status")!] = erledigtStatus.Id.ToString();
                    }
                    else
                    {
                        await AddAlertAsync(new AlertBox
                        {
                            AlertType = AlertType.Danger,
                            Message = $@"Der ecoDMS Status konnte für die Rechnung {input.Zugang.ZUGA_A_RE_NR} nicht auf '{erledigtStatusText}' gesetzt werden da der Status nicht gefunden wurde
Die Rechnung wurde bezahlt und in Datev verbucht"
                        });
                        return false;
                    }
                }
                else
                {
                    sucheDokument.ClassifyAttributes[ecoDmsController.ClassifyAttributes.GetKeyByValue("ToDo")!] = zahlenToDo;
                    if (bearbeitenStatus is not null)
                    {
                        sucheDokument.ClassifyAttributes[ecoDmsController.ClassifyAttributes.GetKeyByValue("Status")!] = bearbeitenStatus.Id.ToString();
                    }
                    else
                    {
                        await AddAlertAsync(new AlertBox
                        {
                            AlertType = AlertType.Danger,
                            Message = $@"Der ecoDMS Status konnte für die Rechnung {input.Zugang.ZUGA_A_RE_NR} nicht auf '{bearbeitenStatusText}' gesetzt werden da der Status nicht gefunden wurde
Die Rechnung wurde in Datev verbucht aber nicht bezahlt"
                        });
                        return false;
                    }
                }
                await ecoDmsController.ClassifyAsync(sucheDokument);
                return true;
            }
            else
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $@"Das Dokument zur Rechnung {input.Zugang.ZUGA_A_RE_NR} konnte nicht in ecoDMS gefunden werden"
                });
                return false;
            }
        }


        private async Task GetEcoDokumentAsync(Zugang zugang)
        {
            _loadingEcoDokument = true;
            _ecoVorschauBilder.Clear();
            _selectedZugang = zugang;
            EcoDmsController ecoDmsController = await EcoDmsController.CreateAsync(new Uri(GlobalConfig.ECODMS_BASIS_URL), GlobalConfig.ECODMS_DEFAULT_USER, Log.Logger);

            var sucheDokument = (await ecoDmsController.EcoSucheDoksAsync(new List<EcoSearchFilter>
            {
                new EcoSearchFilter
                {
                    ClassifyAttribut = ecoDmsController.ClassifyAttributes.GetKeyByValue("Belegnummer")!,
                    SearchOperator = SuchOperator.Gleich,
                    SearchValue = zugang.ZUGA_A_RE_NR?.Trim()
                },
                new EcoSearchFilter
                {
                    ClassifyAttribut = "docart",
                    SearchOperator = SuchOperator.Gleich,
                    SearchValue = "15"
                }
            })).FirstOrDefault();


            if (sucheDokument is not null)
            {
                try
                {
                    int zähler = 1;
                    while (true)
                    {
                        var data = await ecoDmsController.GetDokumentenVorschauAsync(sucheDokument.DocId, zähler, 820);
                        string ecoBaseImage = Convert.ToBase64String(data);
                        _ecoVorschauBilder.Add(ecoBaseImage);
                        zähler++;
                    }
                }
                catch (Exception)
                {


                }
            }

            _loadingEcoDokument = false;
        }

        private bool ExportierenErlaubt(RechnungsPrüfungInput input)
        {
            var exportierteZugänge = _zugänge.Where(x => x.Exportieren).ToList();
            return !exportierteZugänge.Where(x => (x.Zugang.ZUGA_D_RE_DATUM.Year != input.Zugang.ZUGA_D_RE_DATUM.Year) || (x.Zugang.ZUGA_D_RE_DATUM.Month != input.Zugang.ZUGA_D_RE_DATUM.Month)).Any();
        }

        private bool _allChecked { get; set; } = false;

        private Task AllChecked(ChangeEventArgs e)
        {
            if (e.Value is not null)
            {
                bool eventChecked = (bool)e.Value;
                _allChecked = eventChecked;
                _zugänge.ForEach(x => x.Exportieren = false);

                if (_allChecked)
                {
                    DateTime minDatum = _zugänge.Min(x => x.Zugang.ZUGA_D_RE_DATUM);


                    foreach (RechnungsPrüfungInput input in _zugänge.Where(x => x.Zugang.ZUGA_D_RE_DATUM.Month == minDatum.Month && x.Zugang.ZUGA_D_RE_DATUM.Year == minDatum.Year))
                    {
                        input.Exportieren = true;
                    }
                }
            }

            return Task.CompletedTask;

        }

    }
}
