using InABox.Core;
using InABox.WPF;
using Syncfusion.Pdf.Parsing;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace InABox.DynamicGrid;

public class DynamicGridColumnNameSelectorGrid : DynamicItemsListGrid<DynamicGridColumnNameSelectorItem>, INotifyPropertyChanged
{
    private bool _canSave;
    public bool CanSave
    {
        get => _canSave;
        set
        {
            _canSave = value;
            DoPropertyChanged();
        }
    }

    private bool _onlyVisible;
    public bool OnlyVisible
    {
        get => _onlyVisible;
        set
        {
            _onlyVisible = value;
            Refresh(false, true);
            DoPropertyChanged();
        }
    }

    private List<DynamicGridColumnNameSelectorItem> _items;

    public string SearchText { get; set; } = "";

    public DynamicGridColumnNameSelectorGrid(IDynamicGridColumnSchema schema)
    {
        var itemMap = new Dictionary<string, DynamicGridColumnNameSelectorItem>();
        var items = new List<DynamicGridColumnNameSelectorItem>();
        var parentCols = new Dictionary<string, List<DynamicGridColumnNameSelectorItem>>();
        foreach (var column in schema.ColumnNames)
        {
            var item = new DynamicGridColumnNameSelectorItem();

            var props = column.Split('.');
            string? parent = null;
            for (int i = 0; i < props.Length - 1; ++i)
            {
                if (parent is null)
                {
                    parent = props[i];
                }
                else
                {
                    parent = $"{parent}.{props[i]}";
                }
                parentCols.GetValueOrAdd(parent).Add(item);
            }

            item.ColumnName = column;
            item.ParentColumn = parent;
            item.Display = props[^1];
            item.IsParent = false;
            item.Comment = schema.GetComment(column) ?? "";
            item.IsVisible = schema.IsVisible(column);
            items.Add(item);
        }

        foreach (var (col, children) in parentCols)
        {
            var lastColIdx = col.LastIndexOf('.');
            var item = new DynamicGridColumnNameSelectorItem
            {
                ColumnName = col,
                IsParent = true,
                Comment = schema.GetComment(col) ?? "",
                IsVisible = children.Any(x => x.IsVisible)
            };
            if (lastColIdx == -1)
            {
                item.ParentColumn = null;
                item.Display = col;
            }
            else
            {
                item.ParentColumn = col[..lastColIdx];
                item.Display = col[(lastColIdx + 1)..];
            }
            items.Add(item);
        }
        items.Sort((a, b) => a.ColumnName.CompareTo(b.ColumnName));

        _items = items;
    }

    protected override void DoReconfigure(DynamicGridOptions options)
    {
        base.DoReconfigure(options);
        options.Clear();
        options.FilterRows = true;
    }

    protected override void SelectItems(CoreRow[]? rows)
    {
        base.SelectItems(rows);
        CanSave = rows is not null && rows.Any(x => !LoadItem(x).IsParent);
        if(rows is not null)
        {
            foreach(var row in rows)
            {
                Component.ExpandRow(row);
            }
        }
    }

    protected override DynamicGridColumns LoadColumns()
    {
        var columns = new DynamicGridColumns<DynamicGridColumnNameSelectorItem>();
        columns.Add(x => x.Display, caption: "Name", width: 250);
        columns.Add(x => x.Comment);
        return columns;
    }

    private UIComponent? _uiComponent;
    private UIComponent Component
    {
        get
        {
            _uiComponent ??= new UIComponent(this);
            return _uiComponent;
        }
    }
    private class UIComponent : DynamicGridTreeUIComponent<DynamicGridColumnNameSelectorItem, string?>
    {
        DynamicGridColumnNameSelectorGrid Grid;

        public UIComponent(DynamicGridColumnNameSelectorGrid grid) : base(x => x.ColumnName, x => x.ParentColumn, null)
        {
            Parent = grid;
            Grid = grid;
            ExpandMode = DynamicTreeGridExpandMode.None;
            ShowHeader = false;
            MinRowHeight = 25;
            GridLines = DynamicTreeGridLines.Horizontal;
        }
        
        protected override Brush? GetCellForeground(CoreRow row, DynamicColumnBase column)
        {
            if(column is DynamicGridColumn gc && gc.ColumnName == nameof(DynamicGridColumnNameSelectorItem.Comment))
            {
                return Colors.Gray.ToBrush();
            }
            else
            {
                var item = Grid.LoadItem(row);
                if (item.IsParent)
                {
                    return Colors.Gray.ToBrush();
                }
                else
                {
                    return base.GetCellForeground(row, column);
                }
            }
        }

        protected override FontStyle? GetCellFontStyle(CoreRow row, DynamicColumnBase column)
        {
            if(column is DynamicGridColumn gc && gc.ColumnName == nameof(DynamicGridColumnNameSelectorItem.Comment))
            {
                return FontStyles.Italic;
            }
            else
            {
                var item = Grid.LoadItem(row);
                if (item.IsParent)
                {
                    return FontStyles.Italic;
                }
                else
                {
                    return base.GetCellFontStyle(row, column);
                }
            }
        }
    }
    protected override IDynamicGridUIComponent<DynamicGridColumnNameSelectorItem> CreateUIComponent() => Component;

    public event PropertyChangedEventHandler? PropertyChanged;
    protected void DoPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new(propertyName));
    }

    protected override void Reload(Filters<DynamicGridColumnNameSelectorItem> criteria, Columns<DynamicGridColumnNameSelectorItem> columns, ref SortOrder<DynamicGridColumnNameSelectorItem>? sort, CancellationToken token, Action<CoreTable?, Exception?> action)
    {
        if (SearchText.IsNullOrWhiteSpace())
        {
            Items = _items.ToList();
        }
        else
        {
            Items = new();

            foreach(var item in _items)
            {
                if (!item.IsParent && item.ColumnName.Contains(SearchText, StringComparison.CurrentCultureIgnoreCase))
                {
                    Items.Add(item);
                }
            }
            foreach(var item in _items)
            {
                if (item.IsParent && Items.Any(x => x.ColumnName.StartsWith(item.ColumnName + ".")))
                {
                    Items.Add(item);
                }
            }
        }
        if (OnlyVisible)
        {
            Items.RemoveAll(x => !x.IsVisible);
        }

        base.Reload(criteria, columns, ref sort, token, action);
    }

    public static bool SelectColumnName(Type type, IEnumerable<string> columnNames, out string value, bool showVisibilityButton = false)
    {
        return SelectColumnName(new DynamicGridObjectColumnSchema(type, columnNames), out value, showVisibilityButton: showVisibilityButton);
    }
    public static bool SelectColumnName(IDynamicGridColumnSchema schema, out string value, bool showVisibilityButton = false)
    {
        var grid = new DynamicGridColumnNameSelectorGrid(schema)
        {
            OnlyVisible = showVisibilityButton
        };
        grid.Refresh(true, true);

        var lbl = new Label
        {
            Content = "Search:",
            Margin = new Thickness(0, 0, 5, 5)
        };

        var search = new TextBox
        {
            Background = Colors.LightYellow.ToBrush(),
            Height = 25,
            Margin = new Thickness(0, 0, 0, 5),
            VerticalContentAlignment = VerticalAlignment.Center,
        };
        search.TextChanged += (o, e) =>
        {
            grid.SearchText = search.Text;
            grid.Refresh(false, true);
        };

        var onlyVisible = new CheckBox()
        {
            Content = "Only Visible?",
            VerticalAlignment = VerticalAlignment.Center,
            Margin = new(5, 0, 0, 5)
        };
        onlyVisible.Bind(CheckBox.IsCheckedProperty, grid, x => x.OnlyVisible);

        var control = new Grid();
        control.AddColumn(GridUnitType.Auto);
        control.AddColumn(GridUnitType.Star);
        if (showVisibilityButton)
        {
            control.AddColumn(GridUnitType.Auto);
        }
        else
        {
            control.AddColumn(0);
        }

        control.AddRow(GridUnitType.Auto);
        control.AddRow(GridUnitType.Star);

        control.AddChild(lbl, 0, 0);
        control.AddChild(search, 0, 1);
        control.AddChild(onlyVisible, 0, 2);
        control.AddChild(grid, 1, 0, colSpan: 3);

        var window = new DynamicContentDialog(control)
        {
            Title = "Select Column",
            Width = 600,
            Height = 600,
            WindowStartupLocation = WindowStartupLocation.CenterScreen
        };
        window.Bind(DynamicContentDialog.CanSaveProperty, grid, x => x.CanSave);

        grid.OnCellDoubleClick += (o, e) =>
        {
            if (e.Row is null) return;

            var item = grid.LoadItem(e.Row);
            if (!item.IsParent)
            {
                window.DialogResult = true;
            }
        };

        if(window.ShowDialog() == true && grid.SelectedRows.FirstOrDefault() is CoreRow row)
        {
            var item = grid.LoadItem(row);
            if (!item.IsParent)
            {
                value = item.ColumnName;
                return true;
            }
        }
        value = "";
        return false;
    }
}

public class DynamicGridColumnNameSelectorItem : BaseObject
{
    public string ColumnName { get; set; } = "";

    public string Display { get; set; } = "";

    public string? ParentColumn { get; set; }

    public string Comment { get; set; } = "";

    public bool IsVisible { get; set; }

    public bool IsParent { get; set; }
}
