using UnityEngine;
using System;

public class Vision : MonoBehaviour
{
    [Range(1,25)]
    [SerializeField] private float length = 10;
    [Range(1,90)]
    [SerializeField] private float angle_FOV = 45;
    [SerializeField] private LayerMask checkMask;
    [SerializeField] private Transform headFoward;
    [SerializeField] private Color gizmoColor = Color.red;
    [SerializeField] private Color gizmoColorFound = Color.green;
    private bool m_lookForPlayer = true;
    private bool m_foundPlayer = true; 
    public bool foundPlayer { get { return m_foundPlayer; } }
    public event Action onFoundPlayer;

    private BlackBoard m_blackboard;

    float GetAngle(Vector3 _headFoward ,Vector3 _agentPos, Vector3 _posPlayer)
    {
        Vector3 dif = _posPlayer - _agentPos;
        return Vector3.Angle(dif,_headFoward);
    }

    bool IsInAngle(Vector3 _headFoward ,Vector3 _agentPos, Vector3 _posPlayer)
    {
        return GetAngle(_headFoward , _agentPos, _posPlayer) < angle_FOV;
    }

    bool IsInRange(Vector3 _agentPos, Vector3 _posPlayer)
    {
        return Vector3.Distance(_agentPos, _posPlayer) < length;
    }

    bool IsInSight(Vector3 _headFoward ,Vector3 _agentPos, Vector3 _posPlayer)
    {
       if (!IsInRange(_agentPos, _posPlayer))
            return false;
        if (!IsInAngle(_headFoward, _agentPos, _posPlayer))
            return false;
        Vector3 pos = new Vector3(_agentPos.x , _posPlayer.y +1 ,_agentPos.z);
        Debug.DrawRay(pos, _agentPos - pos * length, Color.blue);
        if (!Physics.Raycast(pos, _agentPos - pos, length, checkMask))
            return false;
        
        
        return true;
    }

    public void SetLookForPlayer(bool _islooking)
    {
        m_lookForPlayer = _islooking;
    }

    void OnPlayerHideResponse()
    {
        SetLookForPlayer(false);
    }

    void OnPlayerVisibleResponse()
    {
        SetLookForPlayer(true);
    }
    
    // Start is called before the first frame update
    void Start()
    {
        m_blackboard = (BlackBoard)FindObjectOfType(typeof(BlackBoard));
        m_blackboard.onPlayerHide += OnPlayerHideResponse;
        m_blackboard.onPlayerVisible += OnPlayerVisibleResponse;
        if (headFoward == null)
            headFoward = transform;
    }
    // Update is called once per frame
    void Update()
    {
        if (!m_lookForPlayer)
            return;
        
        m_foundPlayer = IsInSight(headFoward.forward, transform.position, m_blackboard.playerPos);
        if (m_foundPlayer)
        {
            onFoundPlayer?.Invoke();
            m_lookForPlayer = false;
        }
    }

    private void OnDisable()
    {
        m_blackboard.onPlayerHide -= OnPlayerHideResponse;
        m_blackboard.onPlayerVisible -= OnPlayerVisibleResponse;
    }

    private void OnDestroy()
    {
        m_blackboard.onPlayerHide -= OnPlayerHideResponse;
        m_blackboard.onPlayerVisible -= OnPlayerVisibleResponse;
    }

    private void OnDrawGizmos()
    {
        float halfFOV = angle_FOV / 2.0f;
        Vector3 visionForward = headFoward==null? transform.forward : headFoward.forward;
        

        Quaternion leftRayRotation = Quaternion.AngleAxis(-halfFOV, Vector3.up);
        Quaternion rightRayRotation = Quaternion.AngleAxis(halfFOV, Vector3.up);
        Vector3 leftRayDirection = leftRayRotation * visionForward;
        Vector3 rightRayDirection = rightRayRotation * visionForward;
        if(m_lookForPlayer)
            Gizmos.color = m_foundPlayer? gizmoColorFound: gizmoColor;
        else
            Gizmos.color = Color.gray;
        Gizmos.DrawRay(transform.position, leftRayDirection * length);
        Gizmos.DrawRay(transform.position, rightRayDirection * length);
    }
}
