using System.Collections;
using UnityEngine;
using Photon.Pun;

public class ForwardRocketScript : MonoBehaviourPunCallbacks, ISpawnable
{
    [Header("Settings")]
    [SerializeField] [Range(1, 10)] float m_lifetime = 5;
    [SerializeField] [Range(1, 2)] float m_speed = 1;
	[SerializeField] LayerMask m_wallMask, m_trackMask;
    [SerializeField] bool m_rocketOwnerProtected = true;

    [Header("Explosion Prefab")]
	[SerializeField] GameObject m_explosionPrefab;

	Vector3 m_velocity = Vector3.zero;

    [Header("Debug")]
    [SerializeField] DebugChannelSO m_debugChannel;

    // READABLES //
    #region
    public RacerCore Owner { get; private set; }
    public bool CanTargetOwner { get; private set; }
    #endregion
    
    // DEFAULT METHODS //
    #region
    void Start()
    {
        if (m_debugChannel)
            m_debugChannel.Raise(this, "Rocket start!");

        m_rocketOwnerProtected = true;

        StartCoroutine(DelayActivation());
    }
    void FixedUpdate()
    {
        MoveRocket();
        UpdateLifetime();
    }
    void OnTriggerEnter (Collider col)
    {
        // Get a player from the collision
        RacerCore _rc = col.GetComponent<RacerCore>();

        // If we didn't get one, return
        if (!_rc)
            return;

        // If this is a network instance, return
        if (!_rc.IsLocal)
            return;

        // If the item has an owner and we just hit that owner...
        if (Owner != null && _rc == Owner)
        {
            // If we are unable to target our owner, return
            if (!CanTargetOwner)
                return;

            // If the owner is still protected, return
            if (m_rocketOwnerProtected)
                return;
        }

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Boom!");

        // Hit the racer
        _rc.Motor.Hit();

        // Go boom!
        Boom();
	}
    private void OnDrawGizmos()
    {
		Gizmos.color = Color.blue;
		Gizmos.DrawLine(transform.position, transform.position + transform.forward);
	}
    #endregion

    // MOVEMENT METHODS //
    #region
    private void MoveRocket()
    {
        RaycastHit _hit;
        
        if (Physics.Raycast(transform.position, transform.forward, out _hit, m_speed, m_wallMask))
        {
            transform.position = _hit.point - transform.forward * GetComponent<Collider>().bounds.extents.magnitude;
            transform.forward = Vector3.Reflect(transform.forward, _hit.normal);
            Debug.DrawLine(_hit.point, _hit.point + _hit.normal);
        }
        else
            transform.position += transform.forward * m_speed;

        Vector3 _right = -transform.right;
        
        if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 1f, transform.position.z), -transform.up, out _hit, Mathf.Infinity, m_trackMask))
        {
            if (Vector3.Angle(transform.up, _hit.normal) < 45)
            {
                transform.up = _hit.normal;
                transform.position = _hit.point + transform.up;
            }
        }

        transform.forward = Vector3.Cross(transform.up, _right);
    }
    #endregion

    // LIFETIME METHODS //
    #region
    private void UpdateLifetime()
    {
        if (PhotonNetwork.IsConnected && !photonView.IsMine)
            return;

        m_lifetime -= Time.fixedDeltaTime;

        if (m_lifetime <= 0)
            Boom();
    }
    #endregion

    // EXECUTABLE METHODS //
    #region
    public void SetOwnerID(int _id)
    {
        Owner = RacerCore.GetRacerByID(_id);

        if (PhotonNetwork.IsConnected && photonView && photonView.IsMine)
            photonView.RPC("SetOwnerIDRemote", RpcTarget.Others, _id);

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Owner ID  set to " + _id);
    }
    public void SetCanTargetOwner(bool _can)
    {
        CanTargetOwner = _can;

        if (PhotonNetwork.IsConnected && photonView && photonView.IsMine)
            photonView.RPC("SetCanTargetOwnerRemote", RpcTarget.Others, _can);

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Rocket can" + (_can ? "" : "'t") + " hit its owner.");
    }
    public void Boom()
    {
        if (m_explosionPrefab)
            Instantiate(m_explosionPrefab, transform.position, Quaternion.identity);

        if (PhotonNetwork.IsConnected && photonView)
        {
            if (photonView.IsMine)
                PhotonNetwork.Destroy(gameObject);
            else
                photonView.RPC("RemoteBoom", RpcTarget.Others);
        }
        else
            Destroy(gameObject);
    }
    #endregion

    // COROUTINES //
    #region
    IEnumerator DelayActivation()
    {
        yield return new WaitForSeconds(0.5f);
        m_rocketOwnerProtected = false;

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Owner is no longer protected.");
    }
    #endregion
    
    // PHOTON / RPC //
    #region
    [PunRPC]
    void RemoteBoom()
    {
        if (m_explosionPrefab)
            Instantiate(m_explosionPrefab, transform.position, Quaternion.identity);

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Rocket has been remotely detonated.");

        if (photonView.IsMine)
            PhotonNetwork.Destroy(gameObject);
    }
    [PunRPC]
    void SetOwnerIDRemote(int _id)
    {
        Owner = RacerCore.GetRacerByID(_id);

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Rocket fired by player with ID " + _id);
    }
    [PunRPC]
    void SetCanTargetOwnerRemote(bool _can)
    {
        CanTargetOwner = _can;

        if (m_debugChannel)
            m_debugChannel.Raise(this, "Rocket can" + (_can ? "" : "'t") + " hit its owner.");
    }
    #endregion
}
