using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using InABox.Configuration;
using InABox.Core;
using InABox.DynamicGrid;

namespace InABox.Wpf;

public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : MasterDetailPanel, IPanel<TMaster>
    where TMaster : Entity, IRemotable, IPersistent, new()
    where TMasterGrid : DynamicDataGrid<TMaster>, new()
    where TSettings : BaseObject, IUserConfigurationSettings, IMasterDetailSettings, new()
{
    
    private DispatcherTimer? timer;
    private readonly List<IMasterDetailPage<TMaster>> _pages = new();
    private DateTime _lastselection = DateTime.MaxValue;
    private int _currentPage = -1;
    private readonly TMasterGrid _masterGrid;
    private IDataModelSource? _modelsource;

    protected TSettings Settings { get; private set; } = new();

    private void LoadSettings()
    {
        Settings = new UserConfiguration<TSettings>().Load();
        _splitPanel.AnchorWidth = Settings.AnchorWidth;
        _splitPanel.View = Settings.ViewType;
        AfterLoadSettings(Settings);
    }
    
    protected void SaveSettings()
    {
        BeforeSaveSettings(Settings);
        Settings.AnchorWidth = _splitPanel.AnchorWidth;
        Settings.ViewType = _splitPanel.View;
        Settings.MasterID = _masterGrid.SelectedRows.FirstOrDefault()?.Get<TMaster, Guid>(x => x.ID) ?? Guid.Empty;
        new UserConfiguration<TSettings>().Save(Settings);
    }
    
    protected abstract void CreatePages();
    protected abstract void AfterLoadSettings(TSettings settings);
    protected abstract void BeforeSaveSettings(TSettings settings);
    protected abstract string MasterColumnsTag { get; }
    public virtual string SectionName => SelectedPage?.DataModelSource()?.SectionName ?? MasterColumnsTag;
    public virtual void CreateToolbarButtons(IPanelHost host)
    {
        SelectedPage?.CreateToolbarButtons(host);
    }
    
    protected override void DoSplitPanelChanged()
    {
        SaveSettings();
        var newTag = GetMasterColumnsTag();
        if (!String.Equals(_masterGrid.ColumnsTag, newTag))
        {
            _masterGrid.ColumnsTag = newTag;
            _masterGrid.Refresh(true, true);
        }
    }

    private string GetMasterColumnsTag()
    {
        var newTag = Settings.ViewType == DynamicSplitPanelView.Master
            ? $"{MasterColumnsTag}:Master"
            : $"{MasterColumnsTag}:Combined";
        return newTag;
    }

    protected MasterDetailPanel()
    {
        _masterGrid = new TMasterGrid();
        _masterGrid.OnSelectItem += MasterGrid_OnSelectItem;
        _masterGrid.BeforeRefresh += MasterGrid_BeforeRefresh;
        _masterGrid.AfterRefresh += MasterGrid_AfterRefresh;
    }

    public void Setup()
    {
        LoadSettings();
        
        _masterGrid.ColumnsTag = GetMasterColumnsTag();
        
        _splitPanel.Master = _masterGrid;
        _splitPanel.MasterCaption = MasterCaption;
        _splitPanel.DetailCaption = DetailCaption;

        _header.Content = MasterCaption;
        
        CreatePages();
        
        timer = new DispatcherTimer();
        timer.Tick += Timer_Tick;
        timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
        
    }
    
    protected TPage? CreatePage<TPage>(Func<bool> isAllowed, string caption) 
        where TPage : class, IMasterDetailPage<TMaster>
    {
        if (isAllowed())
        {
            var header = new DynamicTabItem() { Header = caption };
            _tabControl.Items.Add(header);
            if (Activator.CreateInstance(typeof(TPage), header) is TPage page)
            {
                _pages.Add(page);
                page.OnUpdateDataModel += Page_OnUpdateDataModel;
                return page;
            }
        }

        return null;
    }

    private void Page_OnUpdateDataModel(string section, DataModel model)
    {
        OnUpdateDataModel?.Invoke(section, model);
    }

    protected TPage? CreatePage<TPage>(string caption)
        where TPage : class, IMasterDetailPage<TMaster>
    {
        return CreatePage<TPage>(() => true, caption);
    }

    public void Shutdown(CancelEventArgs? cancel)
    {
        foreach(var page in _pages)
        {
            page.Shutdown(cancel);
            if (cancel?.Cancel == true) return;
        }
        if (timer != null)
            timer.IsEnabled = false;
    }
    
    public void Refresh()
    {
        _masterGrid.Refresh(timer?.IsEnabled == false, true);
        _lastselection = DateTime.MinValue;
        if (timer != null)
            timer.IsEnabled = true;
    }
    
    public DataModel DataModel(Selection selection)
    {
        if (_modelsource == null)
        {
            var row = _masterGrid.SelectedRows.FirstOrDefault();
            var filter = row != null
                ? new Filter<TMaster>(x => x.ID).IsEqualTo(row.Get<TMaster, Guid>(x => x.ID))
                : new Filter<TMaster>().None();
            return new AutoDataModel<TMaster>(filter);
        }

        return _modelsource.DataModel(selection);
    }

    public event DataModelUpdateEvent? OnUpdateDataModel;
    
    public bool IsReady { get; set; }
    
    protected IMasterDetailPage<TMaster>? SelectedPage => _pages.FirstOrDefault(x => x.Tab == _tabControl.SelectedTab);
    
    public Dictionary<string, object[]> Selected()
    {
        return SelectedPage != null
           ? SelectedPage.Selected()
           : new Dictionary<string, object[]> { { typeof(TMaster).EntityName(), _masterGrid.SelectedRows } };
    }

    public void Heartbeat(TimeSpan time)
    {
        SelectedPage?.Heartbeat(time);
    }
    
    protected override void DoPagesChanged()
    {
        _lastselection = DateTime.MinValue;
    }
    
    
    private void Timer_Tick(object? sender, EventArgs e)
    {
        if (_lastselection < DateTime.Now.AddMilliseconds(-500) && !_masterGridRefreshing)
        {
            _lastselection = DateTime.MaxValue;
            var master = _masterGrid.SelectedRows.FirstOrDefault()?.ToObject<TMaster>() ?? new TMaster();
            var dataModelSource = SelectedPage?.Refresh(master);
            if (_tabControl.SelectedIndex != _currentPage)
            {
                if(dataModelSource is not null)
                {
                    _modelsource = dataModelSource;
                    OnUpdateDataModel?.Invoke(dataModelSource.SectionName, dataModelSource.DataModel(Selection.None));
                }
                _currentPage = _tabControl.SelectedIndex;
            }
        }
    }
    
    private bool _masterGridRefreshing;

    private void MasterGrid_BeforeRefresh(object sender, BeforeRefreshEventArgs args)
    {
        _masterGridRefreshing = true;
    }

    private void MasterGrid_AfterRefresh(object sender, AfterRefreshEventArgs args)
    {

        _masterGrid.SelectedRows = Settings.MasterID == Guid.Empty
            ? Array.Empty<CoreRow>()
            : _masterGrid.Data.Rows.Where(r => r.Get<TMaster, Guid>(c => c.ID) == Settings.MasterID).ToArray();
        _masterGridRefreshing = false;
    }

    private void MasterGrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
    {
        if (!_masterGridRefreshing)
        {
            _lastselection = DateTime.Now;
            SaveSettings();
        }
    }
}

public abstract class MasterDetailPanel : UserControl
{
    protected DynamicSplitPanel _splitPanel;
    protected Label _header;
    protected DynamicTabControl _tabControl;

    protected abstract string MasterCaption { get; }
    protected abstract string DetailCaption { get; }

    
    protected MasterDetailPanel()
    {
        _splitPanel = new DynamicSplitPanel
        {
            View = DynamicSplitPanelView.Combined,
            AnchorWidth = 300,
            MasterCaption = MasterCaption,
            DetailCaption = DetailCaption
        };
        _splitPanel.OnChanged += SplitPanel_OnChanged;

        _header = new Label
        {
            HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center,
            VerticalContentAlignment = System.Windows.VerticalAlignment.Center,
        };

        _splitPanel.Header = new Border
        {
            BorderBrush = new SolidColorBrush(Colors.Gray),
            BorderThickness = new System.Windows.Thickness(0.75),
            Background = new SolidColorBrush(Colors.WhiteSmoke),
            Height = 25,
            Child = _header
        };

        _tabControl = new DynamicTabControl();
        Grid.SetColumn(_tabControl, 2);
        Grid.SetRow(_tabControl, 0);
        Grid.SetRowSpan(_tabControl, 2);
        _tabControl.SelectionChanged += Pages_OnChanged;
        _tabControl.SeparatorMargin = 4;
        _splitPanel.Detail = _tabControl;

        Content = _splitPanel;
    }

    protected abstract void DoSplitPanelChanged();
    
    private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
    {
        DoSplitPanelChanged();
    }

    protected abstract void DoPagesChanged();
    
    private void Pages_OnChanged(object sender, SelectionChangedEventArgs e)
    {
        if (Equals(e.Source, _tabControl))
            DoPagesChanged();
    }
}