using System;
using System.Collections;
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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using InABox.Wpf.Editors;
using Microsoft.Xaml.Behaviors.Core;

namespace InABox.DynamicGrid
{

    public class DynamicTabControlEventArgs : CancelEventArgs
    {
        public DynamicTabItem TabItem { get; set; }
    }    
    
    public class DynamicTabItemContextMenuEventArgs : CancelEventArgs
    {
        public ContextMenu Menu { get; set; }
    }

    public class DynamicTabItemRenamedEventArgs : CancelEventArgs
    {
        public String OldName { get; set; }
        public String NewName { get; set; }
    }

    public delegate void DynamicTabControlChangedEvent(object sender, EventArgs args);
    
    public delegate void DynamicTabControlCreateEvent(object sender, DynamicTabControlEventArgs args);
    
    public delegate void DynamicTabItemCloseEvent(object sender, DynamicTabControlEventArgs args);
    
    public delegate void DynamicTabItemContextMenuEvent(object sender, DynamicTabItemContextMenuEventArgs args);

    public delegate void DynamicTabItemRenamedEvent(object sender, DynamicTabItemRenamedEventArgs args);
    
    public class DynamicTabControl : TabControl
    {

        public event DynamicTabControlChangedEvent OnTabsChanged;
        
        public static readonly DependencyProperty ChangedCommandProperty =
            DependencyProperty.Register(nameof(ChangedCommand), typeof(ICommand), typeof(DynamicTabControl));

        public ICommand ChangedCommand
        {
            get { return base.GetValue(ChangedCommandProperty) as ICommand; }
            set { base.SetValue(ChangedCommandProperty, value); }
        }
        
        public event DynamicTabControlCreateEvent OnCreateTab;
        
        public static readonly DependencyProperty CreateTabCommandProperty =
            DependencyProperty.Register(nameof(CreateTabCommand), typeof(ICommand), typeof(DynamicTabControl));

        public ICommand CreateTabCommand
        {
            get { return base.GetValue(CreateTabCommandProperty) as ICommand; }
            set { base.SetValue(CreateTabCommandProperty, value); }
        }

        public static readonly DependencyProperty CanCreateTabProperty =
            DependencyProperty.Register(nameof(CanCreateTab), typeof(bool), typeof(DynamicTabControl), new PropertyMetadata(false));
        
        public bool CanCreateTab
        {
            get => (bool)GetValue(CanCreateTabProperty);
            set => SetValue(CanCreateTabProperty, value);
        }

        public DynamicTabItem? SelectedTab => (SelectedItem as DynamicTabItem)!;
        
        static DynamicTabControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DynamicTabControl), new FrameworkPropertyMetadata(typeof(DynamicTabControl)));
        }

        public DynamicTabControl() : base()
        {

            ChangedCommand = new ActionCommand(() => OnTabsChanged?.Invoke(this, new EventArgs()));
            
            CanCreateTab = false;
            CreateTabCommand = new ActionCommand(() =>
            {
                var args = new DynamicTabControlEventArgs() { TabItem = new DynamicTabItem() { Header = "New TabItem" }};
                OnCreateTab?.Invoke(this, args);
                if (args.Cancel == false)
                {
                    Items.Add(args.TabItem);
                    ChangedCommand.Execute(null);
                }
            });
        }
        
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new DynamicTabItem();
        }

        public static readonly DependencyProperty TabStripVisibleProperty =
            DependencyProperty.Register(nameof(TabStripVisible), typeof(bool), typeof(DynamicTabControl), new PropertyMetadata(true));

        public bool TabStripVisible
        {
            get => (bool)GetValue(TabStripVisibleProperty);
            set
            {
                SetValue(TabStripVisibleProperty, value);
                Style s = new Style();
                s.Setters.Add(new Setter(UIElement.VisibilityProperty, value ? Visibility.Visible : Visibility.Collapsed));
                ItemContainerStyle = s;
            }
        }
    }
    
    public class DynamicTabItem : TabItem
    {

        public event DynamicTabItemCloseEvent OnCloseTab;

        
        public static readonly DependencyProperty CloseTabCommandProperty =
            DependencyProperty.Register(nameof(CloseTabCommand), typeof(ICommand), typeof(DynamicTabItem));

        public ICommand CloseTabCommand
        {
            get { return base.GetValue(CloseTabCommandProperty) as ICommand; }
            set { base.SetValue(CloseTabCommandProperty, value); }
        }
        
        public static readonly DependencyProperty CanCloseProperty =
            DependencyProperty.Register(nameof(CanClose), typeof(bool), typeof(DynamicTabItem), new PropertyMetadata(false));
        
        public bool CanClose
        {
            get => (bool)GetValue(CanCloseProperty);
            set => SetValue(CanCloseProperty, value);
        }
        
        public event DynamicTabItemContextMenuEvent OnContextMenuOpening;

        public static readonly DependencyProperty ContextMenuCommandProperty =
            DependencyProperty.Register(nameof(ContextMenuCommand), typeof(ICommand), typeof(DynamicTabItem));

        public ICommand ContextMenuCommand
        {
            get { return base.GetValue(ContextMenuCommandProperty) as ICommand; }
            set { base.SetValue(ContextMenuCommandProperty, value); }
        }
        
        public static readonly DependencyProperty CanRenameProperty =
            DependencyProperty.Register(nameof(CanRename), typeof(bool), typeof(DynamicTabItem), new PropertyMetadata(false));
        
        public bool CanRename
        {
            get => (bool)GetValue(CanRenameProperty);
            set => SetValue(CanRenameProperty, value);
        }
        
        /// <summary>
        /// Called when a tab is renamed. Note that changing <see cref="DynamicTabItemRenamedEventArgs.NewName"/> will change the new name of the tab.
        /// </summary>
        public event DynamicTabItemRenamedEvent OnTabRenamed;
        
        static DynamicTabItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DynamicTabItem), new FrameworkPropertyMetadata(typeof(DynamicTabItem)));
        }

        public DynamicTabItem() : base()
        {
            Height = 25;
            CloseTabCommand = new ActionCommand(() =>
            {
                bool bConfirm = false;
                if (OnCloseTab != null)
                {
                    var args = new DynamicTabControlEventArgs() { TabItem = this };
                    OnCloseTab?.Invoke(this, args);
                    bConfirm = !args.Cancel;

                }
                else
                    bConfirm = MessageBox.Show("Are you sure you wish to close this tab?", "Close Tab", MessageBoxButton.YesNo) ==
                               MessageBoxResult.Yes;
                
                if (bConfirm)
                {
                    var parent = Parent as DynamicTabControl;
                    if (parent != null)
                    {
                        parent.Items.Remove(this);
                        parent.ChangedCommand.Execute(null);
                    }
                }
            });

            ContextMenuCommand = new ActionCommand(() =>
            {

                ContextMenu menu = new ContextMenu();
                if (CanRename)
                {
                    menu.Items.Add(new MenuItem()
                    {
                        Header = "Rename Tab", Command = new ActionCommand(() =>
                        {
                            String tabname = Header.ToString() ?? "";
                            if (TextEdit.Execute("Rename Tab", ref tabname))
                            {
                                var args = new DynamicTabItemRenamedEventArgs() { OldName = Header.ToString() ?? "", NewName = tabname };
                                OnTabRenamed?.Invoke(this, args);
                                Header = args.NewName;
                                var parent = Parent as DynamicTabControl;
                                if (parent != null)
                                    parent.ChangedCommand.Execute(null);
                            }
                        })
                    });
                }

                if (OnContextMenuOpening != null)
                {
                    var args = new DynamicTabItemContextMenuEventArgs { Menu = menu };
                    OnContextMenuOpening.Invoke(this, args);
                    if (args.Cancel == false)
                        args.Menu.IsOpen = true;
                }
                else
                    menu.IsOpen = CanRename;
            });

        }

    }
    

}
