using IHandlers;
using Sirenix.OdinInspector;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

namespace mPS
{
    public class FlayerVelUnit : MonoBehaviour,IVelocity
    {
        [Header("控制信息"),ShowInInspector]
        private float timeRate = 1f;
        public float TimeRate
        {
            get { return timeRate; }
            set { timeRate = value; }
        }

        [Header("基础对象")]
        public Transform _phyTransform;
        public Rigidbody _phyRigidbody;
        public Collider _phyCollider;
        public float _phyMass = 3.0f;
        public float _refRadius = 0.15f;    //应该与胶囊体参考半径对齐
        [Header("速度影响参数")]
        public float _baseSpeedRate = 3f;
        public float _speedRate = 3f;
        public float _collideThershold = 90f;
        [Header("Y轴运动")]
        public bool enableGravity = false;
        public float gravity = -9.81f;
        [Header("四层速度")]
        public Vector3 _inputVelocity = Vector3.zero;
        public Vector3 _impulseVeclocity = Vector3.zero;
        public Vector3 _staticFieldVelocity = Vector3.zero;
        public Vector3 _dynamicFieldVelocity = Vector3.zero;
        public Vector3 _outputVelocity = Vector3.zero;
        [Header("主动速度影响参数")]
        public float _nowInputRate = 1f;

        [Header("冲量速度参数")]
        public float _defaultInhibitTime = 0.1f;
        public float _outerAddInhibitTime = 0f;
        public float _ImpulseDeclineRate = 2.8f;
        public float _defaultImpulse = 1f;

        

        [Header("物理互动回调")]
        public UnityEvent<Collision> OnCollide = new();

        #region Mono挂载部分
        public void VelAwake()
        {
            //if(this.TryGetComponent<DataUnit>(out DataUnit unit))
            //{
            //    _dataUnit = unit;
            //}
            _inputVelocity = Vector3.zero;
            _impulseVeclocity = Vector3.zero;
            _staticFieldVelocity = Vector3.zero;
            _dynamicFieldVelocity = Vector3.zero;
            _outputVelocity = Vector3.zero;

            //有关主动速度影响的初始化
            _nowInputRate = nowInputRateAdd = nowInputRateMul = 1f;
            inputDampSrcAdd.Clear();
            inputDampSrcMul.Clear();
            inputDampRateMul.Clear();
            inputDampRateAdd.Clear();
        }

        public void VelFixedUpdate()  //物理逻辑更新
        {
            //第一层 主动速度
            UpdateInputRate();
            //第二层 被动速度 冲量型速度
            UpdateImpulseVel();
            //第三层 被动速度 静态场速度

            //第四层 被动速度 动态场速度

            //速度合成
            UpdateVelocity();
            //移动触发事件
            DoMovingEvent();
        }

        protected void OnCollisionEnter(Collision collision)
        {
            EventImpulseCollide(collision);
        }
        #endregion

        #region 4层速度合成
        public virtual void UpdateVelocity()
        {
            _outputVelocity = _inputVelocity * _nowInputRate 
                + _impulseVeclocity 
                + _staticFieldVelocity 
                + _dynamicFieldVelocity;
            _phyRigidbody.velocity = _outputVelocity * timeRate;
            //Debug.Log("output vel is "+  _outputVelocity);

            //重置动态场速度
            _dynamicFieldVelocity = Vector3.zero;
        } 
        #endregion
        #region 速度更新-主动速度
        /// <summary>
        /// 用于设置主动速度的方向，设置速度大小请使用setSpeed，输入后自动归一化
        /// </summary>
        /// <param name="_inputVelocity"></param>
        /// <returns></returns>
        public void SetInputVelocity(Vector3 _velocity)
        {
            if (_velocity != Vector3.zero)
            {
                _inputVelocity = _velocity.normalized * _speedRate;
            }
            else
            {
                _inputVelocity = Vector3.zero;
            }
        }
        public void ResetInputVelocity() { _inputVelocity = Vector3.zero; }
        #region 有关主动速度影响的内容
        /// <summary>
        /// 用于设置该对象主动运动的基础速度，类型float
        /// </summary>
        /// <param name="_speed"></param>
        public void SetSpeed(float _speed)
        {
            if(_speed >= 0){_speedRate = _speed;}
            else { Debug.LogError("Not valid Speed for " + gameObject); }
        }
        public float GetSpeed()=>_speedRate;
        public float GetBaseSpeed()=>_baseSpeedRate;
        public void ResetSpeed() { _speedRate = _baseSpeedRate; }

        /// <summary>
        /// 用于更新有关速度速率影响的内容
        /// </summary>
        public void UpdateInputRate()
        {
            if(inputDampSrcAdd.Count == 0 && inputDampSrcMul.Count == 0)
            {
                _nowInputRate = 1f;
                return;
            }

            nowInputRateAdd = 1;
            //加法处理
            for(int i = inputDampSrcAdd.Count-1; i>=0; i--)
            {
                //移除已经无效的对象
                if (inputDampSrcAdd[i] && !inputDampSrcAdd[i].activeSelf)
                {
                    inputDampSrcAdd.RemoveAt(i);
                    inputDampRateAdd.RemoveAt(i);
                    continue;
                }

                nowInputRateAdd += inputDampRateAdd[i];
            }

            //乘法处理
            for (int i = inputDampSrcMul.Count - 1; i >= 0; i--)
            {
                //移除已经无效的对象
                if (inputDampSrcMul[i] && !inputDampSrcMul[i].activeSelf)
                {
                    inputDampSrcMul.RemoveAt(i);
                    inputDampRateMul.RemoveAt(i);
                    continue;
                }

                nowInputRateMul *= inputDampRateMul[i];
            }

            _nowInputRate = nowInputRateAdd * nowInputRateMul;
        }

        public virtual void SendInputRate(GameObject go, float targetRate, bool isAdd = true) //对主动速度的减速效果
        {
            if (isAdd)
            {
                if (inputDampSrcAdd.Contains(go))
                {
                    inputDampRateAdd[inputDampSrcAdd.IndexOf(go)] = targetRate;
                    return;
                }
                else
                {
                    inputDampSrcAdd.Add(go);
                    inputDampRateAdd.Add(targetRate);
                }
            }
            else
            {
                if (inputDampSrcMul.Contains(go))
                {
                    inputDampRateMul[inputDampSrcMul.IndexOf(go)] = targetRate;
                    return;
                }
                else
                {
                    inputDampSrcMul.Add(go);
                    inputDampRateMul.Add(targetRate);
                }
            }

        }
        public void RemoveInputRate(GameObject go)
        {
            int index;
            if (inputDampSrcAdd.Contains(go))
            {
                index = inputDampSrcAdd.IndexOf(go);
                inputDampSrcAdd.RemoveAt(index);
                inputDampRateAdd.RemoveAt(index);
            }
            else if (inputDampSrcMul.Contains(go))
            {
                index = inputDampSrcMul.IndexOf(go);
                inputDampSrcMul.RemoveAt(index);
                inputDampRateMul.RemoveAt(index);
            }
        }
        public List<GameObject> inputDampSrcAdd = new List<GameObject>();
        public List<float> inputDampRateAdd = new List<float>();
        public List<GameObject> inputDampSrcMul = new List<GameObject>();
        public List<float> inputDampRateMul = new List<float>();
        private float nowInputRateAdd,nowInputRateMul;
        #endregion
        #endregion
        #region 速度更新-冲量型速度
        /// <summary>
        /// 用于设置对象被单次冲击时的速度，独立叠加，一起衰减，
        /// </summary>
        /// <param name="_impulse">冲量-速度方向（输入后归一化）</param>
        /// <param name="_strength">冲量-速度大小</param>
        public void SetImpulseVelocity(Vector3 _impulse, float _strength)
        {
            if (_impulse == Vector3.zero) return;
            _impulseVeclocity += _impulse.normalized * _strength;
        }
        /// <summary>
        /// 直接叠加输入的_impulse
        /// </summary>
        /// <param name="_impulse"></param>
        public void SetImpulseVelocity(Vector3 _impulse)
        {
            _impulseVeclocity += _impulse;
        }
        public void SetImpulseVelocityOverWrite(Vector3 _impulse)
        {
            _impulseVeclocity = _impulse;
        }
        protected float _localImpulseTimel = 0;



        /// <summary>
        /// 用于设置对象 冲量速度衰减的抑制时间
        /// </summary>
        /// <param name="_inhibitTime"></param>
        /// <returns></returns>
        public void SetImpulseInhibitTime(float _inhibitTime)
        {
            _outerAddInhibitTime = _inhibitTime;
        }
        /// <summary>
        /// 刷新 冲量速度衰减抑制器
        /// </summary>
        public void FlushImpulseInhibition()
        {
            _localImpulseTimel = _defaultInhibitTime + _outerAddInhibitTime;
        }



        /// <summary>
        /// 更新冲量型速度衰减
        /// </summary>
        protected void UpdateImpulseVel()
        {
            float timeDelta = Time.fixedDeltaTime * timeRate;
            if (_localImpulseTimel > 0)            //冲量速度衰减抑制
            {
                _localImpulseTimel -= timeDelta;
                declineVel = _ImpulseDeclineRate * 0.00001f * timeDelta * _impulseVeclocity;
                _impulseVeclocity = declineVel.magnitude > _impulseVeclocity.magnitude ? Vector3.zero : _impulseVeclocity - declineVel;
                return;
            }
            //非抑制情况下 固定衰减量
            if (_impulseVeclocity.magnitude < 0.5f)
            {
                _impulseVeclocity = Vector3.zero;
            }
            else
            {
                declineVel = _ImpulseDeclineRate * timeDelta * _impulseVeclocity;
                _impulseVeclocity = declineVel.magnitude > _impulseVeclocity.magnitude ? Vector3.zero : _impulseVeclocity - declineVel;
            }
            //处理重力计算
            _impulseVeclocity.y += enableGravity ? gravity * timeDelta : 0;
        }
        protected Vector3 declineVel;     
        
        /// <summary>
        /// 碰撞时调用 用于计算碰撞结果
        /// </summary>
        protected void EventImpulseCollide(Collision collision)
        {
            _collision = collision;
            //安全措施
            if (collision == null || collision.contactCount == 0)
            {
                return;
            }
            _otherCollider = collision.gameObject;
            if (!_otherCollider.TryGetComponent<IVelocity>(out _otherIVel))
            {
                //Debug.Log("No IVel");
                return;
            }

            //准备计算信息
            _selfVelocity   = Vector3.Project(_outputVelocity, collision.impulse);              //获取己方在碰撞方向上的速度分量
            _otherVelocity  = Vector3.Project(_otherIVel.getOtherVelocity(), collision.impulse);//获取对方在碰撞方向上的速度分量
            _otherMass      = _otherIVel.getOtherMass();

            //碰撞条件
            if ((_impulseVeclocity.magnitude * _phyMass + _otherVelocity.magnitude * _otherMass) < _collideThershold) return;

            //先剔除自身的速度分量 然后计算分量结果加回
            _recordVelocity = _impulseVeclocity;

            _formerVelocity = _impulseVeclocity; //暂存 用来计算速度前后变化量
            _impulseVeclocity -= Vector3.Project(_outputVelocity, collision.impulse);
            _impulseVeclocity += ((_phyMass - _otherMass) 
                * _selfVelocity + 2 * _otherMass * _otherVelocity) / (_phyMass + _otherMass)
                * _defaultImpulse;

            //Debug.Log(
            //                        gameObject.name + " // " +
            //                        collision.impulse + " >> " + ((_phyMass - _otherMass) * _selfVelocity + 2 * _otherMass * _otherVelocity) / (_phyMass + _otherMass)
            //                        //* ((_dataUnit == null) ? _defaultImpulse : _dataUnit.impulseRt)
            //                        + " <> " + _impulseVeclocity
            //                        );
            //Debug.Log(_collision.gameObject.name + " // " + _otherMass);

            ////碰撞的伤害
            DoCollideDamage(_otherMass, _formerVelocity, _otherIVel.getOtherImpulseDamageRate());

            //后续添加参数来操作？敌人遍历和速度重导向
            DoCollideEvent(collision);
            DoCollideBuff();

            //如果免疫碰撞 则恢复速度
            //if (_dataUnit != null && _dataUnit.immuneCollide) _impulseVeclocity = _recordVelocity;

        }
        protected IVelocity _otherIVel;
        protected GameObject _otherCollider;
        protected Vector3 _selfVelocity, _otherVelocity,_formerVelocity,_recordVelocity;
        protected float _otherMass;
        protected Collision _collision;

        protected virtual void DoCollideDamage(float _otherMass, Vector3 _formerVelocity, float _otherImpulseDamage)
        {
            //免疫检测
            //if (_dataUnit != null && _dataUnit.immuneDamage) return;
            //碰撞的伤害
            //_otherMass = (_impulseVeclocity - _formerVelocity).magnitude;
            //if (_dataUnit != null
            //    && _otherMass > _dataUnit.impulseDamageThresholdRt
            //    )
            //{
            //    _dataUnit.AddHealth(-_otherMass * _dataUnit.impulseDamageRateRt * _otherImpulseDamage,ActType.Collision);
            //}
        }
        protected virtual void DoCollideEvent(Collision collision)
        {
            //这部分用于碰撞激活的事件 不影响碰撞
            //不同类型敌人可以改写这部分来实现不同的碰撞事件，对于武器球，碰撞的时候会通知其Agent来激活其技能系统

            OnCollide.Invoke(collision);
        }

        protected virtual void DoCollideBuff()
        {
            //这部分用于处理碰撞后有关碰撞结果的修改
            //
        }

        protected virtual void DoMovingEvent()
        {

        }
        #endregion
        #region 给外面用于获取信息
        public Collision GetCollision()
        {
            return _collision;
        }
        #endregion

        #region 速度更新-静态场速度
        public void SetWindHeat(Vector3 windHeat)
        {
            windHeat.y = 0;
            windHeat /= _phyMass;
            _staticFieldVelocity = windHeat;
        }

        public Vector3 getOtherVelocity()=> _outputVelocity;
        public float getOtherMass()=> _phyMass;
        
        //等房间数据完善后做这个
        #endregion
        #region 速度更新-动态场速度
        //等相关技能和对象管理模式实装后做这个
        /// <summary>
        /// 受到质量影响
        /// </summary>
        /// <param name="dynamicaVel"></param>
        public void Add_FieldVelocity(Vector3 dynamicaVel)
        {
            _dynamicFieldVelocity += dynamicaVel / _phyMass;
        }
        #endregion


    }

    public class InputDampSet
    {
        public GameObject mObj;
        public float Rate = 1f;
    }

    
}




