using Elwig.Helpers;
using Elwig.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Elwig.Windows {

    public partial class OriginHierarchyWindow : ContextWindow {

        private bool isUpdating = false;

        public OriginHierarchyWindow() {
            InitializeComponent();
            ActivateKgButton.IsEnabled = false;
            DeactivateKgButton.IsEnabled = false;
        }

        protected override async Task OnRenewContext() {
            ControlUtils.RenewItemsSource(WineOrigins, (await Context.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId), i => (i as WineOrigin)?.HkId, WineOrigins_SelectionChanged);
            if (WineOrigins.SelectedItem == null) {
                var hkid = await Context.WbKgs
                    .GroupBy(k => k.AtKg.Gem.WbGem.HkId)
                    .Where(g => g.Count() > 0)
                    .OrderByDescending(g => g.Count())
                    .Select(g => g.Key)
                    .FirstOrDefaultAsync();
                ControlUtils.SelectListBoxItem(WineOrigins, o => (o as WineOrigin)?.HkId, hkid);
            }
            ControlUtils.RenewItemsSource(WbGls, await Context.WbGls.OrderBy(g => g.GlNr).ToListAsync(), g => (g as WbGl)?.GlNr, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
            await UpdateWbGems();
            await UpdateWbKgs();
            await UpdateWbGlKgs();
            await UpdateWbRds();
        }

        private async Task UpdateWbGems() {
            WbGemsHeader.Content = "Gemeinden" + (WineOrigins.SelectedItem is WineOrigin o ? $" ({o.Name})" : "");
            var selHkId = (WineOrigins.SelectedItem as WineOrigin)?.HkId;
            ControlUtils.RenewItemsSource(WbGems, await Context.WbGems.Where(g => g.HkId == selHkId).Select(g => g.AtGem).OrderBy(g => g.Name).ToListAsync(), g => (g as AT_Gem)?.Gkz, WbGems_SelectionChanged);
            await UpdateWbKgs();
        }

        private async Task UpdateWbKgs() {
            WbKgsHeader.Content = "Verfügbare KG";
            IQueryable<AT_Kg>? kgs = null;
            if (WbGems.SelectedItem is AT_Gem g) {
                WbKgsHeader.Content += $" ({g.Name})";
                kgs = Context.Katastralgemeinden.Where(k => k.Gkz == g.Gkz);
            } else if (WineOrigins.SelectedItem is WineOrigin o) {
                WbKgsHeader.Content += $" ({o.Name})";
                kgs = Context.WbGems.Where(g => g.HkId == o.HkId).SelectMany(g => g.AtGem.Kgs);
            } else {
                kgs = null;
            }
            if (kgs == null) {
                WbKgs.ItemsSource = null;
            } else {
                ControlUtils.RenewItemsSource(WbKgs, await kgs.OrderBy(k => k.WbKg.Gl == null).ThenBy(k => k.WbKg.GlNr).ThenBy(k => k.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr, WbKgs_SelectionChanged);
            }
        }

        private async Task UpdateWbGlKgs() {
            WbGlKgsHeader.Content = "Aktive KG";
            if (WbGls.SelectedItem is WbGl g) {
                WbGlKgsHeader.Content += $" ({g.Name})";
                ControlUtils.RenewItemsSource(WbGlKgs, await Context.WbKgs.Where(k => k.GlNr == g.GlNr).Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr, WbGlKgs_SelectionChanged);
            } else {
                WbGlKgs.ItemsSource = null;
            }
            UpdateButtons();
        }

        private async Task UpdateStatusBar() {
            StatusKgName.Text = "Katastralgemeinde: ";
            StatusWbRds.Text = "Riede: ";
            StatusDefaultKgs.Text = "Stammgemeinde: ";
            StatusAreaCommitments.Text = "Flächenbindungen: ";
            StatusDeliveries.Text = "Lieferungen: ";
            if (WbGlKgs.SelectedItem is AT_Kg k && k.WbKg != null) {
                StatusKgName.Text += $"{k.Name} ({k.KgNr:00000})";
                var reeds = await Context.WbRde.Where(r => r.KgNr == k.KgNr).CountAsync();
                StatusWbRds.Text += $"{reeds:N0}";
                var activeMembers = await Context.Members.Where(m => m.IsActive && m.DefaultKgNr == k.KgNr).CountAsync();
                var allMembers = await Context.Members.Where(m => m.DefaultKgNr == k.KgNr).CountAsync();
                StatusDefaultKgs.Text += $"{activeMembers:N0} ({allMembers:N0})";
                var year = Utils.CurrentNextSeason;
                var activeAreaComs = await Context.AreaCommitments.Where(c => c.KgNr == k.KgNr && c.YearFrom <= year && (c.YearTo == null || c.YearTo >= year)).CountAsync();
                var allAreaComs = await Context.AreaCommitments.Where(c => c.KgNr == k.KgNr).CountAsync();
                StatusAreaCommitments.Text += $"{activeAreaComs:N0} ({allAreaComs:N0})";
                var deliveryParts = await Context.DeliveryParts.Where(p => p.KgNr == k.KgNr).CountAsync();
                var deliveries = await Context.Deliveries.Where(d => d.Parts.Any(p => p.KgNr == k.KgNr)).CountAsync();
                StatusDeliveries.Text += $"{deliveries:N0} ({deliveryParts:N0})";
            } else {
                StatusKgName.Text += "-";
                StatusWbRds.Text += "-";
                StatusDefaultKgs.Text += "-";
                StatusAreaCommitments.Text += "-";
                StatusDeliveries.Text += "-";
            }
        }

        private async Task UpdateWbRds() {
            WbRdsHeader.Content = "Riede";
            if (WbGlKgs.SelectedItem is AT_Kg k) {
                WbRdsHeader.Content += $" ({k.Name})";
                ControlUtils.RenewItemsSource(WbRds, await Context.WbRde.Where(r => r.KgNr == k.KgNr).OrderBy(r => r.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr);
            } else {
                WbRds.ItemsSource = null;
            }
            UpdateButtons();
        }

        private async void WineOrigins_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
            await UpdateWbGems();
        }

        private async void WbGls_SelectionChanged(object? sender, SelectionChangedEventArgs? e) {
            await UpdateWbGlKgs();
        }

        private async void WbGems_SelectionChanged(object? sender, SelectionChangedEventArgs? e) {
            await UpdateWbKgs();
        }

        private async void WbGlKgs_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            await UpdateWbRds();
            if (!isUpdating && WbGlKgs.SelectedItem is AT_Kg k) {
                isUpdating = true;
                ControlUtils.SelectListBoxItem(WineOrigins, o => (o as WineOrigin)?.HkId, k.Gem.WbGem?.HkId);
                ControlUtils.SelectListBoxItem(WbGems, g => (g as AT_Gem)?.Gkz, k.Gkz);
                ControlUtils.SelectListBoxItem(WbKgs, k => (k as AT_Kg)?.KgNr, k.KgNr);
                isUpdating = false;
            }
            await UpdateStatusBar();
        }

        private void WbKgs_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            UpdateButtons();
            if (!isUpdating && WbKgs.SelectedItem is AT_Kg k && k.WbKg != null && ((WbGls.SelectedItem as WbGl)?.GlNr == k.WbKg?.GlNr || WbGls.SelectedItem == null)) {
                isUpdating = true;
                ControlUtils.SelectListBoxItem(WbGls, g => (g as WbGl)?.GlNr, k.WbKg?.GlNr);
                ControlUtils.SelectListBoxItem(WbGlKgs, k => (k as AT_Kg)?.KgNr, k.KgNr);
                isUpdating = false;
            }
        }

        private void UpdateButtons() {
            if (WbKgs.SelectedItem is AT_Kg v) {
                ActivateKgButton.IsEnabled = v.WbKg?.GlNr != (WbGls.SelectedItem as WbGl)?.GlNr;
                ActivateKgButton.ToolTip = $"KG {v.Name} Großlage {(WbGls.SelectedItem as WbGl)?.Name} zuweisen";
            } else {
                ActivateKgButton.IsEnabled = false;
                ActivateKgButton.ToolTip = $"Verfügbare Katastralgemeinde Großlage {(WbGls.SelectedItem as WbGl)?.Name} zuweisen";
            }

            if (WbGlKgs.SelectedItem is AT_Kg a) {
                DeactivateKgButton.IsEnabled = true;
                DeactivateKgButton.ToolTip = $"KG {a.Name} deaktivieren";
            } else {
                DeactivateKgButton.IsEnabled = false;
                DeactivateKgButton.ToolTip = "Aktive Katastralgemeinde deaktivieren";
            }
        }

        private async void ActivateKgButton_Click(object sender, RoutedEventArgs e) {
            if (WbKgs.SelectedItem is not AT_Kg k || WbGls.SelectedItem is not WbGl g) return;
            try {
                if (k.WbKg != null) {
                    k.WbKg.GlNr = g.GlNr;
                    Context.Update(k.WbKg);
                } else {
                    var wbKg = Context.CreateProxy<WbKg>();
                    wbKg.KgNr = k.KgNr;
                    wbKg.GlNr = g.GlNr;
                    await Context.AddAsync(wbKg);
                }
                await Context.SaveChangesAsync();
                await App.HintContextChange();
                ControlUtils.SelectListBoxItem(WbGlKgs, kg => (kg as AT_Kg)?.KgNr, k.KgNr);
            } catch (Exception exc) {
                var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
                if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
                MessageBox.Show(str, "Katastralgemeinde aktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void DeactivateKgButton_Click(object sender, RoutedEventArgs e) {
            if (WbGlKgs.SelectedItem is not AT_Kg k || k.WbKg == null) return;
            var r = MessageBox.Show(
                $"Sollen alle Riede und Stammgemeinden-Einträge von der KG {k.Name} wirklich unwiderruflich gelöscht werden?",
                "Katastralgemeinde deaktivieren", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
            if (r != MessageBoxResult.Yes) return;
            try {
                Context.Remove(k.WbKg);
                await Context.SaveChangesAsync();
                await App.HintContextChange();
                ControlUtils.SelectListBoxItem(WbKgs, kg => (kg as AT_Kg)?.KgNr, k.KgNr);
            } catch (Exception exc) {
                await HintContextChange();
                var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message;
                if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
                MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        public void FocusKgNr(int kgnr) {
            var kg = Context.Katastralgemeinden.Find(kgnr);
            ControlUtils.SelectListBoxItem(WbGls, kg.WbKg.Gl, g => (g as WbGl)?.GlNr);
            ControlUtils.SelectListBoxItem(WbGlKgs, kg, k => (k as AT_Kg)?.KgNr);
            WbGlKgs.Focus();
        }
    }
}
