using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
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<TIssues> : DynamicImageColumn
    where TIssues : Entity, IRemotable, IPersistent, IIssues, new()
{
    private static readonly BitmapImage _warning = Wpf.Resources.warning.AsBitmapImage();

    private readonly IDynamicGrid _parent;

    public string IssuesProperty;
    public Func<CoreRow[], TIssues[]> LoadIssues;

    public DynamicIssuesColumn(IDynamicGrid parent, string issuesProperty, Func<CoreRow[], TIssues[]> loadIssues)
    {
        Image = IssuesImage;
        Filters = new[] { "Active Issues", "No Issues" };
        FilterRecord = DoFilterIssues;
        ContextMenu = CreateIssuesMenu;
        ToolTip = CreateIssuesToolTip;
        _parent = parent;
        Position = DynamicActionColumnPosition.Start;

        IssuesProperty = issuesProperty;
        LoadIssues = loadIssues;
    }

    public DynamicIssuesColumn(IDynamicGrid parent):
        this(parent, CoreUtils.GetFullPropertyName<TIssues, string>(x => x.Issues, ""), (rows) => rows.ToObjects<TIssues>().ToArray())
    {
    }

    private string? GetIssues(CoreRow? row)
    {
        return row?.Get<string>(IssuesProperty);
    }

    private BitmapImage? IssuesImage(CoreRow? row)
    {
        if (GetIssues(row).IsNullOrWhiteSpace())
            return null;
        return _warning;
    }

    private FrameworkElement? CreateIssuesToolTip(DynamicActionColumn column, CoreRow? row)
    {
        var text = GetIssues(row);
        if (text.IsNullOrWhiteSpace())
            text = "No Issues Found";
        return TextToolTip(text);
    }

    private bool DoFilterIssues(CoreRow row, string[] filter)
    {
        var noissues = GetIssues(row).IsNullOrWhiteSpace();
        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<TIssues>())
            return null;

        var issues = rows?.Select(GetIssues).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 = LoadIssues(rows).ToArray();
            foreach (var update in _updates)
            {
                update.Issues = "";
            }
            using (new WaitCursor())
            {
                Client.Save(_updates, "Clearing Issues", (o, e) => { });
            }

            // False here to prevent Refreshing and losing the selected row record
            foreach (var row in rows)
                _parent.UpdateRow(row, IssuesProperty, "");
        }
    }

    private void EditIssues(CoreRow[]? rows)
    {
        var objects = LoadIssues(rows ?? Array.Empty<CoreRow>());

        var map = new Dictionary<CoreRow, TIssues>();
        if (rows is not null)
        {
            var i = 0;
            foreach (var row in rows)
            {
                map[row] = objects[i];
                ++i;
            }
        }

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

            foreach (var row in map.Keys)
                _parent.UpdateRow(row, IssuesProperty, map[row].Issues);
        }
    }
}