using Elwig.Dialogs;
using Elwig.Helpers;
using Elwig.Models.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Elwig.Windows {
    public partial class BaseDataWindow {

        private bool _seasonChanged = false;
        private bool _seasonUpdate = false;

        private async Task SeasonsInitEditing(AppDbContext ctx) {
            SeasonAddButton.IsEnabled = false;
            SeasonRemoveButton.IsEnabled = false;
            ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
                .OrderByDescending(s => s.Year)
                .Include(s => s.Modifiers)
                .Include(s => s.Currency)
                .ToListAsync());
            SeasonList_SelectionChanged(null, null);
        }

        private async Task SeasonsFinishEditing(AppDbContext ctx) {
            SeasonAddButton.IsEnabled = true;
            SeasonRemoveButton.IsEnabled = true;
            ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
                .OrderByDescending(s => s.Year)
                .Include(s => s.Modifiers)
                .Include(s => s.Currency)
                .ToListAsync());
            _seasonChanged = false;
        }

        private async Task SeasonsSave(AppDbContext ctx) {
            if (!_seasonChanged || SeasonList.SelectedItem is not Season s)
                return;
            ctx.Update(s);
            await ctx.SaveChangesAsync();
        }

        private void SeasonList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
            _seasonUpdate = true;
            if (SeasonList.SelectedItem is Season s) {
                SeasonModifierList.ItemsSource = s.Modifiers.OrderBy(m => m.Ordering).ToList();
                SeasonMaxKgPerHaInput.Text = s.MaxKgPerHa.ToString();
                SeasonVatNormalInput.Text = (s.VatNormal * 100).ToString();
                SeasonVatFlatrateInput.Text = (s.VatFlatrate * 100).ToString();
                SeasonStartInput.Text = $"{s.StartDate:dd.MM.yyyy}";
                SeasonEndInput.Text = $"{s.EndDate:dd.MM.yyyy}";
                SeasonMinKgPerBsInput.Text = s.MinKgPerBusinessShare.ToString();
                SeasonMaxKgPerBsInput.Text = s.MaxKgPerBusinessShare.ToString();
                SeasonPenaltyPerKgInput.Text = s.PenaltyPerKg?.ToString() ?? "";
                SeasonPenaltyInput.Text = s.PenaltyAmount?.ToString() ?? "";
                SeasonPenaltyNoneInput.Text = s.PenaltyNone?.ToString() ?? "";
                SeasonPenaltyPerBsInput.Text = s.PenaltyPerBsAmount?.ToString() ?? "";
                SeasonPenaltyPerBsNoneInput.Text = s.PenaltyPerBsNone?.ToString() ?? "";
                SeasonBsValueInput.Text = s.BusinessShareValue?.ToString() ?? "";

                var sym = s.Currency.Symbol ?? s.Currency.Code;
                SeasonModifierAbsInput.Unit = $"{sym}/kg";
                SeasonPenaltyPerKgInput.Unit = $"{sym}/kg";
                SeasonPenaltyInput.Unit = sym;
                SeasonPenaltyNoneInput.Unit = sym;
                SeasonPenaltyPerBsInput.Unit = $"{sym}/GA";
                SeasonPenaltyPerBsNoneInput.Unit = $"{sym}/GA";
                SeasonBsValueInput.Unit = $"{sym}/GA";
                AreaCommitmentTypePenaltyPerKgInput.Unit = $"{sym}/kg";
                AreaCommitmentTypePenaltyInput.Unit = sym;
                AreaCommitmentTypePenaltyNoneInput.Unit = sym;
            } else {
                SeasonModifierList.ItemsSource = null;
                SeasonMaxKgPerHaInput.Text = "";
                SeasonVatNormalInput.Text = "";
                SeasonVatFlatrateInput.Text = "";
                SeasonStartInput.Text = "";
                SeasonEndInput.Text = "";
                SeasonMinKgPerBsInput.Text = "";
                SeasonMaxKgPerBsInput.Text = "";
                SeasonPenaltyPerKgInput.Text = "";
                SeasonPenaltyInput.Text = "";
                SeasonPenaltyNoneInput.Text = "";
                SeasonPenaltyPerBsInput.Text = "";
                SeasonPenaltyPerBsNoneInput.Text = "";
                SeasonBsValueInput.Text = "";
            }
            _seasonUpdate = false;
        }

        private void Season_Changed(object? sender, RoutedEventArgs? evt) {
            if (_seasonUpdate || (!IsEditing && !IsCreating) || SeasonList.SelectedItem is not Season s) return;
            _seasonChanged = true;

            if (SeasonMaxKgPerHaInput.Text.Length > 0)
                s.MaxKgPerHa = int.Parse(SeasonMaxKgPerHaInput.Text);
            if (SeasonVatNormalInput.Text.Length > 0)
                s.VatNormal = double.Parse(SeasonVatNormalInput.Text) / 100;
            if (SeasonVatFlatrateInput.Text.Length > 0)
                s.VatFlatrate = double.Parse(SeasonVatFlatrateInput.Text) / 100;
            if (SeasonMinKgPerBsInput.Text.Length > 0)
                s.MinKgPerBusinessShare = int.Parse(SeasonMinKgPerBsInput.Text);
            if (SeasonMaxKgPerBsInput.Text.Length > 0)
                s.MaxKgPerBusinessShare = int.Parse(SeasonMaxKgPerBsInput.Text);
            s.PenaltyPerKg = (SeasonPenaltyPerKgInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerKgInput.Text) : null;
            s.PenaltyAmount = (SeasonPenaltyInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyInput.Text) : null;
            s.PenaltyNone = (SeasonPenaltyNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyNoneInput.Text) : null;
            s.PenaltyPerBsAmount = (SeasonPenaltyPerBsInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsInput.Text) : null;
            s.PenaltyPerBsNone = (SeasonPenaltyPerBsNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsNoneInput.Text) : null;
            s.BusinessShareValue = (SeasonBsValueInput.Text.Length > 0) ? decimal.Parse(SeasonBsValueInput.Text) : null;

            UpdateButtons();
        }

        private void SeasonMinMaxKgInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckInteger((TextBox)sender, true, 5));
            Season_Changed(sender, evt);
        }

        private void SeasonVatInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, true, 2, 1));
            Season_Changed(sender, evt);
        }

        private void SeasonPenaltyPerKgInput_TextChanged(object sender, TextChangedEventArgs evt) {
            if (SeasonList.SelectedItem is not Season s) return;
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 2, s.Precision));
            Season_Changed(sender, evt);
        }

        private void SeasonPenaltyInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, 2));
            Season_Changed(sender, evt);
        }

        private void SeasonPenaltyPerBsInput_TextChanged(object sender, TextChangedEventArgs evt) {
            if (SeasonList.SelectedItem is not Season s) return;
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, s.Precision));
            Season_Changed(sender, evt);
        }

        private async void SeasonAddButton_Click(object sender, RoutedEventArgs evt) {
            var s = SeasonList.ItemsSource.Cast<Season>().FirstOrDefault();
            var year = Utils.CurrentYear;
            if (year == s?.Year) year++;

            List<Currency> currencies;
            using (var ctx = new AppDbContext()) {
                currencies = await ctx.Currencies
                    .OrderBy(c => c.Code)
                    .ToListAsync();
            }
            var d = new NewSeasonDialog(s, currencies);
            if (d.ShowDialog() == true) {
                Mouse.OverrideCursor = Cursors.AppStarting;
                try {
                    using var ctx = new AppDbContext();
                    ctx.Add(new Season {
                        Year = year,
                        CurrencyCode = d.CurrencyCode,
                        Precision = d.Precision,
                        MaxKgPerHa = s?.MaxKgPerHa ?? 10000,
                        VatNormal = s?.VatNormal ?? 0.10,
                        VatFlatrate = s?.VatFlatrate ?? 0.13,
                        MinKgPerBusinessShare = s?.MinKgPerBusinessShare ?? 500,
                        MaxKgPerBusinessShare = s?.MaxKgPerBusinessShare ?? 1000,
                        PenaltyPerKgValue = s?.PenaltyPerKgValue,
                        PenaltyAmoutValue = s?.PenaltyAmoutValue,
                        PenaltyNoneValue = s?.PenaltyNoneValue,
                        PenaltyPerBsAmountValue = s?.PenaltyPerBsAmountValue,
                        PenaltyPerBsNoneValue = s?.PenaltyPerBsNoneValue,
                        BusinessShareValueValue = s?.BusinessShareValueValue,
                        CalcMode = s?.CalcMode ?? 0,
                    });
                    if (s != null && d.CopyModifiers) {
                        int mult = d.Precision > s.Precision ? (int)Math.Pow(10, d.Precision - s.Precision) : 1;
                        int div = d.Precision < s.Precision ? (int)Math.Pow(10, s.Precision - d.Precision) : 1;
                        ctx.AddRange(s.Modifiers.Select(m => new Modifier {
                            Year = year,
                            ModId = m.ModId,
                            Ordering = m.Ordering,
                            Name = m.Name,
                            AbsValue = m.AbsValue * mult / div,
                            RelValue = m.RelValue,
                            IsStandard = m.IsStandard,
                            IsQuickSelect = m.IsQuickSelect,
                        }));
                    }
                    await ctx.SaveChangesAsync();
                } 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, "Saison anlegen", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                await App.HintContextChange();
                Mouse.OverrideCursor = null;
                SeasonList.SelectedIndex = 0;
            }
        }

        private async void SeasonRemoveButton_Click(object sender, RoutedEventArgs evt) {
            if (SeasonList.SelectedItem is not Season s)
                return;
            var r = MessageBox.Show(
                $"Soll die Saison {s.Year} wirklich unwiderruflich gelöscht werden?",
                "Saison 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();
                } 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, "Saison löschen", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                await App.HintContextChange();
                Mouse.OverrideCursor = null;
            }
        }
    }
}