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

public class PlayerController : MonoBehaviour
{
	public float distance = 10.0f;


	float velocityY = 0.0f;
	const float gravity = 9.8f;

	public HookBehaviour hook;

	private Rigidbody rb;
	private CapsuleCollider col;
	private DistanceJoint3D joint;
	private bool isWired;

	private float movement;
	private Animator animator;


	[SerializeField]
	private Transform groundChecker;
	public LayerMask groundMask;
	private bool IsGrounded
	{
		get {
			RaycastHit hit;
			return Physics.SphereCast(transform.position, col.radius / 2, Vector3.down, out hit, col.bounds.extents.y + 0.5f, groundMask);
			//return Physics.Raycast(transform.position, Vector3.down, col.bounds.extents.y + 0.5f, groundMask);
			//return Physics.OverlapSphere(groundChecker.position, 0.1f, groundMask).Length > 0;
		}
	}

	public int MaxHealth { get; private set; }
	private int _health;
	public int Health {
		get
		{
			return _health;
		}
		private set
		{
			_health = value;
			IngameUIManager.inst.UpdatePlayerHealthUI(MaxHealth, _health);
		}
	}

	[SerializeField]
	private float outOfMapTimer = 10;

#if UNITY_EDITOR
    private void OnDrawGizmos()
    {
		Gizmos.color = Color.red;
        Gizmos.DrawLine(transform.position, Camera.main.transform.forward.normalized * 200);

		col = GetComponent<CapsuleCollider>();
		if (IsGrounded)
			Gizmos.color = Color.green;
		Gizmos.DrawSphere(transform.position + Vector3.down * (col.bounds.extents.y + 0.05f), 0.1f);
	}
#endif

    private void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        joint = GetComponent<DistanceJoint3D>();
        rb = GetComponent<Rigidbody>();
		col = GetComponent<CapsuleCollider>();

        movement = 0.0f;
        animator = GetComponentInChildren<Animator>();

		MaxHealth = Health = 100;
    }
    private void Update()
    {
        float vertical = Input.GetAxis("Vertical");
        float horizontal = Input.GetAxis("Horizontal");

        Animate(vertical, horizontal);

		RaycastHit hit;
		if (!hook.gameObject.activeSelf && Physics.Raycast(transform.position, Camera.main.transform.forward, out hit, 700))
		{
			IngameUIManager.inst.UpdateDistanceUI(Vector3.Distance(transform.position, hit.point));
		}
		else
			IngameUIManager.inst.UpdateDistanceUI(-1);

		if (Input.GetMouseButtonDown(1))
        {
            if (!hook.gameObject.activeSelf)
            {
                FireHook();
            }
            else
                ReturnHook();
        }
		
		if (IsGrounded)
		{
			//rb.velocity = Vector3.zero;
			transform.position += (horizontal * transform.right + vertical * transform.forward).normalized * 10.0f * Time.deltaTime;
			//rb.velocity = (horizontal * transform.right + vertical * transform.forward).normalized * 10.0f;
			if (Input.GetButtonDown("Jump"))
			{
				rb.velocity = (horizontal * transform.right + vertical * transform.forward).normalized * 5.0f;
				rb.velocity += new Vector3(0, 10 - rb.velocity.y, 0);
			}
		}
        else
        {
			if (joint.enabled)
				joint.moveDelta = (horizontal * transform.right + vertical * transform.forward).normalized * 30.0f;
			else
				rb.AddForce((horizontal * transform.right + vertical * transform.forward).normalized * 10.0f);
        }

		if (MapManager.inst.IsOutOfMapBounds(transform.position))
		{
			outOfMapTimer -= Time.deltaTime;
			if (outOfMapTimer <= 0)
				Health = 0;
		}
		else
			outOfMapTimer = 10;
		IngameUIManager.inst.UpdateOutOfMapWarningUI(outOfMapTimer);
	}

    private void LateUpdate()
    {
        IngameUIManager.inst.UpdateHeightText(transform.position.y);
        if (GameManager.inst.MaxHeight < transform.position.y)
        {
            IngameUIManager.inst.UpdateMaxHeightText(transform.position.y);
            GameManager.inst.MaxHeight = transform.position.y;
        }
    }

	private void FixedUpdate()
	{
		/*
		if (IsGrounded)
		{
			RaycastHit hit;
			Debug.Log(Physics.Raycast(transform.position, Vector3.down, out hit, groundMask));
			Debug.Log(Physics.gravity + " * " + hit.normal + " = " + Vector3.Dot(Physics.gravity, hit.normal));
			//Debug.Log(Physics.gravity + Physics.gravity * Vector3.Dot(Physics.gravity, hit.normal));
			rb.AddForce(Physics.gravity + Physics.gravity * Vector3.Dot(Physics.gravity, hit.normal));
		}
		*/
	}

	private void FireHook()
    {
        joint.enabled = false;
        hook.gameObject.SetActive(true);
        hook.transform.position = transform.position;
        hook.EnableHook(Camera.main.transform.forward.normalized * 200);
    }

    public void ReturnHook()
    {
        joint.enabled = false;
        hook.DisableHook();
        isWired = false;
        //rb.useGravity = true;
    }

    public void ActiveWire()
    {
        joint.enabled = true;
        joint.distance = Vector3.Distance(transform.position, hook.transform.position);
        isWired = true;
        //rb.useGravity = false;
    }

	public void GetDamaged(int damage)
	{
		Health = Mathf.Max(0, Health - damage);
		Camera.main.GetComponent<CameraController>().PlayHitEffect();
	}

    private void Animate(float vertical, float horizontal)
    {
        animator.SetBool("IsGrounded", IsGrounded);
        animator.SetFloat("Vertical", vertical, 0.05f, Time.deltaTime);
        animator.SetFloat("Horizontal", horizontal, 0.05f, Time.deltaTime);

        float currentMovement = vertical * vertical + horizontal * horizontal;
        if (currentMovement <= 0.0001f)
        {
            movement = Mathf.Lerp(movement, 0, 0.01f);
        } else
        {
            movement = Mathf.Lerp(movement, 1, 0.05f);
        }
        animator.SetFloat("Movement", movement);
        animator.SetBool("Connected", joint.enabled);
    }
}