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

namespace Elwig.Dialogs {
    public partial class DeliverySplittingDialog : ContextWindow {

        public class Row {
            public DeliveryPart Part { get; set; }
            public bool SplitCompletely { get; set; }
            public string? SplitWeightString { get; set; }
            public int? SplitWeight {
                get => int.TryParse(SplitWeightString, out var v) ? v : null;
                set => SplitWeightString = $"{value}";
            }
            public bool SplitWeightEnabled { get; set; }
        }

        private readonly Delivery _delivery;

        public int? MgNr { get; set; }
        public string? LsNr { get; set; }
        public int[]? Weights => DeliveryParts.Select(r => r.SplitCompletely ? r.Part.Weight : r.SplitWeight ?? 0).ToArray();

        public ObservableCollection<Row> DeliveryParts { get; set; }

        public DeliverySplittingDialog(Delivery d) {
            _delivery = d;
            DeliveryParts = new(d.Parts.Select(p => new Row {
                Part = p,
                SplitCompletely = false,
                SplitWeight = null,
                SplitWeightEnabled = true,
            }).ToList());
            InitializeComponent();
        }

        protected override async Task OnRenewContext(AppDbContext ctx) {
            ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
                .Where(m => m.IsActive)
                .OrderBy(m => m.Name)
                .ThenBy(m => m.GivenName)
                .ToListAsync());
            ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries
                .Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId)
                .OrderBy(d => d.LsNr)
                .Include(d => d.Member)
                .Include(d => d.Parts)
                .ToListAsync());
            if (DeliveryInput.SelectedItem == null)
                ControlUtils.SelectItem(DeliveryInput, _delivery);
            CheckValidity();
        }

        private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
            if (DepreciateModeInput.IsChecked == true) {
                MgNr = null;
                LsNr = null;
            } else if (MemberModeInput.IsChecked == true) {
                MgNr = ((Member)MemberInput.SelectedItem).MgNr;
                LsNr = null;
            } else if (DeliveryModeInput.IsChecked == true) {
                MgNr = null;
                LsNr = ((Delivery)DeliveryInput.SelectedItem).LsNr;
            }
            DialogResult = true;
            Close();
        }

        private void ModeInput_Changed(object sender, RoutedEventArgs evt) {
            if (!IsLoaded) return;
            CheckValidity();
            if (DepreciateModeInput.IsChecked == true) {
                MgNrInput.Visibility = Visibility.Hidden;
                MemberInput.Visibility = Visibility.Hidden;
                MemberReferenceButton.Visibility = Visibility.Hidden;
                DeliveryInput.Visibility = Visibility.Hidden;
            } else if (MemberModeInput.IsChecked == true) {
                MgNrInput.Visibility = Visibility.Visible;
                MemberInput.Visibility = Visibility.Visible;
                MemberReferenceButton.Visibility = Visibility.Visible;
                DeliveryInput.Visibility = Visibility.Hidden;
            } else if (DeliveryModeInput.IsChecked == true) {
                MgNrInput.Visibility = Visibility.Hidden;
                MemberInput.Visibility = Visibility.Hidden;
                MemberReferenceButton.Visibility = Visibility.Hidden;
                DeliveryInput.Visibility = Visibility.Visible;
            }
        }

        private void CheckValidity() {
            var weight = DeliveryParts.Sum(r => r.SplitCompletely ? r.Part.Weight : r.SplitWeight ?? 0);
            var total = DeliveryParts.Sum(r => r.Part.Weight);
            InfoBlock.Text = $"Insgesamt {weight:N0} kg / {total:N0} kg ausgewählt.";
            ConfirmButton.IsEnabled = DeliveryParts.Any(r => r.SplitCompletely || r.SplitWeight > 0) && (
                DepreciateModeInput.IsChecked == true ||
                (MemberModeInput.IsChecked == true && MemberInput.SelectedItem != null && !DeliveryParts.All(r => r.SplitCompletely)) ||
                (DeliveryModeInput.IsChecked == true && DeliveryInput.SelectedItem != null));
        }

        private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
            var res = Validator.CheckMgNr((TextBox)sender, true);
            var text = MgNrInput.Text;
            var caret = MgNrInput.CaretIndex;
            ControlUtils.SelectItemWithPk(MemberInput, res.IsValid ? int.Parse(MgNrInput.Text) : null);
            MgNrInput.Text = text;
            MgNrInput.CaretIndex = caret;
        }

        private void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
            var m = MemberInput.SelectedItem as Member;
            MgNrInput.Text = m?.MgNr.ToString();
            CheckValidity();
        }

        private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
            if (MemberInput.SelectedItem is not Member m) return;
            App.FocusMember(m.MgNr);
        }

        private void DeliveryInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
            CheckValidity();
        }

        private void SplitCompletelyInput_Changed(object sender, RoutedEventArgs evt) {
            var checkbox = (CheckBox)sender;
            var dpnr = int.Parse(checkbox.Tag.ToString()!);
            var row = DeliveryParts.First(d => d.Part.DPNr == dpnr);
            if (checkbox.IsChecked == true) {
                row.SplitWeightEnabled = false;
                row.SplitWeight = row.Part.Weight;
            } else if (checkbox.IsChecked == false) {
                row.SplitWeightEnabled = true;
                row.SplitWeight = null;
            }
            CollectionViewSource.GetDefaultView(DeliveryParts).Refresh();
            CheckValidity();
        }

        private void SplitWeightInput_TextChanged(object sender, TextChangedEventArgs evt) {
            var textbox = (TextBox)sender;
            Validator.CheckInteger(textbox, false, 6);
            var dpnr = int.Parse(textbox.Tag.ToString()!);
            var row = DeliveryParts.First(d => d.Part.DPNr == dpnr);
            var w = int.TryParse(textbox.Text, out var v) ? v : (int?)null;
            if (w >= row.Part.Weight) {
                row.SplitCompletely = true;
                row.SplitWeightEnabled = false;
                row.SplitWeight = row.Part.Weight;
                CollectionViewSource.GetDefaultView(DeliveryParts).Refresh();
            }
            CheckValidity();
        }
    }
}