using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour {

    public float walkSpeed = 0.5f;
    public float jumpForce= 10f;
    public int walkSpeedAnimation = 1;
    public int runSpeedFactorAnimation = 2;
    public float boostDuration = 2f;
    public float originalRunSpeed = 1f;

    private bool isStop = false;

    public float runSpeedFactor
    {
        get { return runSpeed; }
        set {
            runSpeed = value;
            StopCoroutine(Run());
            StartCoroutine(Run());
        }
    }

    private float runSpeed;

    private Vector3 movement;
    private Animator anim;                      
    private Rigidbody playerRigidbody;          
    private int floorMask;                      
    private float camRayLength = 100f;
    private bool grounded = true;
    private SpriteRenderer spriteRender;
    private bool runState = false;


    void Awake()
    {
        // Create a layer mask for the floor layer.
        floorMask = LayerMask.GetMask("Floor");

        // Set up references.
        playerRigidbody = GetComponent<Rigidbody>();
        anim = GetComponentInChildren<Animator>();
        spriteRender = GetComponentInChildren<SpriteRenderer>();
    }

   void Update()    
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, -Vector3.up,out hit, Mathf.Infinity, floorMask)){
                // Range  Grounded
                if (hit.distance > 0f && hit.distance < 0.55f )
                {
                    grounded = true;
                }else 
                {
                    grounded = false;
                }
                Debug.DrawLine(transform.position, hit.transform.position, Color.green);
        }
        else
        {
            grounded = false;
        }
     }


    void steps()
    {
        AkSoundEngine.PostEvent("Play_Steps", gameObject);
    }
    void FixedUpdate()
    {
        // Store the input axes.
        float horizontalControl;
        float verticalControl;
        //bool runState = Input.GetButton("Run");
        bool jumpState;

      
        // Store the input axes.
        horizontalControl = Input.GetAxisRaw("Horizontal");
        verticalControl = Input.GetAxisRaw("Vertical");
        //bool runState = Input.GetButton("Run");
        jumpState = Input.GetButtonDown("Jump") && grounded;

        // Turn the player to face the mouse cursor.
        //Turning();

        // Move the player around the scene.
        Move(horizontalControl, verticalControl, jumpState);

        //Jump
        Jump(jumpState);

    }


    
    IEnumerator Run( )
    {
        runState = true;
        yield return new WaitForSeconds(boostDuration);
        runState = false;
        runSpeed = originalRunSpeed;
    }

    void Move(float horizontal, float vertical, bool jumpState)
    {
        float runSpeedFactor = 1;
       
        if (runState)
        {
            runSpeedFactor = this.runSpeedFactor;
        }

        //Priority Direction
        /*if (horizontal != 0)
        {
            vertical = 0;
        }*/

        //resetPosition
        if (isStop)
        { 
            vertical = 0;
            horizontal = 0;
            playerRigidbody.velocity = new Vector3(0f,0f,0f);
        }
        else
        {
            // Set the movement vector based on the axis input.
            movement.Set(horizontal, 0f, vertical);

            //Rotation vector to point mouse
            movement = Quaternion.AngleAxis(transform.localEulerAngles.y, Vector3.up) * movement;

            // Normalise the movement vector and make it proportional to the speed per second.
            movement = movement.normalized * walkSpeed * runSpeedFactor * Time.deltaTime;

            // Move the player to it's current position plus the movement.
            playerRigidbody.MovePosition(transform.position + movement);
        }

        // Animate the player.
        Animating(horizontal, vertical, jumpState);

       

    }

    void Jump(bool jumpState)
    {
        if (jumpState && grounded)
        {
            playerRigidbody.velocity = (Vector3.up * 0);
            playerRigidbody.AddForce(Vector3.up * jumpForce + movement);

            //dash
            //playerRigidbody.MovePosition(transform.position + movement * 10 + transform.up * /*jumpForce * */Time.deltaTime);
        }
    }

    void Turning()
    {
        // Create a ray from the mouse cursor on screen in the direction of the camera.
        Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition);

        // Create a RaycastHit variable to store information about what was hit by the ray.
        RaycastHit floorHit;

        // Perform the raycast and if it hits something on the floor layer...
        if (Physics.Raycast(camRay, out floorHit, camRayLength, floorMask))
        {
            // Create a vector from the player to the point on the floor the raycast from the mouse hit.
            Vector3 playerToMouse = floorHit.point - transform.position;

            // Ensure the vector is entirely along the floor plane.
            playerToMouse.y = 0f;

            // Create a quaternion (rotation) based on looking down the vector from the player to the mouse.
            Quaternion newRotation = Quaternion.LookRotation(playerToMouse);

            // Set the player's rotation to this new rotation.
            playerRigidbody.MoveRotation(newRotation);

            Debug.DrawLine(Camera.main.transform.position, floorHit.transform.position, Color.green);
        }
    }

    void Animating(float horizontal, float vertical, bool jumpState)
    {
        bool isMoving = horizontal != 0f || vertical != 0f;
        bool isleft = horizontal > 0f && vertical == 0f;
        bool isRigth = horizontal < 0f && vertical == 0f;
        bool isDown = horizontal == 0f && vertical > 0f;
        bool isUP = horizontal == 0f && vertical < 0f;

        //Velocity
        if (runState)
        {
            anim.speed = walkSpeedAnimation * runSpeedFactorAnimation;     
        }
        else
        {
            anim.speed = walkSpeedAnimation;
        }
        
        //Side Orientation
        if (isRigth)
        {
            spriteRender.flipX = false;
        }
        if (isleft)
        {
            spriteRender.flipX = true;
        }

        anim.SetBool("Teleport", isStop);

        //Move
        anim.SetBool("Walk", isMoving);
        //Orientation
        anim.SetBool("Side", (isRigth || isleft));
        anim.SetBool("Down", isDown );
        anim.SetBool("Up", isUP);
    }

    public IEnumerator Die(Transform spawnPoint) {
        playerRigidbody.constraints = RigidbodyConstraints.FreezeAll;
        anim.SetBool("Died", true);
        yield return new WaitForSeconds(1f);
        transform.position = spawnPoint.position;
        playerRigidbody.constraints = RigidbodyConstraints.FreezeRotation;
        anim.SetBool("Died", false);
    }

    public void setStop(bool isStop)
    {
        this.isStop = isStop; 
    }


}
