using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using Image = System.Windows.Controls.Image;

namespace InABox.WPF
{
    public static class WPFUtils
    {
        public static T? FindLogicalParent<T>(this DependencyObject dependencyObject)
            where T : DependencyObject
        {
            DependencyObject? parent = dependencyObject; 
            do
            {
                parent = LogicalTreeHelper.GetParent(parent);
            } while(parent != null && parent is not T);
            return parent as T;
        }

        public static int GetRow(this Grid grid, DependencyObject dependencyObject)
        {
            while (true)
            {
                var parent = LogicalTreeHelper.GetParent(dependencyObject);
                if (parent == null)
                    return -1;
                if (parent == grid)
                    return Grid.GetRow(dependencyObject as UIElement);
                dependencyObject = parent;
            }
        }

        public static int GetRowSpan(this Grid grid, DependencyObject dependencyObject)
        {
            while (true)
            {
                var parent = LogicalTreeHelper.GetParent(dependencyObject);
                if (parent == null)
                    return -1;
                if (parent == grid)
                    return Grid.GetRowSpan(dependencyObject as UIElement);
                dependencyObject = parent;
            }
        }
        public static void SetGridPosition(this FrameworkElement element, int row, int column, int rowspan, int colspan)
        {
            element.SetValue(Grid.ColumnProperty, column);
            element.SetValue(Grid.ColumnSpanProperty, Math.Max(1, colspan));
            element.SetValue(Grid.RowProperty, row);
            element.SetValue(Grid.RowSpanProperty, Math.Max(1, rowspan));
        }

        public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
        {
            if (depObj != null)
                //ContentControl cc = depObj as ContentControl;
                //if (cc != null)
                //{
                //    if (cc.Content == null)
                //        yield return null;
                //    if (cc.Content is T)
                //        yield return cc.Content as T;
                //    foreach (var child in FindVisualChildren<T>(cc.Content as DependencyObject))
                //        yield return child;
                //}
                //else
                for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    var child = VisualTreeHelper.GetChild(depObj, i);
                    if (child is null)
                        continue;

                    if (child is T t)
                        yield return t;

                    foreach (var childOfChild in FindVisualChildren<T>(child))
                        yield return childOfChild;
                }
        }

        #region Menu Utils

        private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index)
        {
            if (index != -1)
            {
                menu.Items.Insert(index, item);
            }
            else
            {
                menu.Items.Add(item);
            }
        }

        private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, bool enabled, int index = -1)
        {
            var item = new MenuItem { Header = caption, IsEnabled = enabled };
            if (image != null)
                item.Icon = new Image() { Source = enabled ? image.AsBitmapImage(24, 24) : image.AsGrayScale().AsBitmapImage(24, 24) };

            ItemsControlInsert(menu, item, index);
            return item;
        }

        private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, Action? click, bool enabled, int index = -1)
        {
            var item = DoAddMenuItem(menu, caption, image, enabled, index);

            if (click != null)
            {
                item.Click += (o, e) =>
                {
                    click();
                };
            }

            return item;
        }
        private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled, int index = -1)
        {
            var item = DoAddMenuItem(menu, caption, image, enabled, index);

            item.Tag = tag;
            item.Click += (o, e) =>
            {
                click((T)(o as MenuItem)!.Tag);
            };

            return item;
        }

        public delegate void CheckToggleAction<T>(T tag, bool isChecked);

        private static MenuItem DoAddCheckItem<T>(ItemsControl menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked, bool enabled, int index = -1)
        {
            var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };

            item.Tag = tag;
            item.Click += (o, e) =>
            {
                click((T)(o as MenuItem)!.Tag, item.IsChecked);
            };

            ItemsControlInsert(menu, item, index);
            return item;
        }

        public static Separator AddSeparator(this ContextMenu menu, int index = -1)
        {
            var separator = new Separator();

            ItemsControlInsert(menu, separator, index);

            return separator;
        }
        public static Separator? AddSeparatorIfNeeded(this ContextMenu menu, int index = -1)
        {
            if (menu.Items.Count == 0) return null;

            var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1;
            if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null;

            var last = menu.Items[lastIndex];
            if (last is Separator) return null;

            var separator = new Separator();

            ItemsControlInsert(menu, separator, index);

            return separator;
        }

        public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
            => DoAddMenuItem(menu, caption, image, click, enabled, index);
        public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
            => DoAddMenuItem(menu, caption, image, click, enabled, index);
        public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
            => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
        public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
            => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
        public static MenuItem AddCheckItem<T>(this ContextMenu menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked = false, bool enabled = true, int index = -1)
            => DoAddCheckItem<T>(menu, caption, tag, click, isChecked, enabled, index);

        #endregion
    }
}