using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using InABox.Clients;
using InABox.Core;

namespace InABox.DynamicGrid
{
    public class CodePopupEditorControl : DynamicEditorControl<Guid>, IPopupEditorControl
    {
        private Type _type;
        private Guid _value = Guid.Empty;
        private TextBox Description;
        private TextBox Editor;

        private string origvalue = "";

        public CodePopupEditorControl()
        {
            OtherColumns = new Dictionary<string, string>();
        }

        public Dictionary<string, string> OtherColumns { get; }

        public string CodeColumn { get; set; }

        public event OnDefineFilter? OnDefineFilter;

        public event OnUpdateOtherEditorHandler OnUpdateOtherEditor;

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


            Editor = new TextBox
            {
                CharacterCasing = CharacterCasing.Upper,
                VerticalAlignment = VerticalAlignment.Stretch,
                VerticalContentAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Stretch
            };
            Editor.BorderThickness = new Thickness(0.75);
            Editor.BorderBrush = new SolidColorBrush(Colors.Black);
            Editor.SetValue(Grid.ColumnProperty, 0);
            Editor.SetValue(Grid.RowProperty, 0);

            Editor.PreviewKeyDown += Editor_PreviewKeyDown;
            Editor.GotFocus += Editor_GotFocus;
            Editor.AcceptsTab = true;
            Editor.LostFocus += Editor_LostFocus;
            Grid.Children.Add(Editor);

            var Select = new Button
            {
                VerticalAlignment = VerticalAlignment.Stretch,
                VerticalContentAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                Content = "..",
                Focusable = false
            };
            Select.BorderThickness = new Thickness(0, 0.75, 0.75, 0.75);
            Select.BorderBrush = new SolidColorBrush(Colors.Black);
            Select.SetValue(Grid.ColumnProperty, 1);
            Select.SetValue(Grid.RowProperty, 0);
            Select.Click += Select_Click;
            Grid.Children.Add(Select);

            Description = new TextBox
            {
                VerticalAlignment = VerticalAlignment.Stretch,
                VerticalContentAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                Margin = new Thickness(5, 0, 0, 0),
                IsReadOnly = true,
                Focusable = false,
                Background = new SolidColorBrush(Colors.Gainsboro)
            };
            Description.SetValue(Grid.ColumnProperty, 2);
            Description.SetValue(Grid.RowProperty, 0);
            Grid.Children.Add(Description);

            return Grid;
        }

        private void Editor_GotFocus(object sender, RoutedEventArgs e)
        {
            origvalue = Editor.Text;
        }

        private void Editor_LostFocus(object sender, RoutedEventArgs e)
        {
            if (Editor.Text.Equals(origvalue))
                return;

            var id = _value;
            LookupValue(CodeColumn, Editor.Text);
            if (id == Guid.Empty)
                CheckChanged();
        }


        private void Editor_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key.Equals(Key.Enter) || e.Key.Equals(Key.Tab))
            {
                if (string.IsNullOrEmpty(Editor.Text))
                {
                    if (!Editor.Text.Equals(origvalue))
                    {
                        LookupValue("ID", Guid.Empty);
                        CheckChanged();
                    }

                    Editor.MoveFocus(new TraversalRequest(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)
                        ? FocusNavigationDirection.Previous
                        : FocusNavigationDirection.Next));
                }
                else
                {
                    if (!Editor.Text.Equals(origvalue))
                    {
                        var code = Editor.Text;
                        LookupValue(CodeColumn, code);
                        if (_value != Guid.Empty)
                        {
                            CheckChanged();
                            Editor.MoveFocus(new TraversalRequest(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)
                                ? FocusNavigationDirection.Previous
                                : FocusNavigationDirection.Next));
                        }
                        else
                        {
                            if (DoSearch(code))
                                Editor.MoveFocus(new TraversalRequest(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)
                                    ? FocusNavigationDirection.Previous
                                    : FocusNavigationDirection.Next));
                        }
                    }
                    else
                    {
                        Editor.MoveFocus(new TraversalRequest(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)
                            ? FocusNavigationDirection.Previous
                            : FocusNavigationDirection.Next));
                    }
                }

                e.Handled = true;
            }
        }

        private void Editor_PreviewKeyUp(object sender, KeyEventArgs e)
        {
        }

        private void Editor_KeyUp(object sender, KeyEventArgs e)
        {
        }

        private void Select_Click(object sender, RoutedEventArgs e)
        {
            DoSearch(Editor.Text);
        }

        private bool DoSearch(string code)
        {
            var result = false;
            if (_type != null)
            {
                var columns = LookupFactory.DefineColumns(_type);
                var cols = OtherColumns.Keys.ToList();
                foreach (var column in columns.ColumnNames())
                    if (cols.Contains(column))
                        cols.Add(column);

                var list = new PopupList(_type, _value, cols.ToArray(), new Dictionary<string, string> { { CodeColumn, code } });

                list.OnDefineFilter += (o, e) => { return OnDefineFilter?.Invoke(o, e); };

                if (list.ShowDialog() == true)
                {
                    result = true;

                    _value = list.ID;

                    foreach (var key in OtherColumns.Keys)
                        OtherValues[OtherColumns[key]] = list.OtherValues[key];
                    CheckChanged();

                    Editor.Text = string.Format("{0}", list.OtherValues[CodeColumn]);

                    var display = new Dictionary<string, object>();
                    foreach (var key in list.OtherValues.Keys.Where(x => !string.Equals(x, CodeColumn)))
                        display[key] = list.OtherValues[key];

                    Description.Text =
                        LookupFactory.FormatLookup(_type, display,
                            new[] { CodeColumn }); //String.Join(" / ", display.Where(x=>(x != null) && !String.IsNullOrWhiteSpace(x.ToString())));
                }
            }

            return result;
        }

        //private void Clear_Click(object sender, RoutedEventArgs e)
        //{
        //    if (_type != null)
        //    {
        //        _value = Guid.Empty;
        //        foreach (var otherfield in OtherColumns.Keys)
        //            OtherValues[OtherColumns[otherfield]] = null;
        //        CheckChanged();
        //        Editor.Text = "";
        //    }
        //}

        public override int DesiredHeight()
        {
            return 25;
        }

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

        protected override Guid RetrieveValue()
        {
            return _value;
        }

        protected override void UpdateValue(Guid value)
        {
            var oldvalue = _value;
            _value = value;
            if (oldvalue != value)
            {
                if (Equals(value, Guid.Empty))
                    SetEmptyValue();
                else
                    LookupValue("ID", value);
            }
        }

        private void SetEmptyValue()
        {
            Editor.Text = "";
            Description.Text = "";
        }

        private void LookupValue(string column, object value)
        {
            var client = ClientFactory.CreateClient(_type);
            var columns = LookupFactory.DefineColumns(_type);
            var cols = columns.ColumnNames();
            foreach (var key in OtherColumns.Where(x => !cols.Contains(x.Key)))
                columns.Add(key.Key);
            var sort = LookupFactory.DefineSort(_type);
            var filter = Activator.CreateInstance(typeof(Filter<>).MakeGenericType(_type));
            CoreUtils.SetPropertyValue(filter, "Expression", CoreUtils.GetMemberExpression(_type, column));
            CoreUtils.SetPropertyValue(filter, "Operator", Operator.IsEqualTo);
            CoreUtils.SetPropertyValue(filter, "Value", value);

            var lookup = client.Query(filter, columns, sort);
            var display = new List<object>();
            var code = "";
            var id = Guid.Empty;
            var displaycols = LookupFactory.DefineColumns(_type).ColumnNames();
            var row = lookup.Rows.FirstOrDefault();
            if (row == null)
                row = lookup.NewRow(true);

            code = row[CodeColumn]?.ToString();
            id = (Guid)row["ID"];

            foreach (var col in displaycols.Where(x => !x.Equals("ID") && !x.Equals(CodeColumn)))
                display.Add(row[col]);

            foreach (var key in OtherColumns.Keys)
                if (lookup.Columns.Any(x => x.ColumnName.Equals(key)))
                    OtherValues[OtherColumns[key]] = row[key];

            _value = id;
            Editor.Text = code;
            Description.Text = string.Join(" / ", display.Where(x => x != null && !string.IsNullOrWhiteSpace(x.ToString())));
        }

        public override void Configure()
        {
            base.Configure();
            _type = (EditorDefinition as CodePopupEditor)!.Type;
        }

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

        public override void SetColor(Color color)
        {
            Editor.Background = new SolidColorBrush(color);
        }
    }
}