using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;

public class Ally : MonoBehaviour
{
    public static List<GameObject> troops = new List<GameObject>();

    [Header("Stats")]
    public float health;

    [Header("Attacking")]
    public bool hasRamDamage;
    public float ramDamage;
    public float ramKnockback;
    [Space]
    public bool hasMeleeAttacks;
    public float meleeRange;
    public float recoveryTime;
    public float chargeTime;
    public float meleeDamage;
    public float meleeKnockback;
    public GameObject attackObject;
    [Space]
    public bool hasRangedAttacks;
    public float aimTime;
    public float rangedRange;
    public float rangedDamage;
    public float rangedKnockback;
    public float reloadTime;
    public float projectileSpeed;
    public GameObject projectile;
    [Space]
    public bool meleeReady = true;
    public bool rangedReady = true;
    public bool isAttacking;
    [Space]
    public float attackRadius;
    public float forgetRadius;

    [Header("Values")]
    public float distanceBetweenTarget;
    public GameObject currentTarget;
    public float startingSpeed;
    public float barTime;

    [Header("References")]
    public Slider slider;
    public Animator anim;
    public GameObject eyes;
    public Barracks parent;
    public Rigidbody2D rb;
    public GameObject pivot;
    public GameObject eyesPoint;
    public GameObject forward;
    public SpriteRenderer spriteRenderer;
    public NavMeshAgent agent;
    public GameObject damageNumber;
    private Color startingColor;

    private void Awake()
    {
        troops.Add(this.gameObject);
        parent = GetComponentInParent<Barracks>();
        parent.aliveAllies.Add(this.gameObject);
    }

    private void Start()
    {
        slider.maxValue = health;

        agent.updateRotation = false;
        agent.updateUpAxis = false;
        startingColor = spriteRenderer.color;

        startingSpeed = agent.speed;
        StartCoroutine(UpdateClosestEnemy());
    }

    private void Update()
    {
        barTime -= Time.deltaTime;
        slider.value = health;

        if (Settings.instance.healthBarsSize == 2)
        {
            slider.transform.localScale *= 2;
        }

        if (barTime <= 0)
        {
            slider.gameObject.SetActive(false);
        }
        else
        {
            slider.gameObject.SetActive(true);
        }

        if (currentTarget != null)
        {
            var offset = 0f;
            Vector2 direction = currentTarget.transform.position - transform.position;
            direction.Normalize();
            float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
            pivot.transform.rotation = Quaternion.Euler(Vector3.forward * (angle + offset));
        }

        HandleTargetting();
        HandleAttacking();


        Vector3 vel = transform.position * rb.velocity;

        if (agent.velocity.x < 0)
        {
            spriteRenderer.flipX = true;
        }
        else if(agent.velocity.x >= 0)
        {
            spriteRenderer.flipX = false;
        }

        

        if (agent.velocity.magnitude > 0.1f)
        {
            eyes.transform.position = new Vector3(eyesPoint.transform.position.x, eyesPoint.transform.position.y, -4f);
            //anim.SetBool("isMoving", true);
        }
        else
        {
            //anim.SetBool("isMoving", false);
            eyes.transform.position = new Vector3(pivot.transform.position.x, pivot.transform.position.y, -4f);
        }
    }


    IEnumerator UpdateClosestEnemy()
    {
        distanceBetweenTarget = Vector2.Distance(gameObject.transform.position, GetClosestEnemy().position);
        currentTarget = GetClosestEnemy().gameObject;

        yield return new WaitForSeconds(1);

        StartCoroutine(UpdateClosestEnemy());
    }

    public void HandleTargetting()
    {
        Vector2 randomPoint = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y) + Random.insideUnitCircle * 3f;

        if (distanceBetweenTarget < attackRadius & Enemy.enemies.Count > 0)
        {
            agent.SetDestination(GetClosestEnemy().transform.position);
        }
        else if (distanceBetweenTarget > forgetRadius)
        {
            agent.SetDestination(randomPoint);
        }
    }

    public Transform GetClosestEnemy()
    {
        float minDistance = 9999;
        GameObject target = null;

        for (int i = 0; i < Enemy.enemies.Count; i++)
        {
            Transform targetTransform = Enemy.enemies[i].transform;
            float distance = Vector2.Distance(gameObject.transform.position, targetTransform.position);

            if (distance < minDistance)
            {
                minDistance = distance;
                target = Enemy.enemies[i].gameObject;
                Debug.Log(target);
            }
        }
        if (target != null)
        {
            return target.transform;
        }
        else
        {
            return gameObject.transform;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (hasRamDamage == true)
        {
            if (collision.gameObject.CompareTag("Enemy"))
            {
                collision.gameObject.GetComponent<Rigidbody2D>().AddForce(forward.gameObject.transform.right * ramKnockback * 15, ForceMode2D.Impulse);
                collision.gameObject.GetComponent<Enemy>().TakeDamage(ramDamage, 3, 1);
                rb.AddForce(-forward.gameObject.transform.right * ramKnockback * 10, ForceMode2D.Impulse);
            }
        }
    }

    void HandleAttacking()
    {
        if (currentTarget != gameObject)
        {
            if (hasMeleeAttacks & distanceBetweenTarget < meleeRange & !isAttacking & meleeReady)
            {
                isAttacking = true;
                meleeReady = false;
                StartCoroutine(MeleeAttack());
            }

            if (hasRangedAttacks & distanceBetweenTarget < rangedRange & !isAttacking & rangedReady)
            {
                isAttacking = true;
                rangedReady = false;
                StartCoroutine(RangedAttack());
            }
        }
    }

    IEnumerator MeleeAttack()
    {
        spriteRenderer.color = Color.grey;
        agent.speed /= 1.5f;
        yield return new WaitForSeconds(chargeTime);
        GameObject attack = Instantiate(attackObject, forward.transform.position, forward.transform.rotation);
        PlayerMeleeAttack a = attack.GetComponent<PlayerMeleeAttack>();
        a.damage = meleeDamage;
        a.knockback = meleeKnockback;
        a.type = 3;
        isAttacking = false;
        spriteRenderer.color = startingColor;
        agent.speed = startingSpeed;
        StartCoroutine(RecoverFromMelee());
    }

    IEnumerator RecoverFromMelee()
    {
        yield return new WaitForSeconds(recoveryTime);

        meleeReady = true;
    }

    IEnumerator RangedAttack()
    {
        spriteRenderer.color = Color.gray;
        agent.speed /= 3;
        yield return new WaitForSeconds(aimTime);
        GameObject Projectile = Instantiate(projectile, forward.transform.position, forward.transform.rotation);
        Projectile p = Projectile.GetComponent<Projectile>();
        p.speed = projectileSpeed;
        p.damage = rangedDamage;
        p.knockback = rangedKnockback;
        p.type = 3;
        isAttacking = false;
        agent.speed = startingSpeed;
        spriteRenderer.color = startingColor;
        StartCoroutine(RecoverFromRanged());
    }

    IEnumerator RecoverFromRanged()
    {
        yield return new WaitForSeconds(reloadTime);

        rangedReady = true;
    }

    public void TakeDamage(float damage, int strength)
    {
        barTime = 3;
        health -= damage;

        if (Settings.instance.damageNumbersSize != 3)
        {
            DamageNumber damagenumber = Instantiate(damageNumber, transform.position, transform.rotation).GetComponent<DamageNumber>();
            damagenumber.Setup(damage, strength);
        }

        if (!isAttacking)
        {
            StartCoroutine(Flash());
        }

        if (health <= 0)
        {
            Die();
        }
    }

    private void OnDestroy()
    {
        troops.Remove(this.gameObject);
        Destroy(gameObject);
    }

    void Die()
    {
        troops.Remove(this.gameObject);
        parent.aliveAllies.Remove(this.gameObject);
        Destroy(gameObject);
    }

    IEnumerator Flash()
    {
        spriteRenderer.color = Color.red;
        yield return new WaitForSeconds(0.1f);
        spriteRenderer.color = startingColor;
    }
}