using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;
using InABox.Core;
using NPOI.OpenXmlFormats.Wordprocessing;
using Syncfusion.UI.Xaml.Grid;

namespace InABox.DynamicGrid;

public abstract class DynamicGridEditorColumn<TEntity, TEditor, TColumn> : IDynamicGridEditorColumn
    where TEntity : BaseObject
    where TEditor : class
    where TColumn : GridColumn, new()
{

    public TColumn Column { get; }
    
    public List<string> ExtraColumns { get; } = new();

    GridColumn IDynamicGridEditorColumn.Column => this.Column;
    
    public string? MappingName => _definition?.ColumnName.Replace('.', '_');
    
    public Func<BaseObject>? GetEntity { get; set; }
    
    public Action<Dictionary<string, object?>>? EntityChanged { get; set; }

    protected void UpdateData(Dictionary<string, object> updates)
    {
        var entity = GetEntity?.Invoke();
        if (entity != null)
        {
            var changes = new Dictionary<string, object?>();
            foreach (var key in updates.Keys)
                DynamicGridUtils.UpdateEditorValue(new BaseObject[] { entity }, key, updates[key], changes);
            EntityChanged?.Invoke(changes);
        }
    }

    protected DynamicGridEditorColumn(DynamicGridColumn definition)
    {
        Column = new TColumn()
        {
            UpdateTrigger = UpdateSourceTrigger.PropertyChanged
        };
        Definition = definition;
    }
    
    private DynamicGridColumn? _definition;

    public DynamicGridColumn? Definition
    {
        get => _definition;
        set
        {
            _definition = value;
            UpdateBinding(Column);
            if (Editor != null)
                DoConfigure(Column, Editor);
        }
    }

    public virtual GridSummaryColumn? Summary() => null;

    public TEditor? Editor
    {
        get
        {
            if (Definition != null)
            {
                var result = Definition?.Editor as TEditor;
                if (result == null)
                    result = CoreUtils.GetProperty<TEntity>(Definition.ColumnName)?.GetEditor() as TEditor;
                return result;
            }
            return null;
        }
    }

    protected virtual void UpdateBinding(TColumn column)
    {
        column.MappingName = MappingName;
    }

    protected TextAlignment GetTextAlignment(TEditor editor) => Definition?.Alignment == Alignment.NotSet
        ? editor is NumericEditor ? TextAlignment.Right : TextAlignment.Left
        : Definition?.Alignment == Alignment.BottomLeft || 
          Definition?.Alignment == Alignment.MiddleLeft || 
          Definition?.Alignment == Alignment.TopLeft
            ? TextAlignment.Left
            : Definition?.Alignment == Alignment.BottomCenter ||
              Definition?.Alignment == Alignment.MiddleCenter ||
              Definition?.Alignment == Alignment.TopCenter
                ? TextAlignment.Center
                : TextAlignment.Right;
    
    private void DoConfigure(TColumn column, TEditor editor)
    {
        Configure(column,editor);
        
        // Post-Configure the column - refactor from DynamicGrid.ReloadColumns()
        Column.Width = column.Width; // != 0 ? column.Width : double.NaN;

        Column.ColumnSizer =
            GridLengthUnitType
                .None; //column.Width != 0 ? GridLengthUnitType.None : GridLengthUnitType.AutoWithLastColumnFill;
        Column.HeaderText = string.IsNullOrWhiteSpace(Definition?.Caption)
            ? Definition?.ColumnName
            : Definition.Caption;

        Column.TextAlignment = GetTextAlignment(editor);

        Column.HorizontalHeaderContentAlignment = Column.TextAlignment == TextAlignment.Left
            ? HorizontalAlignment.Left
            : Column.TextAlignment == TextAlignment.Center
                ? HorizontalAlignment.Center
                : HorizontalAlignment.Right;

    }
    
    
    protected abstract void Configure(TColumn column, TEditor editor);

    public virtual bool VariableWidth => true;
    public virtual bool VariableHeight => false;

    public virtual bool Filtered => true;

    public virtual bool Editable => Definition?.Editor.Editable == InABox.Core.Editable.Enabled;

}