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.Erweiterungen;
using WK5.Core.Models;
using WK5.Core.Models.Starmoney;
using WK5.Core.PageModels;
using WK5.Core.PageModels.Stammdaten.Kunden;
using WK5.Core.Validators.Stammdaten.Kunden;

namespace WK5_Blazor.Pages.Stammdaten.Kunden
{
    public partial class KundenLastschriftExport : IDisposable, IHilfeModal
    {
        private CancellationTokenSource _loadingCts = new CancellationTokenSource();
        private List<LastschriftRechnungExport> _exportDaten = new List<LastschriftRechnungExport>();
        public decimal ZahllimitProTag { get; set; }
        public bool ShowHilfeModal { get; set; }

        private async Task LadeExportDaten()
        {
            CleanUpTokenSource(ref _loadingCts, true);
            using FbController2 fbController = new FbController2();
            await foreach (var item in belegService.GetExportLastschriftRechnungenAsync(fbController, _loadingCts.Token))
            {
                _exportDaten.Add(item);
            }
        }
        private LastschriftKonditionenInput? _konditionenInput;
        private LastschriftKonditionenInputValidator _konditionenValidator = new LastschriftKonditionenInputValidator();

        protected override async Task OnInitializedAsync()
        {
            await LadeExportDaten();
            ZahllimitProTag = GlobalConfig.GetZahllimitProTag();
        }
        private async Task UpdateZahlungskonditionenAsync()
        {
            if (_konditionenInput is null)
            {
                return;
            }

            using FbController2 fbController = new FbController2();
            await kundenService.UpdateLastschriftKonditionenAsync(fbController, _konditionenInput);

            foreach (var item in _exportDaten.Where(x => x.Kundennummer.Equals(_konditionenInput.Kundennummer)))
            {
                item.MandatsAusstellungsdatum = _konditionenInput.Ausstellungsdatum;
                item.Iban = _konditionenInput.IBAN;
                item.Bic = _konditionenInput.BIC;
            }

            await jsRuntime.ShowToast(ToastType.success, "Zahlungskonditionen erfolgreich aktualisiert.");
        }
        private Task EditZahlungskonditionen(LastschriftRechnungExport export)
        {
            _konditionenInput = new LastschriftKonditionenInput(export.Kundennummer)
            {
                Ausstellungsdatum = export.MandatsAusstellungsdatum,
                BIC = export.Bic ?? String.Empty,
                IBAN = export.Iban ?? String.Empty
            };
            return Task.CompletedTask;
        }

        public IEnumerable<(string lieferantenName, int zahlungsbedingung, DateTime zahlungsziel, decimal skonto, decimal summe)> GetSummen()
        {
            foreach (var item in _exportDaten.Where(x => x.Exportieren))
            {
                Zahlungsbedingung? zahlungsbedingung = Program.AppDaten.Zahlungsbedingungen[item.ZahlungsbedingungId];
                if (zahlungsbedingung is null)
                {
                    throw new ArgumentNullException(nameof(zahlungsbedingung));
                }

                DateTime zahlungsziel = item.Rechnungsdatum;
                int addTage = zahlungsbedingung.ZABD_N_NETTOTAGE;

                zahlungsziel = zahlungsziel.AddDays(addTage);


                yield return (item.Kundennummer, item.ZahlungsbedingungId, zahlungsziel, 0, item.Betrag);
            }
        }

        public async Task ExportierenAsync()
        {
            using FbController2 fbController = new FbController2();
            await fbController.StartTransactionAsync();
            List<SepaÜberweisung> überweisungen = new List<SepaÜberweisung>();
            var zugängeZuExportieren = _exportDaten.Where(x => x.Exportieren).ToList();
            foreach (var export in zugängeZuExportieren)
            {
                Zahlungsbedingung? zahlungsbedingung = Program.AppDaten.Zahlungsbedingungen[export.ZahlungsbedingungId];

                if (zahlungsbedingung is null)
                {
                    throw new ArgumentNullException(nameof(zahlungsbedingung));
                }


                DateTime zahlungsziel = export.Rechnungsdatum;
                int addTage = zahlungsbedingung.ZABD_N_NETTOTAGE;

                // Bei Lastschriften gibt es keinen Spielraum, wir dürfen nciht vor dem angegeben Zahlungstermin eine Lastschrift beauftragen!
                zahlungsziel = zahlungsziel.AddDays(addTage);

                // 15.06.2020 - MK: StarMoney kann Lastschriften nur in der Zukunft bearbeiten.
                if(zahlungsziel.Date <= DateTime.Today.Date)
                {
                    zahlungsziel = DateTime.Now.Date.AddDays(1);
                }

                SepaTextschlüssel textschlüssel = SepaTextschlüssel.Lastschrift_Abbuchungsauftragsverfahren;

                string? gläubigerIdentifikationsnummer = GlobalConfig.GetConfig(GlobalConfig.GLAEUBIGER_IDENTIFIKATIONSNUMMER_CONFIG_NAME) as string;

                if (String.IsNullOrWhiteSpace(gläubigerIdentifikationsnummer))
                {
                    throw new ArgumentNullException(nameof(gläubigerIdentifikationsnummer));
                }

                if (export.MandatsAusstellungsdatum == default)
                {
                    throw new ArgumentException(nameof(export.MandatsAusstellungsdatum));
                }

                if (String.IsNullOrWhiteSpace(export.Iban))
                {
                    throw new ArgumentNullException(nameof(export.Iban));
                }

                if (String.IsNullOrWhiteSpace(export.Bic))
                {
                    throw new ArgumentNullException(nameof(export.Iban));
                }


                SepaÜberweisung überweisung = new SepaÜberweisung
                {
                    Art = SepaArt.SEPA_BasisLastschrift,
                    Begünstiger = export.Kundenname,
                    BegünstigerZeile2 = "",
                    BicDesBegünstigten = export.Bic,
                    IbanDesBegünstigten = export.Iban,
                    Textschlüssel = textschlüssel,
                    Adressbuchübernahme = true,
                    Turnus = SepaTurnus.Einmalig,
                    Datum = DateTime.Now,
                    Rechnungsbetrag = export.Betrag,
                    AuftragAusführenAm = zahlungsziel,
                    Skonto = 0, // Bei Lastschrift gibt es kein Skonto
                    Währung = "EUR", // Währung ist immer Euro, da wir andere Währungen beim zubuchen in EUR umwandeln.
                    UnsereKundennummerBeimLieferanten = export.Kundennummer,
                    Ausstellungsdatum = export.MandatsAusstellungsdatum,
                    GläubigerIdentifikation = gläubigerIdentifikationsnummer,
                    Mandatsreferenz = export.Kundennummer,
                    Mandatsstatus = SepaMandatsstatus.Wiederkehrend
                };

                überweisung.Rechnungsnummern.Add($"RE-{export.Rechnungsnummer}");
                überweisungen.Add(überweisung);

                //Auf exportiert setzen
                await belegService.SetLastschriftExportedAsync(export.Rechnungsnummer, fbController);


                _exportDaten.Remove(export);
            }



            StringBuilder sb = new StringBuilder();
            sb.Append("Offline verwalten;");
            sb.Append("Adressbuchübernahme;");
            sb.Append("Eilauftrag;");
            sb.Append("Datum;");
            sb.Append("Begünstigter;");
            sb.Append("Begünstigter Zeile 2;");
            sb.Append("Begünstigter Zeile 3;");
            sb.Append("Begünstigter Zeile 4;");
            sb.Append("Konto des Begünstigten;");
            sb.Append("BLZ des Begünstigten;");
            sb.Append("IBAN des Begünstigten;");
            sb.Append("BIC des Begünstigten;");
            sb.Append("Rechnungsbetrag;");
            sb.Append("Skonto;");
            sb.Append("Währung;");
            sb.Append("Betrag;");
            for (int i = 0; i < SepaÜberweisung.ANZAHL_VERWENDUNGSZWECKE; i++)
            {
                sb.Append($"Verwendungszweckzeile {i + 1};");
            }

            sb.Append("Name des Spenders;");
            sb.Append("PLZ und Straße des Spenders;");
            sb.Append("Kontoinhaber;");
            sb.Append("Rechnungsnummer;");
            sb.Append("Turnus;");
            sb.Append("Ausführungstag;");
            sb.Append("Erstmalig;");
            sb.Append("Letzmalig;");
            sb.Append("Auftrag ausführen am;");
            sb.Append("Mandatsstatus;");
            sb.Append("Gläubiger-Identifikation;");
            sb.Append("Mandatsreferenz;");
            sb.Append("Ausstellungsdatum;");
            sb.Append("Automatisch Letztmalig;");
            sb.Append("Textschlüssel;");
            sb.Append($"Art;{Environment.NewLine}");
            foreach (SepaÜberweisung überweisung in überweisungen)
            {
                überweisung.WriteLine(ref sb);
            }
            await fbController.CommitChangesAsync();

            // StarMoney braucht die Datei als ISO-8859-1, wir haben den Inhalt aber als UTf-8, also müssen wir Konvertieren
            var bytes = Encoding.UTF8.GetBytes(sb.ToString());
            var bytesConverted = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), bytes);
            await downloadService.DownloadFile("StarMoney_LastschriftImport.csv", bytesConverted, "text/plain");
            await downloadService.ClearBuffers();
        }

        public void CleanUpTokenSource(ref CancellationTokenSource cts, bool createNewTokenSource = false)
        {
            cts?.Cancel();
            cts?.Dispose();

            if (createNewTokenSource)
            {
                cts = new CancellationTokenSource();
            }
        }


        public void Dispose()
        {
            CleanUpTokenSource(ref _loadingCts);
        }
    }
}
