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

namespace InABox.DynamicGrid
{
    public class DynamicIssuesColumn<T> : DynamicImageColumn
        where T : Entity, IRemotable, IPersistent, IIssues, new()
    {
        private static readonly BitmapImage _warning =Wpf.Resources.warning.AsBitmapImage();

        private readonly IDynamicGrid _parent;

        public DynamicIssuesColumn(IDynamicGrid parent) : base(IssuesImage)
        {
            Filters = new[] { "Active Issues", "No Issues" };
            FilterRecord = DoFilterIssues;
            ContextMenu = CreateIssuesMenu;
            ToolTip = CreateIssuesToolTip;
            _parent = parent;
            Position = DynamicActionColumnPosition.Start;
        }

        private static BitmapImage? IssuesImage(CoreRow? row)
        {
            if (row == null || string.IsNullOrWhiteSpace(row.Get<T, string>(x => x.Issues)))
                return null;
            return _warning;
        }

        private FrameworkElement? CreateIssuesToolTip(DynamicActionColumn column, CoreRow? row)
        {
            var text = row?.Get<T, string>(x => x.Issues);
            if (string.IsNullOrWhiteSpace(text))
                text = "No Issues Found";
            return TextToolTip(text);
        }

        private bool DoFilterIssues(CoreRow row, string[] filter)
        {
            var noissues = string.IsNullOrWhiteSpace(row?.Get<T, string>(x => x.Issues));
            if (filter.Contains("No Issues") && noissues)
                return true;
            if (filter.Contains("Active Issues") && !noissues)
                return true;
            return false;
        }

        private MenuItem CreateMenu(string caption, RoutedEventHandler click)
        {
            var item = new MenuItem();
            item.Header = caption;
            item.Click += click;
            return item;
        }

        private ContextMenu? CreateIssuesMenu(CoreRow[]? rows)
        {
            if (!Security.CanManageIssues<T>())
                return null;

            var issues = rows?.Select(r => r.Get<T, string>(x => x.Issues)).Where(x => !string.IsNullOrWhiteSpace(x)).Any();
            var result = new ContextMenu();

            if (issues != true)
            {
                result.Items.Add(CreateMenu("Create Issue", (o, e) => EditIssues(rows)));
            }
            else
            {
                result.Items.Add(CreateMenu("Update Issues", (o, e) => EditIssues(rows)));
                result.Items.Add(CreateMenu("Clear Issues", (o, e) => ClearIssues(rows)));
            }

            return result;
        }

        private void ClearIssues(CoreRow[]? rows)
        {
            if(rows is null)
            {
                return;
            }
            if (MessageBox.Show("This will clear the flagged issues for these items!\n\nAre you sure you wish to continue?", "Confirm",
                    MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                var _updates = rows.Select(x => x.ToObject<T>()).ToArray();
                foreach (var update in _updates)
                    update.Issues = "";
                using (new WaitCursor())
                {
                    new Client<T>().Save(_updates, "Clearing Issues", (o, e) => { });
                }

                // False here to prevent Refreshing and losing the selected row record
                foreach (var row in rows)
                    _parent.UpdateRow<T, string>(row, x => x.Issues, "");
            }
        }

        private void EditIssues(CoreRow[]? rows)
        {
            var map = new Dictionary<CoreRow, T>();
            if(rows is not null)
            {
                foreach (var row in rows)
                    map[row] = row.ToObject<T>();
            }

            if (new DynamicIssuesEditor(map.Values.ToArray()).ShowDialog() == true)
            {
                using (new WaitCursor())
                {
                    new Client<T>().Save(map.Values, "Updating Issues", (o, e) => { });
                }

                foreach (var row in map.Keys)
                    _parent.UpdateRow<T, string>(row, x => x.Issues, map[row].Issues);
            }
        }
    }
}