using System;
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.Editors;
using InABox.WPF;

namespace InABox.DynamicGrid;

public class DynamicProblemsColumn<TEntity> : DynamicImageColumn
    where TEntity : Entity, IRemotable, IPersistent, IProblems, new()
{
    private static readonly BitmapImage _warning = Wpf.Resources.warning.AsBitmapImage();
    private static readonly BitmapImage _graywarning = Wpf.Resources.warning.AsGrayScale().AsBitmapImage();

    private readonly IDynamicGrid<TEntity> _parent;

    public Func<IIssues[], FrameworkElement?>? CustomiseEditor { get; set; }
    
    public Action<IIssues[], FrameworkElement?>? IssuesUpdated { get; set; }

    public DynamicProblemsColumn(IDynamicGrid<TEntity> parent)
    {
        Image = IssuesImage;
        GetFilter = () => new FuncCheckBoxDynamicGridColumnFilter(DoFilterIssues, FilterData);
        ContextMenu = CreateIssuesMenu;
        ToolTip = CreateIssuesToolTip;
        _parent = parent;
        Position = DynamicActionColumnPosition.Start;

        if (typeof(TEntity).GetInterfaceDefinition(typeof(IProblems<>)) is Type problemInterface)
        {
            var tProblem = problemInterface.GenericTypeArguments[0];
            foreach(var column in DynamicGridUtils.LoadEditorColumns(tProblem))
            {
                _parent.AddHiddenColumn(nameof(IProblems.Problem) + "." + column.Name);
            }
        }
    }

    private IEnumerable<Tuple<string, object?>> FilterData()
    {
        yield return new("Active Issues", true);
        yield return new("No Issues", false);
    }

    private bool DoFilterIssues(CoreRow row, Predicate<object?> filter)
    {
        var hasIssues = row?.Get<TEntity, string[]>(x => x.Problem.Notes)?.Any() == true;
        return filter(hasIssues);
    }
    
    private BitmapImage? IssuesImage(CoreRow? row)
    {
        if (row?.Get<TEntity,string[]>(x=>x.Problem.Notes)?.Any() != true)
            return null;
        return row?.Get<TEntity,DateTime>(x=>x.Problem.Resolved).IsEmpty() == true
            ? _warning
            : _graywarning;
    }

    private FrameworkElement? CreateIssuesToolTip(DynamicActionColumn column, CoreRow? row)
    {
        var text = row?.Get<TEntity, string[]>(x => x.Problem.Notes) ?? new string[] { };
        return TextToolTip(NotesEditor.FormatNotes(text));
    }

    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 (rows is null || rows.Length == 0) return null;

        if (!Security.CanManageProblems<TEntity>())
            return null;

        var issues = rows.Any(r => r.Get<TEntity, string[]>(x => x.Problem.Notes).Length > 0);
        var result = new ContextMenu();

        if (!issues)
        {
            result.Items.Add(CreateMenu("Create Issue", (o, e) => EditIssues(rows)));
        }
        else if(rows.Length > 1)
        {
            result.Items.Add(CreateMenu("Add Issue", (o, e) => AddIssue(rows)));
        }
        else
        {
            result.Items.Add(CreateMenu("Update Issues", (o, e) => EditIssues(rows)));
            if (Security.CanManageProblems<TEntity>())
            {
                result.Items.Add(new Separator());
                result.Items.Add(CreateMenu("Mark as Resolved", (o, e) => ResolveIssues(rows)));
            }
        }

        return result;
    }

    private void ResolveIssues(CoreRow[] rows)
    {
        var row = rows[0];
        
        var entity = row.ToObject<TEntity>();
        entity.Problem.Resolved = DateTime.Now;
        using (new WaitCursor())
            Client.Save(entity, "Resolving Issues", (o, e) => { });
        
        // False here to prevent Refreshing and losing the selected row record
        _parent.UpdateRow<TEntity, DateTime>(row, x=>x.Problem.Resolved, entity.Problem.Resolved);
        
        // 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 AddIssue(CoreRow[] rows)
    {
        var entities = rows.ToArray<TEntity>();
        var issue = "";
        if(TextEdit.Execute("Enter new issue: ", ref issue) && !issue.IsNullOrWhiteSpace())
        {
            foreach(var entity in entities)
            {
                entity.Problem.Notes = entity.Problem.Notes.Concatenate([issue]);
            }
            Client.Save(entities, "Saving Issues", (o, e) => { });
            _parent.UpdateRows(rows, entities);
        }
    }

    private void EditIssues(CoreRow[] rows)
    {
        var entities = rows.ToArray<TEntity>();
        
        var _grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicItemsListGrid<>), entities.First().Problem.GetType());
        if (_grid.EditItems(entities.ToArray(x => x.Problem)))
        {
            using (new WaitCursor())
                Client.Save(entities, "Saving Issues", (o, e) => { });
            _parent.UpdateRows(rows, entities);
        }
    }
}