using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum AgentState
{
    Idle,
    Patrol,
    Follow,
    Aggressive
}

[RequireComponent(typeof(Player))]
public class Agent : MonoBehaviour
{

    Player player;

    Dictionary<AgentState, Action> actions = new Dictionary<AgentState, Action>();


    private Controller2D controller2D;
    AgentState state;

    private const float AttackTime = 2f;
    private bool isAlreadyAttacking = false;
    public Transform target;
    //[HideInInspector]
    public List<Transform> visibleTargets = new List<Transform>();

    public float viewRadius;
    [Range(0, 360)]
    public float viewAngle;

    public bool isStatic;

    public LayerMask targetMask;
    public LayerMask obstacleMask;

    public AgentState prevState;

    private void Awake()
    {
        controller2D = GetComponent<Controller2D>();
    }

    // Use this for initialization
    void Start()
    {
        player = GetComponent<Player>();
        actions.Add(AgentState.Idle, Idle);
        actions.Add(AgentState.Patrol, Patrol);
        actions.Add(AgentState.Follow, Follow);
        actions.Add(AgentState.Aggressive, Aggressive);

        state = AgentState.Patrol;
        player.SetDirectionalInput(Vector2.right);

        StartCoroutine("FindTargetsWithDelay", .2f);
    }

    // Update is called once per frame
    void Update()
    {

        //if (Input.GetKeyDown(KeyCode.F))
        //    state = AgentState.Follow;
        //if (Input.GetKeyDown(KeyCode.P))
        //    state = AgentState.Patrol;
        //if (Input.GetKeyDown(KeyCode.K))
        //state = AgentState.Aggressive;

        if (player.IsDead) return;

        if (isStatic)
            Idle();
        else
            actions[state]();

    }



    public void SetState(AgentState s)
    {
        prevState = state;
        state = s;
        isStatic = false;

        player.animator.SetBool("Crazy", false);
    }

    void Idle ()
    {
        player.SetDirectionalInput(Vector2.zero);
    }

    void Patrol()
    {
        if (!controller2D.collisions.below)
            return;

        //Debug.Log(transform.name + " is patrolling on " + controller2D.platform.name + "!");


        if (player.velocity.x > 0)
        {

            if (transform.position.x - controller2D.platform.bounds.center.x > controller2D.platform.bounds.extents.x * 0.9f)
            {
                //Debug.Log(transform.name + " needs to go left!");
                player.SetDirectionalInput(Vector2.left);
            }

        }
        else if (player.velocity.x < 0)
        {

            if (controller2D.platform.bounds.center.x - transform.position.x > controller2D.platform.bounds.extents.x * 0.9f)
            {
                //Debug.Log(transform.name + " needs to go right!");
                player.SetDirectionalInput(Vector2.right);
            }
        }
        if (player.moveAmount == Vector2.zero)
        {
            //Debug.Log(transform.name + " needs to go " + (controller2D.collisions.left ? "right!" : "left!"));
            player.SetDirectionalInput(player.velocity.x < 0 ? Vector2.right : Vector2.left);
        }
    }

    void Follow()
    {
        if (isTargetVisible())
        {
            Debug.Log(transform.name + " is following " + target.name);
            if (Mathf.Abs(target.position.x - transform.position.x) > 0.2f)
                player.SetDirectionalInput(target.position.x - transform.position.x > 0f ? Vector2.right : Vector2.left);
            else
                player.SetDirectionalInput(Vector2.zero);
        }
        else
            Patrol();
    }

    void GoCrazy()
    {
        player.SetDirectionalInput(Vector2.zero);
        player.animator.SetBool("Crazy", true);
    }

    void Aggressive()
    {
        target = null;
        //Dictionary<int, Transform> targetSelector = new Dictionary<int, Transform>();
        //foreach (var visibleTarget in visibleTargets)
        //{
        //    if (visibleTarget.tag.Equals("Destructable"))
        //    {
        //        targetSelector[1] = visibleTarget;
        //    }
        //    else if (visibleTarget.tag.Equals("Player"))
        //    {
        //        targetSelector[2] = visibleTarget;
        //    }
        //    else
        //    {
        //        targetSelector[3] = visibleTarget;
        //    }
        //}
        //if (targetSelector.ContainsKey(1))
        //{
        //    target = targetSelector[1];
        //}
        //else if (targetSelector.ContainsKey(2))
        //{
        //    target = targetSelector[2];
        //}
        //else if (targetSelector.ContainsKey(3))
        //{
        //    target = targetSelector[3];
        //}


        if (target != null)
        {
            if (Mathf.Abs(target.position.x - transform.position.x) > 0.2f)
                player.SetDirectionalInput(target.position.x - transform.position.x > 0f ? Vector2.right : Vector2.left);
            else
            {
                player.SetDirectionalInput(Vector2.zero);
                StartCoroutine(Attack());
            }
        }
        else
        {
            bool jump = UnityEngine.Random.Range(0, 100) < 5;
            if (jump)
            {
                //player.animator.SetBool("Crazy", false);
                //player.OnJumpInputDown();
            }
            else
            {
                
                bool patrol = UnityEngine.Random.Range(0, 100) < 5;
                if (patrol)
                {
                    player.animator.SetBool("Crazy", false);
                    Patrol();
                }
                else
                {
                    player.SetDirectionalInput(Vector2.zero);
                    player.animator.SetBool("Crazy", true);
                }
            }


        }
    }

    IEnumerator Attack()
    {
        if (!isAlreadyAttacking)
        {
            Debug.Log(transform.name + " is attacking " + target.name);
            isAlreadyAttacking = true;
            yield return new WaitForSeconds(AttackTime);
            isAlreadyAttacking = false;
        }

    }

    IEnumerator FindTargetsWithDelay(float delay)
    {
        while (true)
        {
            yield return new WaitForSeconds(delay);
            FindVisibleTargets();
        }
    }

    void FindVisibleTargets()
    {
        visibleTargets.Clear();
        Collider2D[] targetsInViewRadius = Physics2D.OverlapCircleAll(transform.position, viewRadius, targetMask);


        for (int i = 0; i < targetsInViewRadius.Length; i++)
        {
            Transform t = targetsInViewRadius[i].transform;
            if (t == transform) continue;
            Vector2 dirToTarget = (t.position - transform.position).normalized;

            //if (Vector2.Angle(player.velocity, dirToTarget) < viewAngle / 2)
            {
                float dstToTarget = Vector2.Distance(transform.position, t.position);
                if (!Physics2D.Raycast(transform.position, dirToTarget, dstToTarget, obstacleMask))
                {
                    visibleTargets.Add(t);
                }
            }
        }
    }

    bool isTargetVisible()
    {
        return visibleTargets.Contains(target);
    }
}
