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

public class NPCController : MonoBehaviour
{
    [Header("Events:")]
    [SerializeField] protected GameEvent_Float experienceOnDeath;
    [Header("Settings:")]
    [SerializeField] protected float sightRange;
    [SerializeField] protected float sightRangeMultiplierForProjectiles;
    [SerializeField] protected float distanceToChangePatrolDestination;
    [SerializeField] protected float patrolAgentSpeed;
    [SerializeField] protected float chasingAgentSpeed;
    [SerializeField] protected float timeBetweenAttacks = 1f;
    [HideInInspector]
    public PhotonView photonView;
    [HideInInspector]
    public Taggable myTag;

    protected NavMeshAgent agent;

    public List<Taggable> possibleTargets = new List<Taggable>();
    public Taggable currentTarget;

    protected SphereCollider sight;

    protected PhotonView otherView;
    protected Taggable possibleTarget;
    protected NPCAbilityBinder abilityBinder;
    protected DropTable dropTable;

    protected Vector3 patrolDestination = new Vector3();

    protected float counter = 0f;

    protected Health health;

    protected bool isDead = false;

    #region Death Animation
    protected float moveSpeed = 0.5f; // Speed of the downwards movement
    protected float moveDistance = 3.0f; // Distance to move downwards
    protected float moveDelay = 0.25f; // Delay before starting the movement
    protected Vector3 startPosition;
    protected Vector3 endPosition;
    #endregion

    protected virtual void Awake()
    {
        myTag = GetComponentInParent<Taggable>();
        agent = GetComponentInParent<NavMeshAgent>();
        photonView = GetComponentInParent<PhotonView>();
        abilityBinder = GetComponent<NPCAbilityBinder>();
        health = GetComponent<Health>();
        dropTable = GetComponentInChildren<DropTable>();

        if (!photonView.IsMine) return;
    }

    // Start is called before the first frame update
    protected virtual void Start()
    {
        if (!photonView.IsMine) return;

        sight = this.gameObject.AddComponent<SphereCollider>();
        sight.radius = sightRange;
        sight.isTrigger = true;
        isDead = false;

        counter = timeBetweenAttacks / 2f;

        health.onDeath.AddListener(OnDeath);
    }

    protected virtual void OnDeath()
    {
        photonView.RPC(nameof(RPC_OnDeath), RpcTarget.All, dropTable.CalculateLootDrop());
    }

    [PunRPC]
    protected virtual void RPC_OnDeath(bool lootDropped)
    {
        if (isDead) return;

        Debug.Log($"{this.gameObject.name} died!");

        isDead = true;

        agent.enabled = false;

        experienceOnDeath.Raise(health.GetMaxValue() * GameConstants.GameBalancing.HealthIntoExperienceMultiplier);

        dropTable.DropLoot(lootDropped);

        if (!photonView.IsMine) return;

        StartCoroutine(AnimateOnDeath());
    }

    protected virtual IEnumerator AnimateOnDeath()
    {
        startPosition = transform.position;
        endPosition = transform.position - Vector3.up * moveDistance;

        yield return new WaitForSeconds(moveDelay);

        float elapsedTime = 0.0f;
        while (elapsedTime < 1.0f)
        {
            // Increment elapsed time based on Time.deltaTime
            elapsedTime += Time.deltaTime * moveSpeed;

            // Move the transform towards the end position
            transform.position = Vector3.Lerp(transform.position, endPosition, elapsedTime);

            yield return null; // Yielding null will make the coroutine wait until the next frame
        }

        DestroyAfterEffect();
    }

    protected virtual void DestroyAfterEffect()
    {
        if (!photonView.IsMine) return;

        PhotonNetwork.Destroy(this.gameObject);
    }

    protected virtual void Update()
    {
        if (!photonView.IsMine) return;
        if (isDead) return;

        if (possibleTargets.Count <= 0)
        {
            if (currentTarget != null)
            {
                currentTarget = null;
                PatrolNewPosition();
            }
            if (agent.destination == null)
            {
                PatrolNewPosition();
            }
            else if (agent.remainingDistance < distanceToChangePatrolDestination)
            {
                PatrolNewPosition();
            }
        }
        else
        {
            if (possibleTargets[0] == null)
            {
                possibleTargets.RemoveAt(0);
                return;
            }

            currentTarget = possibleTargets[0];
            agent.speed = chasingAgentSpeed;
            patrolDestination = currentTarget.transform.position;
            patrolDestination.y = 0f;
            agent.SetDestination(patrolDestination);

            counter += Time.deltaTime;
            if (agent.remainingDistance <= sightRange * sightRangeMultiplierForProjectiles)
            {
                agent.isStopped = true;
                if (counter >= timeBetweenAttacks)
                {
                    counter = 0f;
                    if (!abilityBinder.ValidCoreAbility())
                        abilityBinder.UsePrimaryAbility();

                    else
                    {
                        if (Random.Range(0, 10) > 3)
                            abilityBinder.UsePrimaryAbility();
                        else
                            abilityBinder.UseCoreAbility(currentTarget.transform.position);
                    }
                }
            }
            else
            {
                agent.isStopped = false;
            }
        }
    }

    protected virtual void PatrolNewPosition()
    {
        agent.speed = patrolAgentSpeed;
        patrolDestination.x = Random.Range(-5, 5);
        patrolDestination.y = 0f;
        patrolDestination.z = Random.Range(-5, 5);
        agent.SetDestination(this.transform.position + patrolDestination);
        agent.isStopped = false;
    }

    protected virtual void OnTriggerEnter(Collider other)
    {
        if (!photonView.IsMine) return;

        otherView = other.GetComponentInParent<PhotonView>();
        if (otherView != null)
        {
            if (otherView == photonView) return;
        }

        possibleTarget = other.GetComponentInParent<Taggable>();

        if (possibleTarget == null) return;

        if (possibleTarget.targetTag == myTag.targetTag || myTag.targetTag.AlliedTags.Contains(possibleTarget.targetTag)) return;

        if (possibleTargets.Contains(possibleTarget)) return;

        possibleTargets.Add(possibleTarget);
    }

    protected virtual void OnTriggerExit(Collider other)
    {
        if (!photonView.IsMine) return;

        otherView = other.GetComponentInParent<PhotonView>();
        if (otherView != null)
        {
            if (otherView == photonView) return;
        }

        possibleTarget = other.GetComponentInParent<Taggable>();

        if (possibleTarget == null) return;

        if (possibleTarget.targetTag == myTag.targetTag) return;

        if (!possibleTargets.Contains(possibleTarget)) return;

        possibleTargets.Remove(possibleTarget);
    }


    protected virtual void OnDrawGizmosSelected()
    {
        Gizmos.DrawWireSphere(this.transform.position, sightRange);
    }
}
