using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Elwig.Windows {
    public partial class DeliveryScheduleAdminWindow : AdministrationWindow {

        public DeliveryScheduleAdminViewModel ViewModel => (DeliveryScheduleAdminViewModel)DataContext;

        private readonly RoutedCommand CtrlF = new("CtrlF", typeof(DeliveryScheduleAdminWindow), [new KeyGesture(Key.F, ModifierKeys.Control)]);

        public DeliveryScheduleAdminWindow() {
            InitializeComponent();
            CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
            ExemptInputs = [
                SearchInput, SeasonInput, OnlyUpcomingInput, DeliveryScheduleList,
            ];
            RequiredInputs = [
                DateInput, BranchInput, DescriptionInput, MainWineVarietiesInput,
            ];

            InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
            SearchInput.TextChanged -= SearchInput_TextChanged;
            ViewModel.FilterSeason = Utils.CurrentLastSeason;
        }

        private void Window_Loaded(object sender, RoutedEventArgs evt) {
            ViewModel.FilterOnlyUpcoming = true;
            LockInputs();
        }

        private async Task RefreshList(bool updateSort = false) {
            using var ctx = new AppDbContext();
            var (_, deliveryScheduleQuery, filter) = await ViewModel.GetFilters(ctx);
            var deliverySchedules = await deliveryScheduleQuery
                .Include(s => s.Varieties)
                .Include(s => s.Branch)
                .AsSplitQuery()
                .ToListAsync();

            if (filter.Count > 0 && deliverySchedules.Count > 0) {
                var dict = deliverySchedules.AsParallel()
                    .ToDictionary(s => s, s => s.SearchScore(filter))
                    .OrderByDescending(a => a.Value)
                    .ThenBy(a => a.Key.DateString)
                    .ThenBy(a => a.Key.Branch.Name)
                    .ThenBy(a => a.Key.Description);
                var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
                deliverySchedules = dict
                    .Where(a => a.Value > threshold)
                    .Select(a => a.Key)
                    .ToList();
            } else {
                deliverySchedules = deliverySchedules
                    .OrderBy(s => s.DateString)
                    .ThenBy(s => s.Branch.Name)
                    .ThenBy(s => s.Description)
                    .ToList();
            }

            ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules,
                DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
            if (updateSort && DeliveryScheduleList.SelectedItem != null)
                DeliveryScheduleList.ScrollIntoView(DeliveryScheduleList.SelectedItem);
        }

        private void RefreshInputs(bool validate = false) {
            ClearInputStates();
            if (ViewModel.SelectedDeliverySchedule is DeliverySchedule s) {
                EditDeliveryScheduleButton.IsEnabled = true;
                DeleteDeliveryScheduleButton.IsEnabled = true;
                FillInputs(s);
            } else {
                EditDeliveryScheduleButton.IsEnabled = false;
                DeleteDeliveryScheduleButton.IsEnabled = false;
                ClearOriginalValues();
                ClearDefaultValues();
                ClearInputs(validate);
                ClearInputStates();
            }
            GC.Collect();
        }

        private void InitInputs() {
            ClearOriginalValues();
            ClearDefaultValues();
            ViewModel.InitInputs();
            ValidateRequiredInputs();
        }

        protected override async Task OnRenewContext(AppDbContext ctx) {
            await base.OnRenewContext(ctx);

            ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync());
            var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync();
            ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties);
            ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties);
            var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
            attrList.Insert(0, new NullItem("- Keine Angabe -"));
            ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
            var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
            cultList.Insert(0, new NullItem("- Kein Angabe -"));
            ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);

            await RefreshList();
        }

        private void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) {
            RefreshInputs();
        }

        private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
            await RefreshList();
        }

        private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
            await RefreshList(true);
        }

        private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
            if (ViewModel.FilterSeason == null) return;
            ViewModel.FilterOnlyUpcoming = false;
            await RefreshList();
        }

        protected override void ShortcutNew() {
            if (!NewDeliveryScheduleButton.IsEnabled || NewDeliveryScheduleButton.Visibility != Visibility.Visible)
                return;
            NewDeliveryScheduleButton_Click(null, null);
        }

        private void NewDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) {
            IsCreating = true;
            DeliveryScheduleList.IsEnabled = false;
            ViewModel.SelectedDeliverySchedule = null;
            HideNewEditDeleteButtons();
            ShowSaveResetCancelButtons();
            UnlockInputs();
            InitInputs();
            ViewModel.EnableSearchInputs = false;
        }

        protected override void ShortcutEdit() {
            if (!EditDeliveryScheduleButton.IsEnabled || EditDeliveryScheduleButton.Visibility != Visibility.Visible)
                return;
            EditDeliveryScheduleButton_Click(null, null);
        }

        private void EditDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) {
            if (ViewModel.SelectedDeliverySchedule == null) return;
            IsEditing = true;
            DeliveryScheduleList.IsEnabled = false;
            HideNewEditDeleteButtons();
            ShowSaveResetCancelButtons();
            UnlockInputs();
            ViewModel.EnableSearchInputs = false;
        }

        protected override void ShortcutDelete() {
            if (!DeleteDeliveryScheduleButton.IsEnabled || DeleteDeliveryScheduleButton.Visibility != Visibility.Visible)
                return;
            DeleteDeliveryScheduleButton_Click(null, null);
        }

        private async void DeleteDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) {
            if (ViewModel.SelectedDeliverySchedule is not DeliverySchedule s)
                return;
            var r = MessageBox.Show(
                $"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?",
                "Leseplan löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
            if (r == MessageBoxResult.OK) {
                Mouse.OverrideCursor = Cursors.AppStarting;
                try {
                    using (var ctx = new AppDbContext()) {
                        ctx.Remove(s);
                        await ctx.SaveChangesAsync();
                    }
                    App.HintContextChange();
                } 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, "Leseplan löschen", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                Mouse.OverrideCursor = null;
            }
        }

        protected override void ShortcutSave() {
            if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible)
                return;
            SaveButton_Click(null, null);
        }

        private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
            Mouse.OverrideCursor = Cursors.AppStarting;
            try {
                await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr);
            } 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, "Leseplan aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            Mouse.OverrideCursor = null;
            IsEditing = false;
            IsCreating = false;
            DeliveryScheduleList.IsEnabled = true;
            HideSaveResetCancelButtons();
            ShowNewEditDeleteButtons();
            LockInputs();
            ViewModel.EnableSearchInputs = true;
            FinishInputFilling();
            await RefreshList();
            RefreshInputs();
            ViewModel.SearchQuery = "";
        }

        protected override void ShortcutReset() {
            if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible)
                return;
            ResetButton_Click(null, null);
        }

        private void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
            if (IsEditing) {
                RefreshInputs();
            } else if (IsCreating) {
                ClearInputs();
                InitInputs();
            }
            UpdateButtons();
        }

        private void CancelButton_Click(object? sender, RoutedEventArgs? evt) {
            IsEditing = false;
            IsCreating = false;
            DeliveryScheduleList.IsEnabled = true;
            HideSaveResetCancelButtons();
            ShowNewEditDeleteButtons();
            RefreshInputs();
            LockInputs();
            ViewModel.EnableSearchInputs = true;
        }

        private void FillInputs(DeliverySchedule s) {
            ClearOriginalValues();
            ClearDefaultValues();
            ViewModel.FillInputs(s);
            FinishInputFilling();
        }

        new protected void ClearInputs(bool validate = false) {
            ViewModel.ClearInputs();
            base.ClearInputs(validate);
        }

        protected override void UpdateButtons() {
            if (!IsEditing && !IsCreating) return;
            bool ch = HasChanged, v = IsValid;
            ResetButton.IsEnabled = ch;
            SaveButton.IsEnabled = v && ch;
        }

        private void FocusSearchInput(object sender, RoutedEventArgs evt) {
            if (!IsEditing && !IsCreating) {
                SearchInput.Focus();
                SearchInput.SelectAll();
            }
        }

        private void ShowSaveResetCancelButtons() {
            SaveButton.IsEnabled = false;
            ResetButton.IsEnabled = false;
            CancelButton.IsEnabled = true;
            ViewModel.EditingButtonsVisibility = Visibility.Visible;
        }

        private void HideSaveResetCancelButtons() {
            SaveButton.IsEnabled = false;
            ResetButton.IsEnabled = false;
            CancelButton.IsEnabled = false;
            ViewModel.EditingButtonsVisibility = Visibility.Hidden;
        }

        private void ShowNewEditDeleteButtons() {
            NewDeliveryScheduleButton.IsEnabled = true;
            EditDeliveryScheduleButton.IsEnabled = ViewModel.SelectedDeliverySchedule != null;
            DeleteDeliveryScheduleButton.IsEnabled = ViewModel.SelectedDeliverySchedule != null;
            ViewModel.ControlButtonsVisibility = Visibility.Visible;
        }

        private void HideNewEditDeleteButtons() {
            NewDeliveryScheduleButton.IsEnabled = false;
            EditDeliveryScheduleButton.IsEnabled = false;
            DeleteDeliveryScheduleButton.IsEnabled = false;
            ViewModel.ControlButtonsVisibility = Visibility.Hidden;
        }

        private void ScheduleDateInput_TextChanged(object sender, TextChangedEventArgs evt) {
            DateInput_TextChanged(sender, evt);
            if (ViewModel.Date is DateOnly date) {
                ViewModel.AncmtToDate = date.AddDays(-2);
            }
        }

        private void MaxWeightInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckInteger((TextBox)sender, false, 6));
        }
    }
}