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

public class PointOfEffectController : MonoBehaviour {

    #region public properties

    [SerializeField]
    Camera mainCamera;

    [SerializeField]
    GameObject table;

    [SerializeField]
    ArmController arm;

    [SerializeField]
    float _speed;


    [SerializeField]
    float _smootDstRadius;

    [SerializeField]
    float _attachedSpeed;

    [SerializeField]
    bool _usable = true;

    [SerializeField]
    bool _canGrip = true;

    [SerializeField]
    bool _isSuperGrip = false;

    [SerializeField]
    float MalusTime;

    #endregion

    #region private properties

    float _radius;
    Vector2 _TableExtents;
    List<GameObject> _foodsGripped = new List<GameObject>();
     

    #endregion

    #region SetUp
    private void Start()
    {
        _radius = GetComponent<CircleCollider2D>().radius;
        _TableExtents = table.GetComponent<SpriteRenderer>().bounds.extents;
        arm._OnArmHit += _onArmHit;
    }

    #endregion

    #region API

    public void FixedUpdate()
    {
        if (_foodsGripped.Count > 0)
        {
            int length = _foodsGripped.Count;
            for (int i = 0; i < length; i++)
            {
                if (_foodsGripped[i] != null)
                {
                    _foodsGripped[i].GetComponent<FoodController>().
                   UpdatePhysics(transform.GetChild(0).position, _attachedSpeed);
                }
            }
           
        }
    }

    public void ReleaseFood(GameObject food)
    {
        try
        {
            if (_foodsGripped.Count != 0)
            {
                int index = _foodsGripped.FindIndex(
                        x => x.transform.parent.GetComponent<Food>().id == food.transform.parent.GetComponent<Food>().id);
                _foodsGripped.RemoveAt(index);
                if (_foodsGripped.Count == 0)
                    food.GetComponent<FoodController>().currentGriper = null;
            }
        }
        catch (Exception E)
        {
            ReleaseAllFood();
        }
    }

    public void ReleaseAllFood()
    {
        try
        {
            if (_foodsGripped.Count > 0)
            {
                _foodsGripped.ForEach(item => {
                    item.GetComponent<FoodController>().currentGriper = null;
                });

                
            }
        }
        catch (Exception E)
        {

        }
        finally
        {
            _foodsGripped.Clear();
        }
        
    }

    public void Update()
    {
#if UNITY_EDITOR
        Cursor.visible = false;
        if (_usable && mainCamera)
            SetPosition(mainCamera.ScreenToWorldPoint(Input.mousePosition));
#endif

        if (_foodsGripped.Count > 0)
        {
            List<GameObject> toClear = new List<GameObject>();

            _foodsGripped.ForEach(item =>
            {
                if (item != null)
                {
                    float sqrdist = (item.transform.position - transform.GetChild(0).position).sqrMagnitude;
                    float radius = GetComponent<CircleCollider2D>().radius;
                    if (sqrdist > radius * radius * _smootDstRadius)
                        toClear.Add(item);
                }
            });

            toClear.ForEach(item =>
            {
                item.GetComponent<FoodController>().currentGriper = null;
                int index = _foodsGripped.FindIndex(
                    x => x.transform.parent.GetComponent<Food>().id == item.transform.parent.GetComponent<Food>().id);
                _foodsGripped.RemoveAt(index);
            });
        }
    }

    public void SetPosition(Vector2 target)
    {
        target = CheckBorders(target);
        transform.position = Vector2.Lerp(transform.position, target, Time.deltaTime * _speed);
    }

    public void SetMalus()
    {
        _canGrip = false;
        GetComponent<SpriteRenderer>().color = new Color(0,0.7f,0.2f);
        Invoke("ResetGrippable", MalusTime);
    }

    public void SetSuperGrip()
    {
        _isSuperGrip = true;
        GetComponent<SpriteRenderer>().color = Color.yellow;
        Invoke("ResetSuperGrip", MalusTime);
    }

    #endregion

    #region Private Methods

    private void ResetGrippable()
    {
        GetComponent<SpriteRenderer>().color = Color.white;
        _canGrip = true;
    }

    private void ResetSuperGrip()
    {
        ReleaseAllFood();
       GetComponent<SpriteRenderer>().color = Color.white;
       _isSuperGrip = false;
        
    }

    Vector2 CheckBorders(Vector2 center)
    {
        if (Mathf.Abs(center.x) + _radius >= _TableExtents.x)
        {
            center.x = _TableExtents.x * Mathf.Sign(center.x);
            center.x -= _radius/4 * Mathf.Sign(center.x);
        }

        if (Mathf.Abs(center.y) + _radius >= _TableExtents.y)
        {
            center.y = _TableExtents.y * Mathf.Sign(center.y);
            center.y -= _radius / 4 * Mathf.Sign(center.y);
        }

        return center;
    }

    private void _onArmHit(Vector2 relativeVelocity)
    {
        //if (!_foodGripped) return;
        //_foodGripped = null;
        //_foodGripped.GetComponent<Rigidbody2D>().velocity = relativeVelocity;
    }

    #endregion

    #region Collision

    public void OnTriggerEnter2D(Collider2D collision)
    {
        if (!_canGrip) return;

        if (collision.gameObject.CompareTag("food") && (_foodsGripped.Count <= 0 || _isSuperGrip))
        {
            GameObject oldGriper = collision.gameObject.GetComponent<FoodController>().currentGriper;
            if (oldGriper != null)
                oldGriper.GetComponent<PointOfEffectController>().ReleaseFood(collision.gameObject);

            _foodsGripped.Add(collision.gameObject);
            collision.gameObject.GetComponent<FoodController>().currentGriper = gameObject;
        }

       
    }

    
    #endregion

    public bool HasGrippedThatFood(GameObject food)
    {
        try
        {
            int index = _foodsGripped.FindIndex(
                       x => x.transform.parent.GetComponent<Food>().id == food.transform.parent.GetComponent<Food>().id);

            return index > -1;
        }
        catch(Exception e)
        {
            ReleaseAllFood();
            return false;
        }
    }
}
