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

public class Grabable : MonoBehaviour 
{
    protected Player _player;
    protected bool _grabbed = false;
    protected Collider _collider;
    private Camera _cam;

    [HideInInspector] public Rigidbody RigidBody;

    private List<Vector3> _storedPos = new List<Vector3>();
    private float _maxDistFromPHovering = 1.8f;


    protected float _releasedTime = 0;

    void Awake()
    {
        GetMyComponents();
        _collider.enabled = false;
    }

    public virtual void Setup(Vector3 force)
    {
        GetMyComponents();

        _collider.enabled = false;
        Invoke("EnableCollider", 0.4f);

        RigidBody.velocity = force;
        ApplyRandomRotation();
    }

    private void EnableCollider()
    {
        _collider.enabled = true;
    }

    private void GetMyComponents()
    {
        _player = FindObjectOfType<Player>();
        _collider = GetComponent<Collider>();
        _cam = Camera.main;
        RigidBody = GetComponent<Rigidbody>();
    }


    public virtual void Update()
    {
        if (Input.GetMouseButton(0) == false && _grabbed)
            Released();

        if (_grabbed)
            HoverLogic();
        else
        {
            if (_releasedTime + 1.4f < Time.time)
            {
                Physics.IgnoreCollision(_collider, _player.GetCollider(), false);
                _releasedTime -= 10000000;
            }
        }

    }

    void HoverLogic()
    {
        float range = Screen.width * 0.1f;

        Vector3 hoverScreenPos = _cam.WorldToScreenPoint(_player.GetHoverPoint());
        Vector3 mousePos = Input.mousePosition;

        hoverScreenPos.z = 0;
        mousePos.z = 0;

        Vector3 delta = mousePos - hoverScreenPos;
        Vector3 direction = delta.normalized;

        float distance = Vector3.Distance(mousePos, hoverScreenPos);

        float fromCenterPercentage = distance / range;
        fromCenterPercentage = Mathf.Clamp01(fromCenterPercentage);


        Vector3 Offset = new Vector3(
            Mathf.Clamp(delta.x / range, -1, 1),
            Mathf.Sin(Mathf.PI * 0.5f * (1f - fromCenterPercentage)),
            Mathf.Clamp(delta.y / range, -1, 1));


        //Debug.Log(Offset);

        Offset *= _maxDistFromPHovering;

        Offset.y *= 0.5f;

        //float rangeLerp = Mathf.Lerp(1f, 1.4f, Mathf.Pow(fromCenterPercentage, 2.0f));
        //Vector3 multiply = new Vector3(fromCenterPercentage, 1 - fromCenterPercentage, fromCenterPercentage) * rangeLerp * 2f;
        //Offset.Scale(multiply);

        transform.position = Vector3.Lerp(transform.position, _player.GetHoverPoint() + Vector3.up * 0.3f + Offset, Time.deltaTime * 8f);

        _storedPos.Insert(0, transform.position);
        if (_storedPos.Count > 11)
            _storedPos.RemoveAt(11);



        //Vector3 center = _player.GetHoverPoint();
        //Vector3 p = _cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Vector3.Distance(transform.position, _cam.transform.position)));
        //p.z = Mathf.Lerp(transform.position.z, _player.transform.position.z, Time.deltaTime * 10f);

        //p.y = Mathf.Max(p.y, 0.6f);

        //transform.position = Vector3.Lerp(transform.position, p, Time.deltaTime * 12f);

        //if (transform.position.y < 0.6f)
        //    transform.position = new Vector3(transform.position.x, 0.6f, transform.position.z);
    }

    public virtual void PickedUp()
    {
        _grabbed = true;
        Cursor.visible = false;
        _player.HoldingGrabable(this);
        _storedPos.Clear();

        RigidBody.useGravity = false;
        RigidBody.velocity = Vector3.zero;
        RigidBody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezePositionZ;

        Physics.IgnoreCollision(_collider, _player.GetCollider());
    }

    public virtual void Released()
    {
        _grabbed = false;
        Cursor.visible = true;

        _releasedTime = Time.time;

        _player.ReleasedPackage();

        RigidBody.isKinematic = false;

        RigidBody.useGravity = true;
        RigidBody.constraints = RigidbodyConstraints.None;
        RigidBody.velocity = GetReleasedVelocity();// MUST BE AFTER CONSTARINS CLEAR

        Physics.IgnoreCollision(_collider, _player.GetCollider());

        ApplyRandomRotation();
    }


    public Vector3 GetReleasedVelocity()
    {
        Vector3 averageDir = Vector3.zero;
        if (_storedPos.Count > 0)
        {
            for (int i = 2; i < _storedPos.Count - 1; i++)
                averageDir += _storedPos[i] - _storedPos[i + 1];

            averageDir /= _storedPos.Count;
        }

        var velocity = Vector3.ClampMagnitude(averageDir * 45, 30f);
        velocity.y = Mathf.Max(velocity.y, 1.5f);
        velocity.y *= 2f;

        return velocity;
    }

    void OnMouseDown()
    {
        Vector3 playerPos = _player.transform.position;
        playerPos.y = transform.position.y;

        float dist = Vector3.Distance(transform.position, playerPos);
        if (Vector3.Distance(transform.position, playerPos) < GameController._maxDistFromPGrab)
            PickedUp();
    }

    public virtual void DestroyMe()
    {
        if (_grabbed)
        {
            _player.ReleasedPackage();
            Cursor.visible = true;
        }

        Destroy(gameObject);
    }

    protected void ApplyRandomRotation()
    {
        RigidBody.angularVelocity = new Vector3(GetRandomPI(), GetRandomPI(), GetRandomPI()) * 3f;
    }

    private float GetRandomPI()
    {
        return Random.Range(Mathf.PI, -Mathf.PI);
    }
}
