using System;
using System.Collections;
using System.Collections.Generic;
using System.Timers;
using UnityEngine;

public class TranslateAnim : MonoBehaviour {
    
/*     public AnimationCurve curve;
    /// <summary>
    /// 到达判断
    /// </summary>
    public float arrivedCheckDistance = 0.1f;
    
   /// <summary>
    /// 运动总时间（）无外力干扰下
    /// </summary>
    float m_AnimTime;

    /// <summary>
    /// 目标位置
    /// </summary>
    Vector3 m_TargetPos;

    /// <summary>
    /// 平均速度
    /// </summary>
    float m_AverageSpeed;

    /// <summary>
    /// 运动方向
    /// </summary>
    Vector3 m_AnimDir;*/

   /// <summary>
   /// 开始运动的时间
   /// </summary>
    float curAnimBeginTime;

    bool arrived = false;

    const float UseFixedDeltaTime = 1 / 60f;
    float originalFixedDeltaTime = 0.02f;


    private Rigidbody m_RigidBody;
    public bool isRigidBody
    {
        get { return m_RigidBody; }
        set
        {
            if (m_RigidBody != value)
            {
                if (value)
                {
                    m_RigidBody = gameObject.AddComponent<Rigidbody>();
                }
                else
                {
                    var rigid = m_RigidBody;
                    Destroy(rigid);
                    m_RigidBody = null;
                }
            }
        }
    }

    private void Awake()
    {
        m_RigidBody = GetComponent<Rigidbody>();
    }

    // Use this for initialization
    void Start () {
        arrived = true;

        originalFixedDeltaTime = Time.fixedDeltaTime;
        Time.fixedDeltaTime = UseFixedDeltaTime;
    }

    private void OnDestroy()
    {
        Time.fixedDeltaTime = originalFixedDeltaTime;
    }
    
/*    /// <summary>
    /// 在一定时间内移动到目标点
    /// </summary>
    /// <param name="targetPos"></param>
    /// <param name="time"></param>
    public void MoveTo(Vector3 targetPos,float time)
    {
        curAnimBeginTime = Time.realtimeSinceStartup;

        m_AnimTime = time;
        m_TargetPos = targetPos;
        m_AnimDir = targetPos - transform.position;
        m_AverageSpeed = m_AnimDir.magnitude / m_AnimTime;

        arrived = false;
    }*/

    /// <summary>
    /// 瞬时力的速度衰减
    /// </summary>
    //public float vAtten = 1;

    /// <summary>
    /// 物体质量
    /// </summary>
    float m = 1;

    List<Velocity> m_VelocityList = new List<Velocity>();
    public List<Velocity> velocityList => m_VelocityList;
    /// <summary>
    /// 增加一个瞬时力
    /// </summary>
    public void AddMomentaryForce(Force force)
    {
        float t = 1;
        float v = force.power / m * t;//f = ma  v = at

        Velocity newV = new Velocity(force.dir.normalized, v,force.atten);
        
        m_VelocityList.Add(newV);

        arrived = false;

        //GameDebug.Log($"AddMomentaryForce:{force.dir}");
    }

    public void AddVelValueForOneFrame(List<Velocity> forward, float f)
    {
        foreach (Velocity velocity in forward)
        {
            velocity.tempValue = f;
        }
    }
    
    public void ClearVelocity()
    {
        this.velocityList.Clear();
    }
/*    /// <summary>
    /// 获取与目标点的距离
    /// </summary>
    /// <param name="targetPos"></param>
    /// <returns></returns>
    float GetDistance(Vector3 targetPos)
    {
        return (targetPos - transform.position).magnitude;
    }

    float curAnimRealUseTime;

    /// <summary>
    /// 停止运动
    /// </summary>
    void Stop()
    {
        m_VelocityList.Clear();
        curAnimRealUseTime = Time.realtimeSinceStartup - curAnimBeginTime;
        arrived = true;
    }*/

/*    /// <summary>
    /// 获取向目标点运动的运动距离（每帧）
    /// </summary>
    /// <returns></returns>
    Vector3  GetMoveToTargetMoveVector()
    {
        float elapsedTime = Time.realtimeSinceStartup - curAnimBeginTime;
        float x = elapsedTime / m_AnimTime;

        if (x > 1 - step)
        {
            x = 1 - step;
        }
        //近似求导
        float x2 = x + step;// UseFixedDeltaTime / m_AnimTime;
        float y = this.curve.Evaluate(x);
        float y2 = this.curve.Evaluate(x2);

        var curAverageSpeed = GetDistance(this.m_TargetPos) / (m_AnimTime - elapsedTime);
        m_AverageSpeed = curAverageSpeed > m_AverageSpeed ? curAverageSpeed : m_AverageSpeed;

        float curSpeed = m_AverageSpeed * (y2 - y) / (x2 - x);
        // Debug.Log("x:"+ x+ " x2:"+ x2+ "  y:" + y + " y2: "+ y2+ "  curSpeed:" + curSpeed+ "   Time.fixedDeltaTime:" + Time.fixedDeltaTime);

        Vector3 dir = (m_TargetPos - transform.position).normalized;

        Vector3 moveToTarget = dir * curSpeed * Time.fixedDeltaTime;

        return moveToTarget;
    }*/

    Queue<Vector3> m_MomentaryMoveVec = new Queue<Vector3>();
    Queue<Vector3> GetForceMoveVector()
    {
        for (int i = 0; i < m_VelocityList.Count; i++)
        {
            Velocity velocity = m_VelocityList[i];
            
            Vector3 vMove = (velocity.v + velocity.tempValue)* velocity.dir;
            
            velocity.tempValue = 0;
            velocity.Atten();

            m_MomentaryMoveVec.Enqueue(vMove);
        }
        for (int i = 0; i < m_VelocityList.Count; )
        {
            Velocity velocity = m_VelocityList[i];
            if (velocity.v <= 0)
            {
                m_VelocityList.RemoveAt(i);
            }
            else
            {
                i++;
            }
        }
        return m_MomentaryMoveVec;
    }

    /// <summary>
    /// delta x
    /// </summary>
    public float step = 0.001f;

	// Update is called once per frame
	void FixedUpdate () {

        if (arrived)
            return;

        if (Time.fixedDeltaTime > UseFixedDeltaTime + 0.0001f)//避免误差
        {
            curAnimBeginTime = Time.realtimeSinceStartup;
            return;
        }

        /*if (moveToTarget)
        {///趋向目标点的运动
            Vector3 moveToTarget = GetMoveToTargetMoveVector();
            float distance = GetDistance(m_TargetPos);
            if (distance <= arrivedCheckDistance || distance <= moveToTarget.sqrMagnitude)
            {
                //到达停止
                transform.position = m_TargetPos;
                Stop();
                Debug.Log("arrived!  GetDistance(m_TargetPos):" + GetDistance(m_TargetPos));
                return;
            }
            transform.position += moveToTarget;
        }*/
        
        Vector3 vec = Vector3.zero;
        
        //瞬时力的运动
        var forceMove = GetForceMoveVector();  
        
        if (forceMove.Count == 0)
            return;
        
        //GameDebug.Log($"move force count:{forceMove.Count}");

        while (forceMove.Count > 0)
        {
            vec += forceMove.Dequeue();
        }

        if (isRigidBody)
        {
            if (vec.y > 0.00001f)
            {
                //GameDebug.Log($"translate move:{vec.y} > 0");
                this.m_RigidBody.velocity = vec;
            }
            else if (vec.y < -0.00001f)
            {
                vec.y += this.m_RigidBody.velocity.y;
                this.m_RigidBody.velocity = vec;
            }
            else
            {
                //GameDebug.Log($"translate move:vec.y == 0");
                vec.y = this.m_RigidBody.velocity.y;
                this.m_RigidBody.velocity = vec;
            }
        }
        else
        {
            transform.position += vec * Time.fixedDeltaTime;
        }
    }

}

public class Force
{
    public Vector3 dir;
    public float power;
    public float atten;
    public Force(Vector3 dir, float power)
    {
        this.dir = dir;
        this.power = power;
        this.atten = 1;
    }
    public Force(Vector3 dir, float power, float atten)
    {
        this.dir = dir;
        this.power = power;
        this.atten = atten;
    }
}

[System.Serializable]
public class Velocity
{
    public Vector3 dir;
    public float v;
    public float atten;
    
    private float m_OriginalV;
    public float originalV => m_OriginalV;

    public float tempValue { get; set; }

    public Velocity(Vector3 dir,float v)
    {
        this.dir = dir.normalized;
        this.v = v;
        this.atten = 1;
    }

    public Velocity(Vector3 dir, float v, float atten)
    {
        this.dir = dir;
        this.v = v;
        this.atten = atten;
        m_OriginalV = v;
    }

    public void Atten()
    {
        v -= atten;
    }
}