using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

[RequireComponent(typeof(NPC))]
[RequireComponent(typeof(Enemy))]
public class ThugNPCFollowing : MonoBehaviour
{
    public const string ACTION_KEY = "ATTACKING";

    private Rigidbody2D myRigidbody;
    public Animator anim;

    private Vector2 movement;
    public bool shouldRotate;
    public Vector3 dir;

    [Header("Following Logic")]
    public Vector3 homePosition;
    public Transform targetPosition;

    public AStarPathfindingAgent agent;

    public bool isDuringFollowing = false; // var is setted by trigger range 

    //public GameObject player;
    [Header("Core Logic")]
    public bool approaching = false;
    public bool isAfterAction = false;
    public float chasingRadius = 6f;  // radious where Npc start attacking ! ! !

    [Header("Attacking Logic")]  // TRASH - dupplicated from Following Enemy - move params to Enemy
    public float attackingRadius = 1.5f;  // radious where Npc start attacking ! ! !

    public bool hit = false;

    public bool firstAttack = false;

    public float timerDmg = 0f;
    public float waitTime = 1.0f;

    public float timerHit = 0f;
    public float hitWaitTime = 0.55f;

    public float expValue;
    public float thrust;
    public float knockTime;

    //public int isKilled; - movet do Enemy
    //isKilled = 0 - mob ALIVE
    //isKilled = 1 - mob DEAD

    public int isKilled2;

    public bool isPanelEnabled = true;



    void Awake()
    {
        agent = GetComponent<AStarPathfindingAgent>();

       
        homePosition = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, gameObject.transform.position.z);
    }

    // Start is called before the first frame update
    void Start()
    {
        targetPosition = GameObject.FindWithTag("Player").transform;

        //Copy from Eollwoing
        if (OnMapAppearanceMethod.IsNewGame())
        {
            gameObject.GetComponent<Enemy>().isKilled = 0;
        }

        if (gameObject.GetComponent<Enemy>().health <= 0)
            gameObject.GetComponent<Enemy>().isKilled = 1;
        else  // Else read saved value
            gameObject.GetComponent<Enemy>().isKilled = PlayerPrefs.GetInt(gameObject.GetComponent<Enemy>().enemyName + "-S");


        if (gameObject.GetComponent<Enemy>().isKilled == 1)
        {
            gameObject.SetActive(false);
            gameObject.GetComponent<Enemy>().isKilled = 0;
        }

        myRigidbody = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    public void Update()
    {
        // 0 Cofigure Animator
        if (Vector2.Distance(targetPosition.position, transform.position) <= chasingRadius)
        {
            dir = targetPosition.position - transform.position;
            float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
            dir.Normalize();
            movement = dir;
            anim.SetBool("isRunning", movement != Vector2.zero);

            if (shouldRotate)
            {
                anim.SetFloat("Xinfo", dir.x);
                anim.SetFloat("Yinfo", dir.y);
            }
        }


        // 1. Check range and decide which action do
        //      Following player detection
        if (IsInChassingRadious())
        {
            // 2'nd state alow us to brak going to hom,e action to follow player again
            if (gameObject.GetComponent<NPC>().State == NPCStateEnum.Pending || gameObject.GetComponent<NPC>().State == NPCStateEnum.Walking)
            {
                approaching = true;

                gameObject.GetComponent<NPC>().State = NPCStateEnum.Walking;
            }
        } else
        {
            // Turn around and go to home position
            if (approaching)
            {
                approaching = false;
                anim.SetBool("isRunning", true);
                gameObject.GetComponent<NPC>().State = NPCStateEnum.Walking;
            }
        }

        // 2.Take action based on conditions around
        HandleState();

        // 3.
        // COPIED FROM Following Enemy scripts
        // Taking hit logic
        timerHit += Time.deltaTime;
        if (hit == true)
        {
            if (timerHit >= hitWaitTime)
            {

                TakeDamage(PlayerPrefs.GetFloat("attackValue"));
                hit = false;
                timerHit = 0f;
                TakeKnockback();
            }
        }

        // Detecting "is alive" logic
        if (gameObject.active == false)
        {
            gameObject.GetComponent<Enemy>().isKilled = 1;
            PlayerPrefs.SetInt(gameObject.GetComponent<Enemy>().enemyName, gameObject.GetComponent<Enemy>().isKilled);
        }
    }

    public void CheckDistance()
    {
        StopAllCoroutines();


        // isDuringFollowing - avr is setted by trigger range 
        if (approaching && !IsInActionRadious())
        {
            agent.FindPath();

            StartCoroutine(agent.FollowPath());
        }
        else if (approaching)
        {
            // in this script we set attacking mode 
            SetActionAfterMetConditions();

            agent.path.Clear(); // if we are able to talgk we dont want go go further player
        }
        else if (!approaching)
        {
            if (Vector2.Distance(transform.position, homePosition) > 0.8f) // cont vale - path finding stop moving them before reachin position well..
            {
                agent.point = homePosition;

                agent.FindPoint();

                StartCoroutine(agent.FollowPath());
            }
            else
            {
                anim.SetBool("isRunning", false);
                gameObject.GetComponent<NPC>().State = NPCStateEnum.Pending;

            }
        }
    }


    #region Taking damage from Player detection

    public void OnTriggerEnter2D(Collider2D collision)
    {
        // Hit logic
        if (collision.gameObject.tag == "AttackHitbox" || collision.gameObject.tag == "PickaxeHitbox")
        {
            hit = true;
        }

    }

    public void OnTriggerExit2D(Collider2D other)
    {
        // Hit logic
        if (other.tag == "AttackHitbox" || other.tag == "PickaxeHitbox")
        {
            timerDmg = 0f;

            hit = false;
        }
    }
    #endregion

    public void HandleState()
    {
        switch (gameObject.GetComponent<NPC>().State)
        {
            case NPCStateEnum.Walking:
                {
                    CheckDistance();
                    break;
                }
            case NPCStateEnum.Talking:
                {
                    TalkingAction();
                    break;
                }
            case NPCStateEnum.Pending:
                {
                    break;
                }
            case NPCStateEnum.Attacking:
                {
                    AttackingAction();
                    break;
                }
            default:
                {
                    Debug.Log("Nieopisane zachowanie NPC ! ! !");
                    break;
                }
        }
    }

    public bool IsInChassingRadious()
    {
        if (Vector2.Distance(targetPosition.position, transform.position) >= chasingRadius)
            return false;

        return true;
    }

    public bool IsInActionRadious()
    {
        if (Vector2.Distance(targetPosition.position, transform.position) >= attackingRadius)
            return false;

        return true;
    }

    public void SetActionAfterMetConditions()
    {
        gameObject.GetComponent<NPC>().State = NPCStateEnum.Attacking;
    }

    public void TalkingAction()
    {
        // Not required in this script
    }

    public void AttackingAction()
    {
        // if during Attacking mode player GO OUT of the attacking radious
        if(!IsInActionRadious())
        {
            gameObject.GetComponent<NPC>().State = NPCStateEnum.Walking;
            return;
        }

        // Attacking logic
            if (firstAttack == false)
            {
                if (timerDmg >= 0.15f)
                {
                    firstAttack = true;

                    GameObject.FindGameObjectWithTag("Player").GetComponent<Player>().TakeDamage(
                        gameObject.GetComponent<Enemy>().baseAttack, 
                        isPanelEnabled
                    );

                    timerDmg = 0f;
                }
            }
            if (timerDmg >= waitTime)
            {
                timerDmg = 0f;

                GameObject.FindGameObjectWithTag("Player").GetComponent<Player>().TakeDamage(
                    gameObject.GetComponent<Enemy>().baseAttack,
                    isPanelEnabled
                );
            }

        timerDmg += Time.deltaTime;

    }

    #region dupplicated from Following :)
    public void TakeDamage(float damage)
    {
        Debug.Log("TakeDamage");
        gameObject.GetComponent<Enemy>().health -= damage;

        if (gameObject.GetComponent<Enemy>().health <= 0)
        {
            gameObject.SetActive(false);
            gameObject.GetComponent<Enemy>().isKilled = 1;
            GameObject.FindGameObjectWithTag("Player").GetComponent<Player>().GetExp(expValue);

            // pass info about killing assigned enemy to mission manager listener
            // pass enemy name from script NOT object name (thats allow to have many different objects variantsa with this same aggregate key (private name - not preffab name) )
            ConditionManager.Instance.UpdateKillCondition(gameObject.GetComponent<Enemy>().MinionName);
        }
    }

    public void TakeKnockback()
    {
        Rigidbody2D enemy = gameObject.GetComponent<Rigidbody2D>();
        Rigidbody2D player = GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>();

        if (enemy != null)
        {
            enemy.isKinematic = false;
            Vector2 difference = enemy.transform.position - player.transform.position;
            difference = difference.normalized * thrust;
            enemy.AddForce(difference, ForceMode2D.Impulse);
            //StartCoroutine(KnockCo(enemy));
        }
    }
    #endregion

    public void AfterAction()
    {
        approaching = false;
        isAfterAction = true;
        //isDuringConversation = false;
        //PlayerPrefs.SetInt(gameObject.name + ".FirstDialogue", System.Convert.ToInt32(isAfterAction));
        gameObject.GetComponent<NPC>().State = NPCStateEnum.Walking;
    }
}