using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Forms.VisualStyles;
using System.Windows.Threading;
using Machinations.Annotations;
using Machinations.FromFlash.graph;
using Machinations.FromFlash.machinations.model;
using Machinations.Log;
using Machinations.Status;

namespace Machinations.WPF
{
    /// <summary>
    /// Interaction logic for SimulationControl.xaml
    /// </summary>
    public partial class SimulationControl : INotifyPropertyChanged
    {
        //private int m_lastStep;
        //private int m_step;
        private StatusHandler m_statusHandler;
        private DispatcherTimer m_timer;
        private MachinationsGraph m_graph;
        public event PropertyChangedEventHandler PropertyChanged;
        private ActionLog m_lastSelected;
        private bool m_showAutomatic;
        private bool m_showInteractive = true;
        private bool m_showOnStart;
        private bool m_showPassive;
        
        private bool m_showPools = true;
        private bool m_showSources = true;
        private bool m_showConverters = true;
        private bool m_showOthers;
        private int m_jumpForward;

        public SimulationControl()
        {
            InitializeComponent();
            m_timer = new DispatcherTimer();
            m_timer.Tick += TimerOnTick;
        }

        public void Initialize(MachinationsGraph graph, PaintingCanvas paintingCanvas)
        {
            m_graph = graph;
            OnPropertyChanged(nameof(TimeMode));
            paintingCanvas.ModelClick += OnInterAction;
            m_graph.EndChanged += () =>
            {
                OnPropertyChanged(nameof(Ended));
                OnPropertyChanged(nameof(EndText));
            };
            Actions = CollectionViewSource.GetDefaultView(m_graph.Log.Actions);
            Actions.Filter = o =>
            {
                var l = (ActionLog) o;
                bool b;
                switch (l.Mode)
                {
                    case ActivationMode.Automatic:
                        b = m_showAutomatic;
                        break;
                    case ActivationMode.Interactive:
                        b = m_showInteractive;
                        break;
                    case ActivationMode.OnStart:
                        b = m_showOnStart;
                        break;
                    case ActivationMode.Passive:
                        b = m_showPassive;
                        break;
                    default:
                        throw new ArgumentException();
                }
                if (!b)
                    return false;
                switch (l.ElementClass)
                {

                    case NodeClass.Converter:
                        return m_showConverters;
                    case NodeClass.Pool:
                        return m_showPools;
                    case NodeClass.Source:
                        return m_showSources;
                    default:
                        return m_showOthers;
                }
            };
        }


        public TimeMode TimeMode
        {
            get
            {
                if (m_graph == null) return TimeMode.Asynchronous;
                return m_graph.TimeMode;
            }
            //set { m_timeMode = value; }
        }

        public int LastStep
        {
            get { return m_statusHandler != null ? m_statusHandler.LastRecord : 0; }
        }

        public DispatcherTimer Timer
        {
            get { return m_timer; }
            set { m_timer = value; }
        }

        public int Step
        {
            get { return m_graph?.Step ?? 0; }
            set
            {
                if ( m_graph.Step!= value)
                {
                    m_graph.Step = value;
                    m_graph.InhibitionChange = true;
                    m_statusHandler.RestoreStatus(m_graph.Step);
                    m_graph.Elements.ForEach(e =>
                    {
                        e.InhibitedChangeApply();
                        e.TurnPoolsApply();
                    });
                    m_graph.InhibitionChange = false;
                    SliderMoved();
                }
            }
        }

        public int JumpForward
        {
            get { return m_jumpForward; }
            set
            {
                if (m_jumpForward != value)
                {
                    m_jumpForward = value;
                    OnPropertyChanged(nameof(JumpForward));
                }
            }
        }

        public ILog Log
        {
            get { return m_graph?.Log; }
        }

        public ICollectionView Actions
        {
            get; private set;
        }

        public bool ShowAutomatic
        {
            get { return m_showAutomatic; }
            set
            {
                if (m_showAutomatic != value)
                {
                    m_showAutomatic = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowInteractive
        {
            get { return m_showInteractive; }
            set
            {
                if (m_showInteractive != value)
                {
                    m_showInteractive = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowOnStart
        {
            get { return m_showOnStart; }
            set
            {
                if (m_showOnStart != value)
                {
                    m_showOnStart = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowPassive
        {
            get { return m_showPassive; }
            set
            {
                if (m_showPassive != value)
                {
                    m_showPassive = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowPools
        {
            get { return m_showPools; }
            set {
                if (m_showPools != value)
                {
                    m_showPools = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowSources
        {
            get { return m_showSources; }
            set
            {
                if (m_showSources != value)
                {
                    m_showSources = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowConverters
        {
            get { return m_showConverters; }
            set
            {
                if (m_showConverters != value)
                {
                    m_showConverters = value;
                    ActionsRefresh();
                }
            }
        }

        public bool ShowOthers
        {
            get { return m_showOthers; }
            set
            {
                if (m_showOthers != value)
                {
                    m_showOthers = value;
                    ActionsRefresh();
                }
            }
        }

        private void ActionsRefresh()
        {
            Actions.Refresh();
            OnPropertyChanged(nameof(Actions));
        }

        public StatusHandler StatusHandler
        {
            get { return m_statusHandler; }
        }

        public bool Ended
        {
            get
            {
                return m_graph != null && m_graph.Ended ;
            }
        }

        public string EndText
        {
            get
            {
                return "Game Finished" + m_graph?.EndCondition;
            }
        }

        public bool CanRightClick
        {
            get { return Step != LastStep || m_graph?.CanSkipTurn == true; }
        }

        

        public void Start()
        {
            if (m_statusHandler == null)
            {
                m_statusHandler = new StatusHandler(m_graph);
                m_statusHandler.LastRecordChanged += () =>
                {
                    OnPropertyChanged(nameof(LastStep));
                    OnPropertyChanged(nameof(Step));
                };
            }
            Reset();
            
            if (TimeMode != TimeMode.TurnBased)
            {
                m_timer.Start();
            }
            else
            {
                Step = 0;
                //m_statusHandler.CreateStatus(m_step);
            }
        }

        public void Stop()
        {
            if (TimeMode != TimeMode.TurnBased)
            {
                m_timer.Stop();
            }
        }

        private void Reset()
        {
            //m_statusHandler = new StatusHandler(m_graph);
            JumpForward = 10;
            m_statusHandler.Reset();
            OnPropertyChanged(nameof(TimeMode));
            m_graph.Log.Reset();
            m_graph.Step = 0;
            SliderMoved();
            ActionsRefresh();
        }

        private void TimerOnTick(object sender, EventArgs eventArgs)
        {
            Tick();
        }

        private void Tick()
        {
            if (m_graph.Running && !m_graph.Ended)
            {
                //SetStepAccToSlider();
                m_graph.OneTurnWithoutUserActions();
                //m_lastStep++;
                //OnPropertyChanged(nameof(LastStep));
                //m_graph.Step++;
                //m_statusHandler.CreateStatus(Step);
                //SliderMoved();
            }
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private void OnRightButtonClick(object sender, RoutedEventArgs e)
        {
            if(TimeMode != TimeMode.TurnBased)return;
            if (Step == LastStep)
            {
                if(m_graph.CanSkipTurn)
                //m_statusHandler.CreateStatus(Step);
                    Tick();
            }
            else
            {
                Step++;
                //m_statusHandler.RestoreStatus(Step);
            }
            
            SliderMoved();
        }

        private void OnLeftButtonClick(object sender, RoutedEventArgs e)
        {
            if (TimeMode != TimeMode.TurnBased) return;
            if (Step > 0)
            {
                Step--;
                //m_statusHandler.RestoreStatus(Step);
                SliderMoved();
            }
        }

        private void SliderMoved()
        {
            OnPropertyChanged(nameof(Step));
            OnPropertyChanged(nameof(CanRightClick));
        }

        private void OnInterAction(MachinationsNode machinationsNode)
        {
            //m_graph.ActionsThisTurn += machinationsNode.Actions;
            SetStepAccToSlider();
            OnPropertyChanged(nameof(Log));
            //if (m_graph.ActionsThisTurn >= m_graph.ActionsPerTurn)
            //{
            //    Tick();
            //}
        }

        private void SetStepAccToSlider()
        {
            if (Step != LastStep)
            {
                //m_lastStep = Step;
                m_graph.ActionsThisTurn = 0;
                m_statusHandler.RemoveStatusesAfter(Step);
                m_graph.Log.DeleteFrom(Step);
            }
        }

        private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            m_lastSelected?.Select(false);
            ListView listView = (ListView)sender;
            m_lastSelected = (ActionLog)listView.SelectedItem;
            m_lastSelected?.Select(true);
            
        }

        private void JumpForwardClick(object sender, RoutedEventArgs e)
        {
            //Stopwatch sw = new Stopwatch();
            //sw.Start();
            m_graph.CanDoEvents = false;
            for (int i = 0; i < JumpForward; i++)
            {
                if(!CanRightClick)
                    break;
                OnRightButtonClick(sender,e);
            }
            m_graph.CanDoEvents = true;
            //sw.Stop();
            //var s = sw.Elapsed;
        }
    }
}
