using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Helpers.Export;
using Elwig.Models.Dtos;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;

namespace Elwig.Windows {
    public partial class MainWindow : ContextWindow {

        private readonly DispatcherTimer _syncTimer = new() { Interval = TimeSpan.FromHours(1) };

        public MainWindow() {
            InitializeComponent();
            var v = Assembly.GetExecutingAssembly().GetName().Version;
            VersionField.Text = $"Version: {v?.ToString() ?? "?"} – {App.BranchName}";
            if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
            Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
            Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
            Menu_Sync.IsEnabled = App.Config.SyncUrl != null;
            SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
            Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
            Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
        }

        private void Window_Loaded(object sender, RoutedEventArgs evt) {
            SeasonInput.Value = Utils.CurrentLastSeason;

            if (Utils.HasInternetConnectivity()) {
                CheckSync(200);
            }
            NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
            _syncTimer.Tick += new EventHandler(OnSyncTimer);
            _syncTimer.Start();
        }

        private void Window_Closing(object sender, CancelEventArgs evt) {
            if (App.NumWindows > 1 && !App.ForceShutdown) {
                foreach (var w in App.Current.Windows.Cast<Window>().Where(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
                    try {
                        w.Close();
                    } catch { }
                }
                Thread.Sleep(100);
                if (App.NumWindows > 1 && !App.Current.Windows.Cast<Window>().Any(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
                    var res = MessageBox.Show("Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?",
                        "Elwig beenden", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
                    if (res != MessageBoxResult.Yes) {
                        evt.Cancel = true;
                    } else {
                        Application.Current.Shutdown();
                    }
                }
            }
        }

        private void Menu_Help_About_Click(object sender, RoutedEventArgs evt) {
            var w = new AboutWindow();
            w.Show();
        }

        private async void Menu_Help_Update_Click(object sender, RoutedEventArgs evt) {
            await App.CheckForUpdates(true);
        }

        private async void Menu_Help_Smtp_Click(object sender, RoutedEventArgs evt) {
            Mouse.OverrideCursor = Cursors.Wait;
            try {
                using var client = await Utils.GetSmtpClient();
                await client!.DisconnectAsync(true);
                MessageBox.Show("E-Mail-Einstellungen erfolgreich überprüft!", "Erfolg", MessageBoxButton.OK, MessageBoxImage.Information);
            } catch (Exception exc) {
                MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            Mouse.OverrideCursor = null;
        }

        private void Menu_Help_Directory_Click(object sender, RoutedEventArgs evt) {
            try {
                Process.Start("explorer.exe", App.DataPath);
            } catch { }
        }

        private void Menu_Help_Config_Click(object sender, RoutedEventArgs evt) {
            try {
                Process.Start(new ProcessStartInfo {
                    FileName = "notepad.exe",
                    Arguments = App.ConfigPath,
                    Verb = "runas",
                    UseShellExecute = true,
                });
            } catch { }
        }

        private void Menu_Help_Log_Click(object sender, RoutedEventArgs evt) {
            var w = new LogWindow();
            w.Show();
        }

        private async void Menu_Scale_SetDateTime_Click(object sender, RoutedEventArgs evt) {
            if (App.CommandScales.Count == 0) {
                MessageBox.Show("Es sind keine geeigneten Waagen verfügbar!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            foreach (var s in App.CommandScales) {
                try {
                    await s.SetDateAndTime(DateTime.Now);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            MessageBox.Show("Datum und Uhrzeit auf entsprechenden Waagen gesetzt!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
            var w = new QueryWindow();
            w.Show();
        }

        private void Menu_Database_Open_Click(object sender, RoutedEventArgs evt) {
            if (Path.GetDirectoryName(App.Config.DatabaseFile) is string path)
                Process.Start("explorer.exe", path);
        }

        private void Menu_Database_Export_Click(object sender, RoutedEventArgs evt) {
            // TODO Menu_Database_Export_Click
        }

        private async void Menu_Database_Import_Click(object sender, RoutedEventArgs evt) {
            try {
                var d = new OpenFileDialog() {
                    Title = "Export-Datei auswählen - Elwig",
                    DefaultExt = "elwig.zip",
                    Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
                    Multiselect = true,
                };
                if (d.ShowDialog() == true) {
                    Mouse.OverrideCursor = Cursors.Wait;
                    await Task.Run(async () => {
                        await ElwigData.Import(d.FileNames, ElwigData.ImportMode.Interactively);
                    });
                }
            } catch (Exception exc) {
                MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
            try {
                var d = new SaveFileDialog() {
                    Title = "Datenbank sichern - Elwig",
                    FileName = $"database_{Utils.Today:yyyy-MM-dd}.sql.zip",
                    DefaultExt = "sql.zip",
                    Filter = "Komprimierte SQL-Datei (*.sql.zip)|*.sql.zip",
                    AddExtension = false,
                };
                if (d.ShowDialog() == true) {
                    if (!d.FileName.EndsWith(".sql.zip")) d.FileName += ".sql.zip";
                    Mouse.OverrideCursor = Cursors.Wait;
                    await Task.Run(async () => {
                        await Database.ExportSql(d.FileName, true);
                    });
                }
            } catch (Exception exc) {
                MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Database_Restore_Click(object sender, RoutedEventArgs evt) {
            try {
                var d = new OpenFileDialog() {
                    Title = "Datenbank wiederherstellen - Elwig",
                    DefaultExt = "sql.zip",
                    Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
                };
                if (d.ShowDialog() == true) {
                    var res = MessageBox.Show("Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?", "Datenbank wiederherstellen",
                        MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
                    if (res != MessageBoxResult.OK)
                        return;

                    Mouse.OverrideCursor = Cursors.Wait;
                    await App.ReplaceDatabase(d.FileName);
                }
            } catch (Exception exc) {
                MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            Mouse.OverrideCursor = null;
        }

        private async void SyncButton_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;
            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
                await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
            });
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Sync_Download_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;
            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
            });
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Sync_UploadBranchDeliveries_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;
            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                await SyncService.UploadBranchDeliveries(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
            });
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;
            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
            });
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Database_Download_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;
            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
                    var files = data
                        .Select(f => new {
                            Name = f!["name"]!.AsValue().GetValue<string>(),
                            Timestamp = f!["modified"] != null && DateTime.TryParseExact(f!["modified"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
                            Url = f!["url"]!.AsValue().GetValue<string>(),
                            Size = f!["size"]!.AsValue().GetValue<long>(),
                        })
                        .Where(f => f.Name.StartsWith("database.") && f.Name.EndsWith(".zip"))
                        .OrderBy(f => f.Size)
                        .ToList();

                    if (files.Count == 0) {
                        MessageBox.Show("Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!", "Datenbank herunterladen",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                    var file = files[0];

                    var res = MessageBox.Show($"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\nWollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\nDas kann zu Datenverlust führen!", "Datenbank herunterladen",
                        MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
                    if (res != MessageBoxResult.OK)
                        return;

                    var filename = Path.Combine(App.TempPath, file.Name);
                    using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
                        using var stream = new FileStream(filename, FileMode.Create);
                        await client.DownloadAsync(file.Url, stream);
                    }

                    res = MessageBox.Show("Die Datenbank wurde erfolgreich heruntergeladen!\n\nSoll die Datenbank wirklich unwiederruflich ersetzt werden?\n\nWenn Sie unsicher sind sprechen Sie sich mit dem Benutzer des Hauptgerätes ab!", "Datenbank herunterladen",
                        MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
                    if (res != MessageBoxResult.OK)
                        return;

                    await App.MainDispatcher.BeginInvoke(async () => {
                        await App.ReplaceDatabase(filename);
                    });
                } catch (HttpRequestException exc) {
                    MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
                } catch (TaskCanceledException exc) {
                    MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }

        private async void Menu_Database_Upload_Click(object sender, RoutedEventArgs evt) {
            if (App.Config.SyncUrl == null)
                return;

            var res = MessageBox.Show("Sind Sie wirklich sicher, dass Sie die Datenbank dieses\nGerätes hochladen möchten? Das sollte nur vom Hauptgerät aus passieren!", "Datenbank hochladen",
                MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
            if (res != MessageBoxResult.OK)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var path = Path.Combine(App.TempPath, "database.sql.zip");
                    await Database.ExportSql(path, true);
                    await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
                    MessageBox.Show($"Hochladen der gesamten Datenbank erfolgreich!", "Datenbank hochladen",
                        MessageBoxButton.OK, MessageBoxImage.Information);
                } catch (HttpRequestException exc) {
                    MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
                } catch (TaskCanceledException exc) {
                    MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }

        private void MemberAdminButton_Click(object sender, RoutedEventArgs evt) {
            var w = new MemberAdminWindow();
            w.Show();
        }

        private void ReceiptButton_Click(object sender, RoutedEventArgs evt) {
            App.FocusReceipt();
        }

        private void DeliveryAdminButton_Click(object sender, RoutedEventArgs evt) {
            var w = new DeliveryAdminWindow();
            w.Show();
        }

        private void DeliveryAncmtButton_Click(object sender, RoutedEventArgs evt) {
            App.FocusDeliveryAncmt();
        }

        private void BaseDataButton_Click(object sender, RoutedEventArgs evt) {
            App.FocusBaseData();
        }

        private void MailButton_Click(object sender, RoutedEventArgs evt) {
            App.FocusMailWindow();
        }

        protected async override Task OnRenewContext(AppDbContext ctx) {
            SeasonInput_TextChanged(null, null);
            CheckSync();
        }

        private void OnSyncTimer(object? sender, EventArgs? evt) {
            if (Utils.HasInternetConnectivity()) {
                CheckSync();
            }
        }

        private void OnNetworkAvailabilityChanged(object? sender, NetworkAvailabilityEventArgs evt) {
            if (!evt.IsAvailable) return;
            if (Utils.HasInternetConnectivity()) {
                CheckSync(1000);
            }
        }

        private async void CheckSync(int delay = 0) {
            if (App.Config.SyncUrl == null) return;
            Utils.RunBackground("Daten Synchronisieren", async () => {
                await Task.Delay(delay);
                var ch = false;
                using (var ctx = new AppDbContext()) {
                    ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
                }
                await App.MainDispatcher.BeginInvoke(() => {
                    if (ch) {
                        SyncButton_1.Text = "\uEA6A";
                        SyncButton_2.Text = "\uEA81";
                    } else {
                        SyncButton_1.Text = "\uE895";
                        SyncButton_2.Text = "";
                    }
                });
            });
        }

        private void SeasonFinish_Expanded(object sender, RoutedEventArgs evt) {
            Height = 660;
        }

        private void SeasonFinish_Collapsed(object sender, RoutedEventArgs evt) {
            Height = 390;
        }

        private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
            using var ctx = new AppDbContext();
            var year = SeasonInput.Value;
            var s0 = await ctx.Seasons.FindAsync(year);
            var valid = (s0 != null);
            DeliveryConfirmationButton.IsEnabled = valid;
            PaymentButton.IsEnabled = valid;
            OverUnderDeliveryButton.IsEnabled = valid;
            BreakdownButton.IsEnabled = valid;
            AreaCommitmentsButton.IsEnabled = valid;
            BreakdownMemberVarietyButton.IsEnabled = valid;

            SeasonStatMembersTotal.Text = "-";
            SeasonStatMembersGeb.Text = "-";
            SeasonStatWeightTotal.Text = "-";
            SeasonStatWeightGeb.Text = "-";
            SeasonStatWeightUngeb.Text = "-";
            SeasonStatArea.Text = "-";
            if (valid) {
                await Task.Run(async () => {
                    var membersTotal = await ctx.Deliveries.Where(d => d.Year == year).Select(d => d.Member).Distinct().CountAsync();
                    var areaComs = Utils.ActiveAreaCommitments(ctx.AreaCommitments, year!.Value);
                    var membersGeb = await areaComs.Select(c => c.Member).Distinct().CountAsync();
                    var weightTotal = await ctx.DeliveryParts.Where(p => p.Year == year).SumAsync(p => p.Weight);
                    var gebWeight = await ctx.DeliveryPartBuckets.Where(b => b.Year == year && b.Discr != "_").SumAsync(b => b.Value);
                    var area = await areaComs.SumAsync(c => c.Area);
                    await App.MainDispatcher.BeginInvoke(() => {
                        if (year != SeasonInput.Value) return;
                        SeasonStatMembersTotal.Text = $"{membersTotal:N0}";
                        SeasonStatMembersGeb.Text = $"{membersGeb:N0}";
                        SeasonStatWeightTotal.Text = $"{weightTotal:N0} kg";
                        SeasonStatWeightGeb.Text = $"{gebWeight:N0} kg";
                        SeasonStatWeightUngeb.Text = $"{weightTotal - gebWeight:N0} kg";
                        SeasonStatArea.Text = $"{area:N0} m²";
                    });
                });
            };
        }

        private void DeliveryConfirmationButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            var w = App.FocusMailWindow(year);
            w.AddDeliveryConfirmation();
        }

        private void PaymentButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            App.FocusPaymentVariants(year);
        }

        private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            var d = new SaveFileDialog() {
                FileName = $"Über-Unterlieferungen-{year}.ods",
                DefaultExt = "ods",
                Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
                Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
            };
            if (d.ShowDialog() == false)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var b = new Billing(year);
                    await b.FinishSeason();
                    await b.CalculateBuckets();
                    App.HintContextChange();

                    using var ctx = new AppDbContext();
                    var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
                    var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
                    using var ods = new OdsFile(d.FileName);
                    await ods.AddTable(tbl1);
                    await ods.AddTable(tbl2);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }

        private async void BreakdownButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            var d = new SaveFileDialog() {
                FileName = $"Aufschlüsselung-{year}.ods",
                DefaultExt = "ods",
                Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
                Title = $"Sorten-/Qualitätsaufschlüsselung {year} speichern unter - Elwig"
            };
            if (d.ShowDialog() == false)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var b = new Billing(year);
                    await b.FinishSeason();
                    await b.CalculateBuckets();
                    App.HintContextChange();

                    using var ctx = new AppDbContext();
                    using var ods = new OdsFile(d.FileName);
                    var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
                    await ods.AddTable(tblTotal);
                    foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
                        var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
                        await ods.AddTable(tbl);
                    }
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }

        private async void AreaCommitmentsButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            var d = new SaveFileDialog() {
                FileName = $"Flächenbindungen-{year}.ods",
                DefaultExt = "ods",
                Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
                Title = $"Flächenbindungen {year} speichern unter - Elwig"
            };
            if (d.ShowDialog() == false)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var b = new Billing(year);
                    await b.FinishSeason();
                    await b.CalculateBuckets();
                    App.HintContextChange();

                    using var ctx = new AppDbContext();
                    var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
                    using var ods = new OdsFile(d.FileName);
                    await ods.AddTable(tbl);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }

        private async void BreakdownMemberVarietyButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonInput.Value is not int year)
                return;
            var d = new SaveFileDialog() {
                FileName = $"Liefermengen-Ertrag-{year}.ods",
                DefaultExt = "ods",
                Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
                Title = $"Liefermengen/Ertrag {year} speichern unter - Elwig"
            };
            if (d.ShowDialog() == false)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            await Task.Run(async () => {
                try {
                    var b = new Billing(year);
                    await b.FinishSeason();
                    await b.CalculateBuckets();
                    App.HintContextChange();

                    using var ctx = new AppDbContext();
                    var tbl = await MemberDeliveryYieldsPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
                    using var ods = new OdsFile(d.FileName);
                    await ods.AddTable(tbl);
                } catch (Exception exc) {
                    MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            });
            Mouse.OverrideCursor = null;
        }
    }
}
