using System;
using UnityEngine;
using Rewired;

public class PlayerController : MonoBehaviour
{
    private Rewired.Player player;

    public float jumpForce = 100f;
    public float moveForce = 100f;          // Amount of force added to move the player left and right.
    public float maxSpeed = 5f;             // The fastest the player can travel in the x axis.

    public Collider2D groundCheck;

    public Animator animUpperbody;
    public Animator animLowerbody;

    private PlayerJetpack jetpack;
    private WeaponHolder weaponHolder;
    private Rigidbody2D rigidBody;

    private float turnInputValue;
    private float aimInputVerticalValue;
    private float aimInputHorizontalValue;

    private bool facingRight;

    private bool jump;
    private bool fire1;
    private bool fire2;
    private bool grounded;

    private float angle;

    private float aimAngle;

    public int PlayerId 
    {
        get 
        {
            if (player != null)
                return player.id;
            else
                return -1;
        }
    }

    public void Init(int playerId) 
    {
        player = ReInput.players.GetPlayer(playerId);
    }

    public void Die() 
    {
        if (player != null) 
        {
            foreach (var joystick in player.controllers.Joysticks) 
            {
                if (joystick.supportsVibration) 
                {
                    joystick.SetVibration(1f, 1f, 2f, 2f);
                }
            }
        }
    }

    public void TakeDamage() 
    {
        if (player != null) 
        {
            foreach (var joystick in player.controllers.Joysticks) 
            {
                if (joystick.supportsVibration) 
                {
                    joystick.SetVibration(0.5f, 0.5f, 0.5f, 0.5f);
                }
            }
        }
    }

    private void Awake()
    {
        rigidBody = GetComponent<Rigidbody2D>();
        jetpack = GetComponent<PlayerJetpack>();
        weaponHolder = GetComponent<WeaponHolder>();

        facingRight = false;
        jump = false;
        fire1 = false;
        fire2 = false;
        grounded = true;
        angle = 45;
    }

    private void OnEnable()
    {
        rigidBody.isKinematic = false;
        turnInputValue = 0f;
    }

    private void OnDisable()
    {
        // When the player is turned off, set it to kinematic so it stops moving.
        rigidBody.isKinematic = true;
    }

    private void Start()
    {
    }

    private void Update()
    {
        if (player != null) 
        {
            turnInputValue = player.GetAxis("Horizontal1");
            aimInputHorizontalValue = player.GetAxis("Horizontal2");
            aimInputVerticalValue = player.GetAxis("Vertical2");

            Aim();

            if (player.GetButtonDown("Jump") && grounded)
            {
                jump = true;
            }

            if (player.GetButtonDown("Fire1"))
            {
                fire1 = true;
            }
            if (player.GetButtonDown("Fire2"))
            {
                fire2 = true;
            }

            if (player.GetButtonDown("Menu"))
            {
                FindObjectOfType<SceneController>().FadeAndLoadScene("Menu");
            }

            jetpack.setJetpacking(player.GetButton("Jetpack"));
        }
    }

    private void CheckGrounded()
    {
        // The player is grounded if a linecast to the groundcheck position hits anything on the ground layer.
        //        grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));

        //        Collider2D c = GetComponentInChildren<CircleCollider2D>();
        //        grounded = groundCheck.IsTouchingLayers(1 << LayerMask.NameToLayer("Ground"));
        grounded = groundCheck.IsTouchingLayers(LayerMask.GetMask("Ground", "Destructable"));
        animLowerbody.SetBool("Grounded", grounded);
        animUpperbody.SetBool("Grounded", grounded);
    }

    private void FixedUpdate()
    {
        CheckGrounded();
        Move();
        if (jump) Jump();
        if (fire1) Fire1();
        if (fire2) Fire2();
    }

    private void Aim()
    {
        var deadzone = 0.25f;
        var stickInput = new Vector2(aimInputHorizontalValue, aimInputVerticalValue);

        if (stickInput.magnitude < deadzone)
            stickInput = Vector2.zero;
        else
            stickInput = stickInput.normalized * ((stickInput.magnitude - deadzone) / (1 - deadzone));

        if (stickInput != Vector2.zero)
        {
            float angle = Mathf.Atan2(stickInput.y, stickInput.x) * Mathf.Rad2Deg;
//            Debug.Log("Stick Input Y: " + stickInput.y);
//            Debug.Log("Stick Input X: " + stickInput.x);

            float angle90 = angle;
            if (angle90 > 90.0f)
                angle90 = 180.0f - angle90;
            if (angle90 < -90.0f)
                angle90 = -(180.0f + angle90);

            if (facingRight)
            {
                weaponHolder.AimAngle = -angle90;
                animUpperbody.SetFloat("Angle", angle90);
            }
            else
            {
                weaponHolder.AimAngle = angle90;
                animUpperbody.SetFloat("Angle", angle90);
            }

            if (angle >= -90.0f && angle < 90.0f && !facingRight)
            {
                TurnRight();
            }
            else if ((angle >= 90.0f || angle < -90.0f) && facingRight)
            {
                TurnLeft();
            }
        }
    }

    private void Move()
    {
        float h = turnInputValue;
        animLowerbody.SetFloat("Speed", Mathf.Abs(h));
        animUpperbody.SetFloat("Speed", Mathf.Abs(h));

        if (h * rigidBody.velocity.x < maxSpeed)
            rigidBody.AddForce(Vector2.right * h * moveForce);
        if (Mathf.Abs(rigidBody.velocity.x) > maxSpeed)
            rigidBody.velocity = new Vector2(Mathf.Sign(rigidBody.velocity.x) * maxSpeed, rigidBody.velocity.y);
    }

    private void Fire1()
    {
        animUpperbody.SetTrigger("Fire");
        weaponHolder.FirePrimary();
        fire1 = false;
    }
    private void Fire2()
    {
        animUpperbody.SetBool("Throwing", true);
        weaponHolder.FireSecondary();
        fire2 = false;
    }

    private void Jump()
    {
        rigidBody.AddForce(new Vector2(0f, jumpForce));
        animLowerbody.SetTrigger("Jumping");
        jump = false;
    }

    void TurnLeft()
    {
        facingRight = false;

        Vector3 theScale = transform.localScale;
        theScale.x = 1;
        transform.localScale = theScale;
    }

    void TurnRight()
    {
        facingRight = true;

        Vector3 theScale = transform.localScale;
        theScale.x = -1;
        transform.localScale = theScale;
    }
}
