using Unity.Mathematics;
using UnityEngine;

public class HaseBewegung : MonoBehaviour
{
    const float MAX_HINTERLAUF_ANGLE = 20;
    const float HINTERLAUF_TIME = .7f;
    public float jumpVelocityX;
    public float maxJumpVelocityY;
    public float waitingTimeBetweenJumps;
    public float earRigidity;
    public float maxEarAngularVelocity;
    public GameObject hinterlauf;
    public GameObject loeffel;
    public GameObject kopf;

    private float xTarget;
    private uint collisions;
    private float nextJumpTime;
    private bool lookingRight;
    private float jumpStartTime;
    private float lastEarAngle;

    private Rigidbody2D rigidBody;
    public void GoToXPosition(float x){
        xTarget = x;
        rigidBody.constraints = RigidbodyConstraints2D.FreezeRotation;
    }

    public void Turn(){
        GetComponent<SpriteRenderer>().flipX = lookingRight;
        loeffel.GetComponent<SpriteRenderer>().flipX = lookingRight;
        hinterlauf.GetComponent<SpriteRenderer>().flipX = lookingRight;
        kopf.GetComponent<SpriteRenderer>().flipX = lookingRight;
        lookingRight = !lookingRight;
        Vector3 v = loeffel.transform.localPosition;
        v.x = -v.x;
        loeffel.transform.localPosition = v;
        v = hinterlauf.transform.localPosition;
        v.x = -v.x;
        hinterlauf.transform.localPosition = v;
        v = kopf.transform.localPosition;
        v.x = -v.x;
        kopf.transform.localPosition = v;
        loeffel.transform.localRotation = Quaternion.Inverse(loeffel.transform.localRotation);
        hinterlauf.transform.localRotation = Quaternion.Inverse(hinterlauf.transform.localRotation);
        kopf.transform.localRotation = Quaternion.Inverse(kopf.transform.localRotation);
        transform.rotation = Quaternion.Inverse(transform.rotation);
    }

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        rigidBody = GetComponent<Rigidbody2D>();
        collisions = 0;
        lookingRight = true;
        nextJumpTime = 0f;
        jumpStartTime = 0;
        lastEarAngle = 0;
    }

    // Update is called once per frame
    void Update()
    {
        if (!targetReached()) {
            if (collisions > 0){
                if (Time.time > nextJumpTime){
                    StartJump();
                    nextJumpTime = 0;
                } else if (nextJumpTime == 0){
                    nextJumpTime = Time.time + waitingTimeBetweenJumps;
                    rigidBody.linearVelocityX = 0;
                }
            }
        } else {
            rigidBody.linearVelocityX = 0;
            rigidBody.linearVelocityY = math.min(rigidBody.linearVelocityY, 0f);
            rigidBody.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezeRotation;
        }
        float earAngle;
        if (rigidBody.linearVelocityX != 0){
            earAngle = math.acos(earRigidity / math.abs(rigidBody.linearVelocityX)) / math.PIHALF * 50;
            if (!lookingRight){
                earAngle *= -1;
            }
        } else {
            earAngle = 0;
        }
        if (math.abs(earAngle - lastEarAngle) / Time.deltaTime > maxEarAngularVelocity) {
            if (earAngle > lastEarAngle){
                earAngle = lastEarAngle + Time.deltaTime * maxEarAngularVelocity;
            } else {
                earAngle = lastEarAngle - Time.deltaTime * maxEarAngularVelocity;
            }
        }
        lastEarAngle = earAngle;
        loeffel.transform.localRotation = Quaternion.AngleAxis(earAngle, Vector3.forward);
        float timeFactor = (Time.time - jumpStartTime) / HINTERLAUF_TIME;
        Vector3 rotationAxis;
        if (lookingRight) {
            rotationAxis = Vector3.back;
        } else {
            rotationAxis = Vector3.forward;
        }
        if (timeFactor < .5f){
            hinterlauf.transform.localRotation = Quaternion.AngleAxis(MAX_HINTERLAUF_ANGLE * timeFactor * 2, rotationAxis);
        } else if (timeFactor < 1.0f){
            hinterlauf.transform.localRotation = Quaternion.AngleAxis(MAX_HINTERLAUF_ANGLE * (1 - timeFactor) * 2, rotationAxis);
        } else {
            hinterlauf.transform.localRotation = Quaternion.identity;
        }
    }

    void OnCollisionEnter2D(Collision2D collision){
        if (collision.gameObject.layer == 7){ //That layer is the ground.
            if (collisions == 0){
                rigidBody.linearVelocityX = 0;
            }
            collisions++;
        }
    }

    void OnCollisionExit2D(Collision2D collision){
        if (collision.gameObject.layer == 7){ //That layer is the ground.
            collisions--;
        }
    }

    private void StartJump(){
        if (lookingRight) {
            rigidBody.linearVelocityX = jumpVelocityX;
        } else {
            rigidBody.linearVelocityX = -jumpVelocityX;
        }
        rigidBody.linearVelocityY = maxJumpVelocityY;
        jumpStartTime = Time.time;
    }

    private bool targetReached(){
        return (lookingRight && transform.position.x >= xTarget) || (!lookingRight && transform.position.x <= xTarget);
    }
}
