using InABox.Clients;
using InABox.Core;
using Syncfusion.Windows.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace InABox.DynamicGrid
{
    public class DimensionsEditorControl
    {
        public static BaseDynamicEditorControl? Create(DimensionsEditor editor)
        {
            var dimensionsType = editor.DimensionsType;
            var dimensions = dimensionsType.GetSuperclassDefinition(typeof(Dimensions<,>));
            if (dimensions == null) return null;

            var tLink = dimensions.GenericTypeArguments[0];
            var tUnit = dimensions.GenericTypeArguments[1];

            return Activator.CreateInstance(typeof(DimensionsEditorControl<,,>).MakeGenericType(dimensionsType, tLink, tUnit), editor) as BaseDynamicEditorControl;
        }
    }

    public class DimensionsEditorControl<TDimensions, TLink, TUnit> : DynamicEnclosedEditorControl<TDimensions>
        where TDimensions : Dimensions<TLink, TUnit>, new()
        where TLink : DimensionUnitLink<TUnit>, new()
        where TUnit : DimensionUnit, new()
    {
        private Grid Grid;
        private ComboBox Combo;

        private DoubleTextBox Quantity;
        private DoubleTextBox Length;
        private DoubleTextBox Width;
        private DoubleTextBox Height;
        private DoubleTextBox Weight;

        private List<Tuple<string, TUnit>> Units;

        private DimensionsEditor Editor;

        public DimensionsEditorControl(DimensionsEditor editor)
        {
            Editor = editor;
        }

        public override int DesiredHeight()
        {
            return 25;
        }

        public override int DesiredWidth()
        {
            return int.MaxValue;
        }

        public override void SetColor(Color color)
        {
            Quantity.Background = new SolidColorBrush(color);
            Length.Background = new SolidColorBrush(color);
            Width.Background = new SolidColorBrush(color);
            Height.Background = new SolidColorBrush(color);
            Weight.Background = new SolidColorBrush(color);
        }

        public override void SetFocus()
        {
            Combo.Focus();
        }

        protected override FrameworkElement CreateEditor()
        {
            Grid = new Grid
            {
                VerticalAlignment = VerticalAlignment.Stretch,
                HorizontalAlignment = HorizontalAlignment.Stretch
            };
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(150, GridUnitType.Pixel) });

            Combo = new ComboBox
            {
                IsEnabled = Editor.AllowEditingUnit
            };
            Combo.SetValue(Grid.ColumnProperty, 0);
            Combo.SetValue(Grid.RowProperty, 0);

            Grid.Children.Add(Combo);

            var result = new Client<TUnit>()
                .Query(
                    LookupFactory.DefineFilter<TUnit>(),
                    LookupFactory.DefineColumns<TUnit>(),
                    LookupFactory.DefineSort<TUnit>());

            Units = result.Rows.Select(row =>
            {
                var values = row.ToDictionary(new[] { "Display" });
                var display = LookupFactory.FormatLookup(typeof(TUnit), values, Array.Empty<string>());
                return new Tuple<string, TUnit>(display, row.ToObject<TUnit>());
            }).ToList();

            Combo.DisplayMemberPath = "Item1";
            Combo.SelectedValuePath = "Item2.ID";
            Combo.ItemsSource = Units;
            Combo.SelectionChanged += Combo_SelectionChanged;

            Quantity = AddDimension("Quantity: ", 1);
            Length = AddDimension("Length: ", 2);
            Width = AddDimension("Width: ", 3);
            Height = AddDimension("Height: ", 4);
            Weight = AddDimension("Weight: ", 5);

            return Grid;
        }

        private void UpdateColumn(int column, bool visible, DoubleTextBox box)
        {
            if (!visible)
            {
                box.Value = 0.0;
            }

            var columnDefinition = Grid.ColumnDefinitions[column * 2];
            if (visible)
            {
                columnDefinition.Width = new GridLength(1, GridUnitType.Star);
            }
            else
            {
                columnDefinition.Width = new GridLength(0);
            }
            columnDefinition = Grid.ColumnDefinitions[column * 2 - 1];
            if (visible)
            {
                columnDefinition.Width = GridLength.Auto;
            }
            else
            {
                columnDefinition.Width = new GridLength(0);
            }
        }

        private DoubleTextBox AddDimension(string name, int column)
        {
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0) });
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0) });

            var label = new Label
            {
                Content = name,
                VerticalAlignment = VerticalAlignment.Center,
                VerticalContentAlignment = VerticalAlignment.Center,
                Margin = new Thickness(5, 0, 0, 0)
            };
            label.SetValue(Grid.ColumnProperty, column * 2 - 1);

            var box = new DoubleTextBox
            {
                VerticalAlignment = VerticalAlignment.Stretch,
                VerticalContentAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Center,
                NumberDecimalDigits = 2,
                Margin = new Thickness(5, 0, 0, 0)
            };
            box.SetValue(Grid.ColumnProperty, column * 2);
            box.ValueChanged += Box_ValueChanged;

            Grid.Children.Add(label);
            Grid.Children.Add(box);

            return box;
        }

        private void Box_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CheckChanged();
        }

        private void Combo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (Combo.SelectedValue is not Guid unitID) return;
            if (Combo.SelectedItem is not Tuple<string, TUnit> tuple) return;
            var unit = tuple.Item2;

            UpdateColumn(1, unit.HasQuantity, Quantity);
            UpdateColumn(2, unit.HasLength, Length);
            UpdateColumn(3, unit.HasWidth, Width);
            UpdateColumn(4, unit.HasHeight, Height);
            UpdateColumn(5, unit.HasWeight, Weight);

            foreach(var property in DatabaseSchema.Properties(typeof(TUnit)))
            {
                var value = property.Getter()(unit);
                OtherValues[$"{ColumnName}.Unit.{property.Name}"] = value;
            }

            CheckChanged();
        }

        public override object? GetValue(string property)
        {
            if (!property.StartsWith($"{ColumnName}.")) return null;
            property = property[(ColumnName.Length + 1)..];

            if (property == "Quantity") return Quantity.Value ?? 0.0;
            if (property == "Length") return Length.Value ?? 0.0;
            if (property == "Width") return Width.Value ?? 0.0;
            if (property == "Height") return Height.Value ?? 0.0;
            if (property == "Weight") return Weight.Value ?? 0.0;
            if (property == "Unit.ID") return Combo.SelectedValue is Guid guid ? guid : Guid.Empty;

            return null;
        }
        public override Dictionary<string, object?> GetValues()
        {
            var values = new Dictionary<string, object?>
            {
                {$"{ColumnName}.Quantity", Quantity.Value ?? 0.0},
                {$"{ColumnName}.Length", Length.Value ?? 0.0},
                {$"{ColumnName}.Width", Width.Value ?? 0.0},
                {$"{ColumnName}.Height", Height.Value ?? 0.0},
                {$"{ColumnName}.Weight", Weight.Value ?? 0.0},
                {$"{ColumnName}.Unit.ID", Combo.SelectedValue is Guid guid ? guid : Guid.Empty }
            };
            return values;
        }

        public override void SetValue(string property, object? value)
        {
            if (!property.StartsWith($"{ColumnName}.")) return;
            property = property[(ColumnName.Length + 1)..];

            if (value is null) return;

            if (property == "Unit.ID")
            {
                Combo.SelectedValue = value is Guid guid ? guid : Guid.Empty;
                return;
            }

            if (property == "Quantity") Quantity.Value = (double)value;
            if (property == "Length") Length.Value = (double)value;
            if (property == "Width") Width.Value = (double)value;
            if (property == "Height") Height.Value = (double)value;
            if (property == "Weight") Weight.Value = (double)value;
        }

    }
}
