using System.Collections;
using System.Collections.Generic;
using MoreMountains.Feedbacks;
using TMPro;
using UnityEngine;
using UnityEngine.AI;

public abstract class Enemy : MonoBehaviour, IDamageable
{
    [Header("Enemy Script")]
    public PlayerController playerController;
    public Animator animator;
    [SerializeField] protected List<GameObject> playerFlanks;
    [SerializeField] CapsuleCollider hitCapsuleCollider;
    [SerializeField] protected Rigidbody rb;
    [SerializeField] protected NavMeshAgent agent;
    [SerializeField] Vector3 alertPos;
    public Transform runAwayTarget;

    public Enemies enemiesSO;

    [Header("Prefabs")]
    [SerializeField] GameObject silverCoinPrefab;
    [SerializeField] GameObject bossCoinPrefab;
    [SerializeField] GameObject healPrefab;
    [SerializeField] GameObject dizzyPrefab;
    [SerializeField] GameObject[] xpStarsPrefabs;
    [SerializeField] GameObject alertPrefab;

    [Header("Feels")]
    [SerializeField] MMF_Player getHitFeel;

    public enum EnemyStates { Idle, Moving, Aiming, Shooting, Dodging, Running };
    [Header("States")]
    public EnemyStates enemyState = EnemyStates.Moving;
    public bool isDizzy;
    public bool isAlerted;
    public bool isDodging;
    public bool isRunningAway;

    [Header("Enemy Stats")]
    public int enemyHP;
    public int dizzyAmount;
    public float rotationSpeed;
    public int playerHarvest;
    public float forceStrength;
    public bool isAttackable;

    public static event System.Action<GameObject> OnEnemyDeath;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    protected virtual void Start()
    {
        playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
        rb = GetComponent<Rigidbody>();
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponentInChildren<Animator>();
        enemyHP = enemiesSO.enemyHP;
        playerHarvest = playerController.playerData.harvesting;

        foreach (var playerFlank in playerController.playerFlanks)
        {
            playerFlanks.Add(playerFlank);
        }

        isAttackable = true;
        SwitchState(EnemyStates.Idle);
        agent.enabled = true;
    }

    protected virtual void Update()
    {
        if (dizzyAmount >= enemiesSO.dizzyMax && !isDizzy)
        {
            StartCoroutine(DizzyTimer());
        }
    }

    public virtual void TakeDamage(int weaponDamage)
    {
        if (enemyHP <= 0) return; // Prevent multiple death calls

        enemyHP -= weaponDamage;

        if (!isAlerted)
        {
            AlertEnemy();
        }

        StartCoroutine(CalculateKnockback(playerController.playerData.knockback, gameObject));

        if (getHitFeel != null) getHitFeel.PlayFeedbacks();

        if (enemyHP <= 0)
        {
            OnEnemyDeath?.Invoke(gameObject);

            hitCapsuleCollider.enabled = false;
            agent.enabled = true;
            agent.isStopped = true;

            Destroy(gameObject, 1f);
        }
    }

    public virtual void Dodge()
    {
        if (!isDodging)
        {
            bool canDodge = Random.value < 0.9;

            if (canDodge)
            {
                StopAllCoroutines();
                StartCoroutine(DodgeTimer());
            }
        }
    }

    IEnumerator DodgeTimer()
    {
        rb.isKinematic = false;
        agent.enabled = false;
        isDodging = true;
        animator.SetBool("isDodging", true);

        Vector3 dodgeDirection = (Random.value > 0.5f) ? -transform.right : transform.right;
        dodgeDirection.y = 0;
        rb.AddForce(dodgeDirection * 20, ForceMode.Impulse);

        yield return new WaitForSeconds(0.5f);

        animator.SetBool("isDodging", false);
        isDodging = false;

        rb.isKinematic = true;
        agent.enabled = true;

        SwitchState(EnemyStates.Moving);
    }

    protected virtual void RunAway()
    {
        if (!isRunningAway)
        {
            StopAllCoroutines();
            agent.isStopped = false;

            StartCoroutine(RunAwayTimer());

            isRunningAway = true;
        }
    }

    IEnumerator RunAwayTimer()
    {
        agent.enabled = true;
        rb.isKinematic = true;

        animator.SetBool("isMoving", true);
        
        while (Vector3.Distance(transform.position, playerController.transform.position) < 15f)
        {
            Vector3 direction = (transform.position - playerController.transform.position).normalized;
            Vector3 runTo = transform.position + direction * 10f;
            runAwayTarget.transform.position = runTo;
            agent.SetDestination(runAwayTarget.transform.position);

            // Debug.DrawLine(transform.position, runTo, Color.red, 2f);

            yield return new WaitForSeconds(0.5f); // re-check interval
        }

        isRunningAway = false;

        animator.SetBool("isMoving", false);

        SwitchState(EnemyStates.Shooting);
    }

    public virtual void AlertEnemy()
    {
        if (!isAlerted)
        {
            Instantiate(alertPrefab, transform.position + alertPos, Quaternion.Euler(-25, 0, 0));
            isAlerted = true;
        }
    }

    IEnumerator CalculateKnockback(int knockback, GameObject gameObject)
    {
        // agent.enabled = false;

        rb.linearVelocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;

        Vector3 direction = gameObject.transform.position - playerController.gameObject.transform.position;
        rb.AddForce(direction * knockback, ForceMode.Impulse);

        yield return new WaitForSeconds(0.1f);

        rb.linearVelocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;

        agent.enabled = true;
    }

    IEnumerator DizzyTimer()
    {
        isDizzy = true;

        agent.isStopped = true;
        agent.speed = 0;
        GameObject dizzyInstance = Instantiate(dizzyPrefab, gameObject.transform.position + new Vector3(0, 1, 0), Quaternion.identity);
        dizzyInstance.transform.SetParent(gameObject.transform);

        yield return new WaitForSeconds(3f);

        Destroy(dizzyInstance);
        agent.isStopped = false;
        agent.speed = enemiesSO.enemySpeed;

        dizzyAmount = 0;
        isDizzy = false;
    }

    private void OnDestroy()
    {
        if (enemyHP > 0) return;
        OnEnemyDeath?.Invoke(gameObject);

        DropXP();

        int healDropChance = Random.Range(1, 10);

        if (healDropChance <= 2) // 20%
        {
            Instantiate(healPrefab, gameObject.transform.position, Quaternion.Euler(0, 0, -30f));
        }


        //enemy will always drop a coin, then with player harvest there's a 50% he'll more
        GameObject coin = Instantiate(silverCoinPrefab, transform.position + new Vector3(0, 1f, 0f), Quaternion.Euler(90, 0, 0));
        coin.transform.SetParent(null);

        if (playerHarvest >= 1)
        {
            for (int i = 0; i < playerHarvest; i++)
            {
                int randomNumber = Random.Range(0, 9);

                if (randomNumber <= 4)
                {
                    GameObject additionalCoin = Instantiate(silverCoinPrefab, transform.position + new Vector3(0, 1f, 0f), Quaternion.Euler(90, 0, 0));
                    additionalCoin.transform.SetParent(null);
                }

                if (randomNumber <= 0)
                {
                    GameObject additionalCoin = Instantiate(bossCoinPrefab, transform.position + new Vector3(0, 1f, 0f), Quaternion.Euler(90, 0, 0));
                    additionalCoin.transform.SetParent(null);
                }
            }
        }
    }

    void DropXP()
    {
        for (int i = 0; i < enemiesSO.xpAmount; i++)
        {
            Vector3 randomOffset = new Vector3(Random.Range(-1, 1), 0, Random.Range(-1, 1));
            float randomStarWeight = Random.value;
            GameObject starToDrop;

            if (randomStarWeight < 0.1f)
            {
                starToDrop = xpStarsPrefabs[2];
            }
            else if (randomStarWeight < 0.4f)
            {
                starToDrop = xpStarsPrefabs[1];
            }
            else
            {
                starToDrop = xpStarsPrefabs[0];
            }

            Rigidbody xpRb = Instantiate(starToDrop, transform.position, Quaternion.identity).GetComponent<Rigidbody>();
            xpRb.AddForce((randomOffset + Vector3.up * 1.1f) * Random.Range(forceStrength - 0.2f, forceStrength), ForceMode.Impulse);
        }
    }

    public void SwitchState(EnemyStates newState)
    {
        enemyState = newState;
        if (!agent.enabled) agent.enabled = true;
    }

    protected void Rotate()
    {
        var direction = (playerController.transform.position - transform.position).normalized;
        direction.y = 0;
        Quaternion targetRotation = Quaternion.LookRotation(direction);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    }
}