using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using MrWu.Debug;

namespace GlobalSever.FSM
{
    /// <summary>
    /// 状态机
    /// </summary>
    public class FSM<T> where T : class
    {
        /// <summary>
        /// 所有状态 
        /// </summary>
        private readonly Dictionary<Type, FSMState<T>> m_States = new Dictionary<Type, FSMState<T>>();

        /// <summary>
        /// 状态切换事件
        /// </summary>
        public Action<FSM<T>, FSMState<T>> OnStateChanged;
        
        /// <summary>
        /// 状态准备切换事件 （延时的情况，还没有真正切换）
        /// </summary>
        public Action<FSM<T>, FSMState<T>> OnStatePreChanged;

        /// <summary>
        /// 状态机持有者
        /// </summary>
        public T Owner { get; private set; }

        /// <summary>
        /// 是否正在运行
        /// </summary>
        public bool IsRunning => CurrentState != null;

        /// <summary>
        /// 有限状态机是否被销毁
        /// </summary>
        public bool IsDestroyed { get; private set; }
        
        /// <summary>
        /// 状态机内存
        /// </summary>
        public FSMMem Mem { get; private set; }

        /// <summary>
        /// 上一个状态
        /// </summary>
        public FSMState<T> LastState { get; private set; }

        /// <summary>
        /// 当前状态机的状态
        /// </summary>
        public FSMState<T> CurrentState { get; private set; }
        /// <summary>
        /// 开启状态
        /// </summary>
        public FSMState<T> StartState { get; private set; }
        /// <summary>
        /// 结束状态
        /// </summary>
        public FSMState<T> EndState { get; private set; }

        public static FSM<T> Create(T owner, FSMMem mem, params FSMState<T>[] states)
        {
            if (owner == null)
            {
                throw new Exception("FSM owner is invalid.");
            }

            if (states == null || states.Length < 1)
            {
                throw new Exception("FSM states is invalid.");
            }
            
            FSM<T> fsm = new FSM<T>();
            fsm.Mem = mem;
            fsm.Owner = owner;
            fsm.IsDestroyed = false;

            for (int i = 0; i < states.Length; i++)
            {
                FSMState<T> state = states[i];
                if (state == null)
                {
                    throw new Exception("FSM states is invalid.");
                }
                
                Type stateType = state.StateType;
                if (fsm.m_States.ContainsKey(stateType))
                {
                    throw new Exception($"FSM state '{stateType}' is already exist.");
                }

                fsm.m_States.Add(stateType, state);
                if (i + 1 < states.Length)
                    state.NextState = states[i + 1];
                if (i - 1 >= 0)
                    state.LastState = states[i - 1];
                if (i == 0)
                    fsm.StartState = state;
                if (i == states.Length - 1)
                    fsm.EndState = state;
                state.OnInit(fsm);
            }
            
            return fsm;
        }

        /// <summary>
        /// 创建有限状态机
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="states"></param>
        public static FSM<T> Create(T owner, params FSMState<T>[] states)
        {
            return Create(owner, new FSMMem(), states);
        }
        
        /// <summary>
        /// 创建独立的状态机
        /// </summary>
        public void CreateSingle(FSMState<T> state)
        {
            if (state == null)
            {
                throw new Exception("FSM states is invalid.");
            }
                
            Type stateType = state.StateType;
            if (m_States.ContainsKey(stateType))
            {
                throw new Exception($"FSM state '{stateType}' is already exist.");
            }
            m_States.Add(stateType, state);
            state.OnInit(this);
        }

        /// <summary>
        /// 清理有限状态机
        /// </summary>
        public void Clear()
        {
            Stop();

            foreach (KeyValuePair<Type, FSMState<T>> state in m_States)
            {
                state.Value.OnDestroy(this);
            }

            Owner = null;
            m_States.Clear();
            IsDestroyed = true;
        }

        /// <summary>
        /// 默认从起始节点开始
        /// </summary>
        public void Start()
        {
            Start(StartState.StateType);
        }

        /// <summary>
        /// 从某个节点恢复
        /// </summary>
        public void Recover(int stateId)
        {
            foreach (var state in m_States)
            {
                if (state.Value.StateId == stateId)
                {
                    Start(state.Key);
                    break;
                }
            }
        }
        
        /// <summary>
        /// 通过内存恢复状态机
        /// </summary>
        public void Recover()
        {
            var state = GetState(Mem.NowStateId);
            Mem.NowStateType = state.StateType;
            Debug.Info($"[FSM] Recover Success. State = {Mem.NowStateType} Id = {Mem.NowStateId}");
            ReallyChangeState(Mem.NowStateType);
        }

        /// <summary>
        /// 开始有限状态机
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        public void Start<TState>() where TState : FSMState<T>
        {
            Start(typeof(TState));
        }

        /// <summary>
        /// 开始有限状态机
        /// </summary>
        /// <param name="stateType"></param>
        /// <exception cref="Exception"></exception>
        public void Start(Type stateType)
        {
            if (IsRunning)
            {
                throw new Exception("FSM is running, can not start again.");
            }

            if (stateType == null)
            {
                throw new Exception("State type is invalid.");
            }

            if (!typeof(FSMState<T>).IsAssignableFrom(stateType))
            {
                throw new Exception($"State type '{stateType}' is invalid.");
            }

            Debug.Info($"[FSM] Start Success. State = {stateType}");
            ReallyChangeState(stateType);
        }

        /// <summary>
         /// 是否存在有限状态机
         /// </summary>
         /// <typeparam name="TState"></typeparam>
         /// <returns></returns>
        public bool HasState<TState>() where TState : FSMState<T>
        {
            return m_States.ContainsKey(typeof(TState));
        }

         /// <summary>
         /// 是否存在有限状态机
         /// </summary>
         /// <param name="stateType"></param>
         /// <returns></returns>
         public bool HasState(Type stateType)
         {
             if (stateType == null)
             {
                 throw new Exception("State type is invalid.");
             }

             if (!typeof(FSMState<T>).IsAssignableFrom(stateType))
             {
                 throw new Exception($"State type '{stateType}' is invalid.");
             }

             return m_States.ContainsKey(stateType);
         }
         
         /// <summary>
         /// 获取有限状态机
         /// </summary>
         /// <typeparam name="TState"></typeparam>
         /// <returns></returns>
         public TState GetState<TState>() where TState : FSMState<T>
         {
             FSMState<T> state = null;
             if (m_States.TryGetValue(typeof(TState), out state))
             {
                 return (TState)state;
             }

             return null;
         }

         /// <summary>
         /// 获取有限状态机状态
         /// </summary>
         /// <param name="stateType"></param>
         /// <returns></returns>
         public FSMState<T> GetState(Type stateType)
         {
             if (stateType == null)
             {
                 throw new Exception("State type is invalid.");
             }

             if (!typeof(FSMState<T>).IsAssignableFrom(stateType))
             {
                 throw new Exception($"State type '{stateType}' is invalid.");
             }

             FSMState<T> state = null;

             if (m_States.TryGetValue(stateType,out state))
             {
                 return state;
             }

             return null;
         }
         
         public FSMState<T> GetState(int stateId)
         {
             foreach (var s in m_States)
             {
                 if (s.Value.StateId == stateId)
                     return s.Value;
             }
             
             throw new Exception($"State Id '{stateId}' is invalid.");
         }

         /// <summary>
         /// 有限状态机更新
         /// </summary>
         /// <param name="interval">与上次更新的时间间隔</param>
         public void Update(int interval)
         {
             //更新持续时间
             if (!IsRunning)
             {
                 return;
             }

             Mem.RunDuratime += interval;
             CurrentState.RunDuratime += interval;
             CurrentState.Update(this,interval);
             if (Mem.NeedChange && Mem.RunDuratime - Mem.LastUpdateTime >= Mem.NowChangeDelayTime)
             {
                 Mem.NowChangeDelayTime = 0;
                 Mem.NeedChange = false;
                 // Debug.Info($"[FSM] Start State = {Mem.NowStateType}");
                 ReallyChangeState(Mem.NowStateType);
             }
         }

         /// <summary>
         /// 关闭有限状态机
         /// </summary>
         public void ShutDown()
         {
             Clear();
         }

         public void Stop()
         {
             if (CurrentState != null)
             {
                 CurrentState.OnLeave(this);
             }
             CurrentState = null;
             Mem.NowStateId = -1;
             Mem.NowStateType = null;
             Mem.NeedChange = false;
         }
         
         public void ChangeStateImmediate<K>() where K : FSMState<T>
         {
             Mem.NowStateType = typeof(K);
             Mem.NeedChange = false;
             ReallyChangeState(Mem.NowStateType);
             
             Debug.Info($"[FSM] Change State Immediate = {Mem.NowStateType}");
         }

         public void ChangeState<K>() where K : FSMState<T>
         {
             ChangeState(typeof(K));
         }

         /// <summary>
         /// 切换当前有限状态机状态
         /// </summary>
         /// <param name="stateType">目标状态</param>
         public void ChangeState(Type stateType, int delayTime = 0)
         {
             if (!IsRunning)
             {
                 throw new Exception("Current state is invalid.");
             }

             
             Debug.Info($"[FSM] Change State = {stateType} Delay = {delayTime}");

             Mem.NowStateType = stateType;
             Mem.NowStateId = GetState(stateType).StateId;
             Mem.NeedChange = true;
             Mem.NowChangeDelayTime = delayTime;
             Mem.LastUpdateTime = Mem.RunDuratime;
         }

         void ReallyChangeState(Type stateType)
         {
             FSMState<T> state = GetState(stateType);

             if (state == null)
             {
                 throw new Exception($"FSM  can not change state to '{stateType}' which is not exist.");
             }

             if (CurrentState != null)
             {
                CurrentState.OnLeave(this);
                LastState = CurrentState;
             }
             CurrentState = state;
             Mem.NowStateId = CurrentState.StateId;
             Mem.NowStateType = CurrentState.StateType;
             OnStateChanged?.Invoke(this, CurrentState);
             CurrentState.OnEnter(this);
         }
    }
}