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

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

        public BaseDataWindow() {
            InitializeComponent();
            RequiredInputs = [
                ClientNameInput, ClientNameTypeInput, ClientNameTokenInput, ClientNameShortInput,
                ClientAddressInput, ClientPlzInput, ClientOrtInput,
            ];
            ExemptInputs = [
                ClientNameFull,
                BranchIdInput, BranchNameInput, BranchPlzInput, BranchOrtInput,
                BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
                WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
                WineAttributeMaxKgPerHaInput.TextBox, WineAttributeStrictInput, WineAttributeFillLowerInput,
                WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput,
                AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
                AreaCommitmentTypeMinKgPerHaInput.TextBox, AreaCommitmentTypePenaltyPerKgInput.TextBox,
                AreaCommitmentTypePenaltyInput.TextBox, AreaCommitmentTypePenaltyNoneInput.TextBox,
                SeasonMaxKgPerHaInput.TextBox, SeasonVatNormalInput.TextBox, SeasonVatFlatrateInput.TextBox, SeasonStartInput, SeasonEndInput,
                SeasonMinKgPerBsInput.TextBox, SeasonMaxKgPerBsInput.TextBox, SeasonBsValueInput.TextBox,
                SeasonPenaltyPerKgInput.TextBox, SeasonPenaltyInput.TextBox, SeasonPenaltyNoneInput.TextBox,
                SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput.TextBox, SeasonModifierAbsInput.TextBox,
            ];
            WineAttributeFillLowerInput.Visibility = Visibility.Hidden;
            WineAttributeFillLowerLabel.Visibility = Visibility.Hidden;
        }

        new protected void LockInputs() {
            base.LockInputs();

            BranchIdInput.IsReadOnly = true;
            BranchNameInput.IsReadOnly = true;
            BranchPlzInput.IsReadOnly = true;
            BranchOrtInput.IsEnabled = false;
            BranchAddressInput.IsReadOnly = true;
            BranchPhoneNrInput.IsReadOnly = true;
            BranchFaxNrInput.IsReadOnly = true;
            BranchMobileNrInput.IsReadOnly = true;

            WineAttributeIdInput.IsReadOnly = true;
            WineAttributeNameInput.IsReadOnly = true;
            WineAttributeActiveInput.IsEnabled = false;
            WineAttributeMaxKgPerHaInput.TextBox.IsReadOnly = true;
            WineAttributeStrictInput.IsEnabled = false;
            WineAttributeFillLowerInput.IsEnabled = false;

            WineCultivationIdInput.IsReadOnly = true;
            WineCultivationNameInput.IsReadOnly = true;
            WineCultivationDescriptionInput.IsReadOnly = true;

            AreaCommitmentTypeWineVariantInput.IsEnabled = false;
            AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
            AreaCommitmentTypeMinKgPerHaInput.TextBox.IsReadOnly = true;
            AreaCommitmentTypePenaltyPerKgInput.TextBox.IsReadOnly = true;
            AreaCommitmentTypePenaltyInput.TextBox.IsReadOnly = true;
            AreaCommitmentTypePenaltyNoneInput.TextBox.IsReadOnly = true;

            SeasonMaxKgPerHaInput.TextBox.IsReadOnly = true;
            SeasonVatNormalInput.TextBox.IsReadOnly = true;
            SeasonVatFlatrateInput.TextBox.IsReadOnly = true;
            SeasonMinKgPerBsInput.TextBox.IsReadOnly = true;
            SeasonMaxKgPerBsInput.TextBox.IsReadOnly = true;
            SeasonPenaltyPerKgInput.TextBox.IsReadOnly = true;
            SeasonPenaltyInput.TextBox.IsReadOnly = true;
            SeasonPenaltyNoneInput.TextBox.IsReadOnly = true;
            SeasonBsValueInput.TextBox.IsReadOnly = true;

            SeasonModifierIdInput.IsReadOnly = true;
            SeasonModifierNameInput.IsReadOnly = true;
            SeasonModifierRelInput.TextBox.IsReadOnly = true;
            SeasonModifierAbsInput.TextBox.IsReadOnly = true;
        }

        new protected void UnlockInputs() {
            base.UnlockInputs();

            BranchIdInput.IsReadOnly = false;
            BranchNameInput.IsReadOnly = false;
            BranchPlzInput.IsReadOnly = false;
            BranchOrtInput.IsEnabled = true;
            BranchAddressInput.IsReadOnly = false;
            BranchPhoneNrInput.IsReadOnly = false;
            BranchFaxNrInput.IsReadOnly = false;
            BranchMobileNrInput.IsReadOnly = false;

            WineAttributeIdInput.IsReadOnly = false;
            WineAttributeNameInput.IsReadOnly = false;
            WineAttributeActiveInput.IsEnabled = true;
            WineAttributeMaxKgPerHaInput.TextBox.IsReadOnly = false;
            WineAttributeStrictInput.IsEnabled = true;
            WineAttributeFillLowerInput.IsEnabled = true;

            WineCultivationIdInput.IsReadOnly = false;
            WineCultivationNameInput.IsReadOnly = false;
            WineCultivationDescriptionInput.IsReadOnly = false;

            AreaCommitmentTypeWineVariantInput.IsEnabled = true;
            AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
            AreaCommitmentTypeMinKgPerHaInput.TextBox.IsReadOnly = false;
            AreaCommitmentTypePenaltyPerKgInput.TextBox.IsReadOnly = false;
            AreaCommitmentTypePenaltyInput.TextBox.IsReadOnly = false;
            AreaCommitmentTypePenaltyNoneInput.TextBox.IsReadOnly = false;

            SeasonMaxKgPerHaInput.TextBox.IsReadOnly = false;
            SeasonVatNormalInput.TextBox.IsReadOnly = false;
            SeasonVatFlatrateInput.TextBox.IsReadOnly = false;
            SeasonMinKgPerBsInput.TextBox.IsReadOnly = false;
            SeasonMaxKgPerBsInput.TextBox.IsReadOnly = false;
            SeasonPenaltyPerKgInput.TextBox.IsReadOnly = false;
            SeasonPenaltyInput.TextBox.IsReadOnly = false;
            SeasonPenaltyNoneInput.TextBox.IsReadOnly = false;
            SeasonBsValueInput.TextBox.IsReadOnly = false;

            SeasonModifierIdInput.IsReadOnly = false;
            SeasonModifierNameInput.IsReadOnly = false;
            SeasonModifierRelInput.TextBox.IsReadOnly = false;
            SeasonModifierAbsInput.TextBox.IsReadOnly = false;
        }

        private void Window_Loaded(object sender, RoutedEventArgs evt) {
            LockInputs();
        }

        protected override async Task OnRenewContext(AppDbContext ctx) {
            await base.OnRenewContext(ctx);
            FillInputs(App.Client);
            ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
                .OrderByDescending(s => s.Year)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
            var year = (SeasonList.SelectedItem as Season)?.Year;
            ControlUtils.RenewItemsSource(BranchList, await ctx.Branches
                .OrderBy(b => b.Name)
                .Include(b => b.PostalDest!.AtPlz)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
            ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
                .OrderBy(a => a.Name)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
            ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.WineVarieties
                .OrderBy(s => s.Name)
                .ToListAsync());
            var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
            attrList.Insert(0, new NullItem(""));
            ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList);
            ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
                .OrderBy(t => t.VtrgId)
                .Include(t => t.WineVar)
                .Include(t => t.WineAttr)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
            ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations
                .OrderBy(c => c.Name)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
            ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
                .Where(m => m.Year == year)
                .OrderBy(m => m.Ordering)
                .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
        }

        protected override void UpdateButtons() {
            if (!IsEditing && !IsCreating) return;
            bool ch = _branchChanged || _attrChanged || _cultChanged || _actChanged ||
                      _seasonChanged || _modChanged || HasChanged,
                v = IsValid;
            CancelButton.IsEnabled = true;
            ResetButton.IsEnabled = ch;
            SaveButton.IsEnabled = ch && v;

            BranchAddButton.IsEnabled = true;
            BranchDeleteButton.IsEnabled = BranchList.SelectedIndex != -1;
            WineAttributeAddButton.IsEnabled = true;
            WineAttributeDeleteButton.IsEnabled = WineAttributeList.SelectedIndex != -1;
            WineCultivationAddButton.IsEnabled = true;
            WineCultivationDeleteButton.IsEnabled = WineCultivationList.SelectedIndex != -1;
            AreaCommitmentTypeAddButton.IsEnabled = true;
            AreaCommitmentTypeDeleteButton.IsEnabled = AreaCommitmentTypeList.SelectedIndex != -1;
            SeasonModifierUpButton.IsEnabled = SeasonModifierList.SelectedIndex >= 1;
            SeasonModifierDownButton.IsEnabled = SeasonModifierList.SelectedIndex != -1 && SeasonModifierList.SelectedIndex < (_modList?.Count - 1 ?? 0);
            SeasonModifierAddButton.IsEnabled = true;
            SeasonModifierDeleteButton.IsEnabled = SeasonModifierList.SelectedIndex != -1;
        }

        private void OriginButton_Click(object sender, RoutedEventArgs evt) {
            App.FocusOriginHierarchy();
        }

        private async Task InitEditing() {
            using var ctx = new AppDbContext();
            await BranchesInitEditing(ctx);
            await WineAttributesInitEditing(ctx);
            await WineCultivationsInitEditing(ctx);
            await AreaCommitmentTypesInitEditing(ctx);
            await SeasonsInitEditing(ctx);
            await ModifiersInitEditing(ctx);
        }

        private async Task Save() {
            using var ctx = new AppDbContext();
            // FIXME
            //using var tx = await ctx.Database.BeginTransactionAsync();
            await UpdateClientParameters(App.Client);
            await BranchesSave(ctx);
            await WineAttributesSave(ctx);
            await WineCultivationsSave(ctx);
            await AreaCommitmentTypesSave(ctx);
            await SeasonsSave(ctx);
            await ModifiersSave(ctx);
            //await tx.CommitAsync();
        }

        private async Task FinishEditing() {
            using var ctx = new AppDbContext();
            await BranchesFinishEditing(ctx);
            await WineAttributesFinishEditing(ctx);
            await WineCultivationsFinishEditing(ctx);
            await AreaCommitmentTypesFinishEditing(ctx);
            await SeasonsFinishEditing(ctx);
            await ModifiersFinishEditing(ctx);
        }

        private async void EditButton_Click(object sender, RoutedEventArgs evt) {
            IsEditing = true;
            EditButton.Visibility = Visibility.Hidden;
            ResetButton.Visibility = Visibility.Visible;

            await InitEditing();

            UnlockInputs();
            UpdateButtons();
        }

        private async void CancelButton_Click(object sender, RoutedEventArgs evt) {
            IsEditing = false;
            IsCreating = false;
            EditButton.Visibility = Visibility.Visible;
            ResetButton.Visibility = Visibility.Hidden;
            CancelButton.IsEnabled = false;
            SaveButton.IsEnabled = false;
            ResetButton.IsEnabled = false;

            await FinishEditing();

            ClearInputStates();
            FillInputs(App.Client);
            LockInputs();
        }

        private async void ResetButton_Click(object sender, RoutedEventArgs evt) {
            _branchChanged = false;
            _attrChanged = false;
            _cultChanged = false;
            _modChanged = false;

            await InitEditing();

            ClearInputStates();
            FillInputs(App.Client);
            UpdateButtons();
        }

        private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
            try {
                await Save();
            } 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, "Stammdaten aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            IsEditing = false;
            IsCreating = false;
            EditButton.Visibility = Visibility.Visible;
            ResetButton.Visibility = Visibility.Hidden;
            CancelButton.IsEnabled = false;
            SaveButton.IsEnabled = false;
            ResetButton.IsEnabled = false;

            await FinishEditing();

            ClearInputStates();
            FillInputs(App.Client);
            LockInputs();

            await HintContextChange();
        }

        private void FillInputs(ClientParameters p) {
            ClearOriginalValues();
            ClearDefaultValues();

            ClientNameInput.Text = p.Name;
            ClientNameSuffixInput.Text = p.NameSuffix;
            ClientNameTypeInput.Text = p.NameType;
            ClientNameTokenInput.Text = p.NameToken;
            ClientNameShortInput.Text = p.NameShort;
            ClientAddressInput.Text = p.Address;
            ClientPlzInput.Text = p.Plz.ToString();
            ClientOrtInput.Text = p.Ort;
            ClientIbanInput.Text = p.Iban;
            ClientBicInput.Text = p.Bic;
            ClientUstIdNrInput.Text = p.UstIdNr;
            ClientLfbisNrInput.Text = p.LfbisNr;
            ClientPhoneNrInput.Text = p.PhoneNr;
            ClientFaxNrInput.Text = p.FaxNr;
            ClientEmailAddressInput.Text = p.EmailAddress;
            ClientWebsiteInput.Text = p.Website;

            TextElementDeliveryNote.Text = p.TextDeliveryNote;
            switch (p.ModeDeliveryNoteStats) {
                case 0: ModeDeliveryNoteNone.IsChecked = true; break;
                case 1: ModeDeliveryNoteGaOnly.IsChecked = true; break;
                case 2: ModeDeliveryNoteShort.IsChecked = true; break;
                case 3: ModeDeliveryNoteFull.IsChecked = true; break;
            }
            TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation;
            TextElementCreditNote.Text = p.TextCreditNote;

            FinishInputFilling();
        }

        private async Task UpdateClientParameters(ClientParameters p) {
            p.Name = ClientNameInput.Text;
            p.NameSuffix = ClientNameSuffixInput.Text.Length > 0 ? ClientNameSuffixInput.Text : null;
            p.NameType = ClientNameTypeInput.Text;
            p.NameToken = ClientNameTokenInput.Text;
            p.NameShort = ClientNameShortInput.Text;
            p.Address = ClientAddressInput.Text;
            p.Plz = int.Parse(ClientPlzInput.Text);
            p.Ort = ClientOrtInput.Text;
            p.Iban = ClientIbanInput.Text.Length > 0 ? ClientIbanInput.Text : null;
            p.Bic = ClientBicInput.Text.Length > 0 ? ClientBicInput.Text : null;
            p.UstIdNr = ClientUstIdNrInput.Text.Length > 0 ? ClientUstIdNrInput.Text : null;
            p.LfbisNr = ClientLfbisNrInput.Text.Length > 0 ? ClientLfbisNrInput.Text : null;
            p.PhoneNr = ClientPhoneNrInput.Text.Length > 0 ? ClientPhoneNrInput.Text : null;
            p.FaxNr = ClientFaxNrInput.Text.Length > 0 ? ClientFaxNrInput.Text : null;
            p.EmailAddress = ClientEmailAddressInput.Text.Length > 0 ? ClientEmailAddressInput.Text : null;
            p.Website = ClientWebsiteInput.Text.Length > 0 ? ClientWebsiteInput.Text : null;

            p.TextDeliveryNote = TextElementDeliveryNote.Text.Length > 0 ? TextElementDeliveryNote.Text : null;
            p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2;
            p.TextDeliveryConfirmation = TextElementDeliveryConfirmation.Text.Length > 0 ? TextElementDeliveryConfirmation.Text : null;
            p.TextCreditNote = TextElementCreditNote.Text.Length > 0 ? TextElementCreditNote.Text : null;

            await p.UpdateValues();
        }

        private void ClientNames_TextChanged(object sender, TextChangedEventArgs evt) {
            var suffix = ClientNameSuffixInput.Text.Length > 0 ? ClientNameSuffixInput.Text : null;
            ClientNameFull.Text = $"{ClientNameInput.Text}{(suffix != null ? $", {suffix}," : "")} {ClientNameTypeInput.Text}";
            TextBox_TextChanged(sender, evt);
        }
    }
}