using InABox.Core;
using InABox.DynamicGrid;
using InABox.Wpf.Dashboard.Editor;
using InABox.WPF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace InABox.Wpf.Dashboard;

public class DynamicDashboardGridPresenterProperties : BaseObject
{
    /// <summary>
    /// The key of the query that will provide the data for this presenter.
    /// </summary>
    public string Table { get; set; } = "";

    public DynamicGridColumns? Columns { get; set; }
}

[Caption("Grid")]
public class DynamicDashboardGridPresenter : IDynamicDashboardDataPresenter<DynamicDashboardGridPresenterProperties>
{
    public DynamicDashboardGridPresenterProperties Properties { get; set; } = null!;

    private DynamicDashboardDataComponent _dataComponent = null!;
    public DynamicDashboardDataComponent DataComponent
    {
        get => _dataComponent;
        set
        {
            _dataComponent = value;
            UpdateData();
        }
    }

    public int PreviewHeight => 300;

    public bool IsPreview { get; set; }

    private CoreTableGrid? Grid;
    private readonly ContentControl Content = new();

    private DynamicDashboardData? _data;

    public FrameworkElement? Setup()
    {
        UpdateData();
        return Content;
    }

    private void UpdateData()
    {
        if (Properties.Table.IsNullOrWhiteSpace() || !DataComponent.TryGetTable(Properties.Table, out var table))
        {
            Properties.Table = DataComponent.Tables.FirstOrDefault()?.Key ?? "";
        }

        if (!DataComponent.TryGetTable(Properties.Table, out table))
        {
            var border = new Border
            {
                Background = Colors.DimGray.ToBrush()
            };
            border.ContextMenuOpening += Border_ContextMenuOpening;
            Content.Content = border;
            return;
        }

        Grid = new DataGrid(this)
        {
            ColumnSchema = new DataGridColumnSchema(this)
        };
        Grid.Refresh(true, false);

        Content.Content = Grid as FrameworkElement;
    }

    private void CustomiseMenu(ContextMenu menu)
    {
        if (!IsPreview) return;

        var tableItem = menu.AddItem("Select Table", null, null);
        foreach(var table in DataComponent.Tables)
        {
            tableItem.AddCheckMenuItem(table.Key, table.Key, SelectTable_Click, isChecked: Properties.Table == table.Key);
        }
        if(tableItem.Items.Count <= 1)
        {
            menu.Items.Remove(tableItem);
        }
        menu.AddItem("Select Data", null, SelectData_Click);
    }

    private void SelectData_Click()
    {
        if (DynamicDashboardDataEditor.Execute(DataComponent))
        {
            UpdateData();
            DataComponent.RunQueryAsync(100).ContinueWith(data =>
            {
                if(data.Exception is not null)
                {
                    MessageWindow.ShowError("Error loading data.", data.Exception);
                }
                else
                {
                    Refresh(data.Result);
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
    }

    private void SelectTable_Click(string key, bool isChecked)
    {
        if (!isChecked) return;

        Properties.Table = key;
        Properties.Columns = null;

        UpdateData();
        if(_data is not null)
        {
            Refresh(_data);
        }
    }

    private void Border_ContextMenuOpening(object sender, ContextMenuEventArgs e)
    {
        var menu = new ContextMenu();

        CustomiseMenu(menu);

        menu.IsOpen = true;

        e.Handled = true;
    }

    public void Refresh(DynamicDashboardData data)
    {
        _data = data;

        if (!DataComponent.TryGetTable(Properties.Table, out var _table) || Grid is null)
        {
            return;
        }

        if(data.TryGetData(Properties.Table, out var table))
        {
            Grid.Table = table;
        }
        else
        {
            Grid.Table.Rows.Clear();
        }
        Grid.Refresh(false, true);
    }

    public void Shutdown(CancelEventArgs? cancel)
    {
    }

    private class DataGridColumnSchema(DynamicDashboardGridPresenter presenter) : IDynamicGridColumnSchema
    {
        public IEnumerable<string> ColumnNames
        {
            get
            {
                if (presenter.DataComponent.TryGetTable(presenter.Properties.Table, out var table))
                {
                    return table.GetColumns(presenter.DataComponent).Where(x => EditorUtils.GetEditor(x.DataType) is not null).Select(x => x.ColumnName);
                }
                else
                {
                    return [];
                }
            }
        }

        public DynamicGridColumn GetColumn(string column)
        {
            var table = presenter.DataComponent.GetTable(presenter.Properties.Table);
            var coreCol = table.GetColumns(presenter.DataComponent).First(x => x.ColumnName == column);
            return DynamicGridColumn.FromCoreColumn(coreCol)!;
        }

        public string? GetComment(string column)
        {
            return null;
        }

        public bool IsVisible(string column)
        {
            return true;
        }
    }

    private class DataGrid(DynamicDashboardGridPresenter presenter) : CoreTableGrid
    {
        protected override void DoReconfigure(DynamicGridOptions options)
        {
            base.DoReconfigure(options);
            options.SelectColumns = true;
        }

        public override DynamicGridColumns GenerateColumns()
        {
            if(presenter.Properties.Columns is not null)
            {
                var columns = new DynamicGridColumns();
                columns.AddRange(presenter.Properties.Columns.Select(x => x.Copy()));
                return columns;
            }
            else
            {
                return base.GenerateColumns();
            }
        }

        protected override void LoadColumnsMenu(ContextMenu menu)
        {
            base.LoadColumnsMenu(menu);
            menu.AddSeparatorIfNeeded();
            presenter.CustomiseMenu(menu);
            menu.RemoveUnnecessarySeparators();
        }

        protected override void SaveColumns(DynamicGridColumns columns)
        {
            base.SaveColumns(columns);
            presenter.Properties.Columns = columns.Count > 0 ? columns : null;
        }

        protected override DynamicGridColumns LoadColumns()
        {
            return presenter.Properties.Columns ?? base.LoadColumns();
        }
    }
}
