using Spine.Unity;
using Spine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EnemyState
{
    Idle = 0,
    Walk = 2,
    Rise = 3,//空中上升
    Fall = 4,//空中下落
    Hurt = 5,
    Attack = 6,
    Die = 7,
}

public enum EnemyTargetType
{
    All = 0,
    Demonic = 1,
    LowHPDemonic = 2,
    Tower = 3,
    Player = 4,
}

public enum SearchState
{
    NoTarget = 0,//搜索范围内没有目标
    InSearchScope = 1,//在搜索范围内发现目标，但不在攻击范围内
    InAttackScope = 2,//目标在攻击范围内
}

public class Enemy : MonoBehaviour
{
    public SkeletonMecanim mecanim;
    public Skeleton skeleton;

    public Animator ani;
    public Animator aniCollider;
    public Rigidbody rb;
    public Foot foot;
    public Transform bodyTrans;
    public UIHP uiHp;
    public SearchTrigger searchTrigger;

    public float extraRiseGravity = 0; //上升时额外重力加速度
    public float extraFallGravity = -10; //下落时额外重力加速度
    public float jumpSpeed = 10;
    //public float airJumpSpeed = 10;
    public float maxMoveSpeed = 5;
    //public float moveAcc = 5f;
    //public float airMoveAcc = 3f;

    public EnemyState state;
    public SearchState searchState;
    [HideInInspector]
    public float hurtKeepTime;
    public float totalHurtKeepTime = 0.5f;
    [HideInInspector]
    public float attackTime;
    public float totalAttack1Time = 0.5f;
    public float totalAttack2Time = 0.5f;

    public List<EnemyTargetType> targetTypes;

    public bool isDie = false;
    public int totalHp = 100;
    public int hp;
    public List<AttackInfo> attack1Infos, attack2Infos;
    public List<AttackTrigger> attackTriggers;
    public float attackDistance;
    public bool canFly = false;
    public bool canHitFly = false;

    public Demonic targetDemonic;
    public Tower targetTower;
    public PlayerController targetPlayer;

    private void Awake()
    {
        if (!mecanim)
        {
            mecanim = GetComponentInChildren<SkeletonMecanim>();
            skeleton = mecanim.skeleton;
        }
        if (!ani)
        {
            ani = GetComponentInChildren<Animator>();
        }
        Debug.Log("测试");
        BeCreate(100);
    }

    private void FixedUpdate()
    {
        OnSearchState();
        OnState();
    }

    public void Turn()
    {
        bodyTrans.localScale = new Vector3(-bodyTrans.localScale.x, bodyTrans.localScale.y, bodyTrans.localScale.z);
    }

    public Vector3 GetMoveDir()
    {
        Vector3 moveDir = Vector3.zero;
        Transform targetTrans = null;
        switch (searchState)
        {
            case SearchState.NoTarget:
                moveDir = Vector3.right;
                break;
            case SearchState.InSearchScope:
                targetTrans = null;
                if (targetDemonic)
                {
                    targetTrans = targetDemonic.transform;
                }
                else if (targetTower)
                {
                    targetTrans = targetTower.transform;
                }
                else if (targetPlayer)
                {
                    targetTrans = targetPlayer.transform;
                }
                if (!targetTrans)
                {
                    moveDir = Vector3.zero;
                }
                else if (targetTrans.position.x - transform.position.x < 0)
                {
                    moveDir = Vector3.left;
                }
                else
                {
                    moveDir = Vector3.right;
                }
                break;
            case SearchState.InAttackScope:
                targetTrans = null;
                if (targetDemonic)
                {
                    targetTrans = targetDemonic.transform;
                }
                else if (targetTower)
                {
                    targetTrans = targetTower.transform;
                }
                else if (targetPlayer)
                {
                    targetTrans = targetPlayer.transform;
                }
                if (!targetTrans)
                {
                    moveDir = Vector3.zero;
                }
                else if (targetTrans.position.x - transform.position.x < 0)
                {
                    moveDir = Vector3.left;
                }
                else
                {
                    moveDir = Vector3.right;
                }
                break;
            default:
                break;
        }
        return moveDir;
    }

    public bool GetAttack()
    {
        if (searchState == SearchState.InAttackScope)
        {
            return true;
        }
        return false;
    }

    public bool GetJump()
    {
        return false;
    }

    public void OnState()
    {
        hurtKeepTime -= Time.deltaTime;
        attackTime -= Time.deltaTime;
        Vector3 leftDir = GetMoveDir();
        bool isAttack = GetAttack();
        switch (state)
        {
            case EnemyState.Idle:
                if (isAttack)
                {
                    Attack2();
                    break;
                }
                if (!foot.TrigGround)
                {
                    if (rb.velocity.y > 0)
                    {
                        ChangeState(EnemyState.Rise);
                        break;
                    }
                    else
                    {
                        ChangeState(EnemyState.Fall);
                        break;
                    }
                }
                if (leftDir.x > 0.3f || leftDir.x < -0.3f)
                {
                    ChangeState(EnemyState.Walk);
                    break;
                }
                //rb.velocity = Vector3.zero;
                break;
            case EnemyState.Walk:
                if (isAttack)
                {
                    Attack2();
                    break;
                }
                if (!foot.TrigGround)
                {
                    if (rb.velocity.y > 0)
                    {
                        ChangeState(EnemyState.Rise);
                        break;
                    }
                    else
                    {
                        ChangeState(EnemyState.Fall);
                        break;
                    }
                }
                if (leftDir.x < 0.3f && leftDir.x > -0.3f)
                {
                    ChangeState(EnemyState.Idle);
                    break;
                }
                if (leftDir.x > 0.3f)
                {
                    //rb.velocity += Vector3.right * moveAcc * Time.deltaTime;
                    rb.velocity = Vector3.right * maxMoveSpeed;
                    //if (rb.velocity.x > maxMoveSpeed)
                    //{
                    //    rb.velocity = new Vector3(maxMoveSpeed, rb.velocity.y, rb.velocity.z);
                    //}
                    if (bodyTrans.localScale.x > 0)
                    {
                        Turn();
                    }
                }
                else if (leftDir.x < -0.3f)
                {
                    //rb.velocity -= Vector3.right * moveAcc * Time.deltaTime;
                    rb.velocity = Vector3.left * maxMoveSpeed;
                    //if (rb.velocity.x < -maxMoveSpeed)
                    //{
                    //    rb.velocity = new Vector3(-maxMoveSpeed, rb.velocity.y, rb.velocity.z);
                    //}
                    if (bodyTrans.localScale.x < 0)
                    {
                        Turn();
                    }
                }
                break;
            case EnemyState.Rise:
                if (rb.velocity.y <= 0)
                {
                    ChangeState(EnemyState.Fall);
                    break;
                }
                //if (btnJumpPress || cacheJumpTime > 0)
                //{
                //    if (!airJumped && rb.velocity.y < airJumpSpeed)
                //    {
                //        airJumped = true;
                //        AirJump();
                //        break;
                //    }
                //}
                
                rb.velocity += Vector3.up * extraRiseGravity * Time.deltaTime;
                break;
            case EnemyState.Fall:
                if (foot.TrigGround)
                {
                    ChangeState(EnemyState.Idle);
                    break;
                }
                //if (foot.canStepPlayers.Count > 0)
                //{
                //    Jump(jumpSpeed / 2);
                //    StepOther();
                //    break;
                //}
                //if (foot.canStepEnemyList.Count > 0)
                //{
                //    Jump(jumpSpeed / 2);
                //    StepEnemy();
                //    break;
                //}
                //if (btnJumpPress || cacheJumpTime > 0)
                //{
                //    if (!airJumped)
                //    {
                //        airJumped = true;
                //        AirJump();
                //        break;
                //    }
                //    else if (canJumpTick >= runner.Tick)
                //    {
                //        Jump();
                //        break;
                //    }
                //}
                rb.velocity += Vector3.up * extraFallGravity * Time.deltaTime;
                break;
            case EnemyState.Hurt:
                if (hurtKeepTime <= 0)
                {
                    ChangeState(EnemyState.Idle);
                    break;
                }
                if (!foot.TrigGround)
                {
                    rb.velocity += Vector3.up * extraFallGravity * Time.deltaTime;
                }
                rb.velocity = rb.velocity / 5 * 4;
                break;
            case EnemyState.Attack:
                if (attackTime <= 0)
                {
                    ChangeState(EnemyState.Idle);
                    break;
                }
                break;
            default:
                break;
        }
    }

    public void ChangeState(EnemyState newState)
    {
        switch (state)
        {
            case EnemyState.Idle:
                break;
            case EnemyState.Walk:
                rb.velocity = Vector3.zero;
                break;
            case EnemyState.Rise:
                break;
            case EnemyState.Fall:
                rb.velocity = Vector3.zero;
                break;
            case EnemyState.Hurt:
                break;
            case EnemyState.Attack:
                aniCollider.Play("NotAttack", 1, 0);
                break;
            case EnemyState.Die:
                isDie = false;
                break;
            default:
                break;
        }
        EnemyState oldState = state;
        state = newState;
        switch (newState)
        {
            case EnemyState.Idle:
                ani.Play("idle", 0, 0);
                aniCollider.Play("Idle", 0, 0);
                rb.velocity = Vector3.zero;
                //animalAni.SetInteger("state", (int)PlayerState.Idle);
                break;
            case EnemyState.Walk:
                ani.Play("walk", 0, 0);
                aniCollider.Play("Walk", 0, 0);
                //animalAni.SetInteger("state", (int)PlayerState.Walk);
                break;
            case EnemyState.Rise:
                aniCollider.Play("Rise", 0, 0);
                break;
            case EnemyState.Fall:
                aniCollider.Play("Fall", 0, 0);
                //animalAni.SetInteger("state", (int)PlayerState.Fall);
                break;
            case EnemyState.Hurt:
                ani.Play("hitted", 0, 0);
                aniCollider.Play("Hurt", 0, 0);
                hurtKeepTime = totalHurtKeepTime;
                //ani.Play("Invincible", 2, 0);
                break;
            case EnemyState.Attack:
                break;
            case EnemyState.Die:
                ani.Play("die", 0, 0);
                aniCollider.Play("Die", 0, 0);
                isDie = true;
                break;
            default:
                break;
        }
    }

    public void Jump()
    {
        SetUpSpeed(jumpSpeed);
        ani.Play("jump", 0, 0);
    }

    public void SetUpSpeed(float speed)
    {
        ChangeState(EnemyState.Rise);
        Vector3 velocity = rb.velocity;
        Vector3 leftDir = GetMoveDir();
        if (leftDir.x > 0.3f)
        {
            if (bodyTrans.localScale.x > 0)
            {
                Turn();
            }
        }
        else if (leftDir.x < -0.3f)
        {
            if (bodyTrans.localScale.x < 0)
            {
                Turn();
            }
        }
        velocity.y = speed;
        rb.velocity = velocity;
        //animalAni.SetInteger("state", (int)PlayerState.Rise);
    }

    public void ChangeSearchState(SearchState newState)
    {
        switch (searchState)
        {
            case SearchState.NoTarget:
                break;
            case SearchState.InSearchScope:
                break;
            case SearchState.InAttackScope:
                break;
            default:
                break;
        }
        searchState = newState;
        switch (searchState)
        {
            case SearchState.NoTarget:
                break;
            case SearchState.InSearchScope:
                break;
            case SearchState.InAttackScope:
                break;
            default:
                break;
        }
    }

    public bool SearchTarget()
    {
        Demonic demonic;
        Tower tower;
        PlayerController player;
        float disDemonic, disTower, disPlayer;
        for (int i = 0; i < targetTypes.Count; i++)
        {
            switch (targetTypes[i])
            {
                case EnemyTargetType.All:
                    demonic = searchTrigger.GetMinDisDemonic(canHitFly, out disDemonic);
                    tower = searchTrigger.GetMinDisTower(out disTower);
                    player = searchTrigger.GetPlayer(out disPlayer);
                    if (disDemonic <= disTower && disDemonic <= disPlayer && demonic != null)
                    {
                        targetDemonic = demonic;
                        targetTower = null;
                        targetPlayer = null;
                        return true;
                    }
                    else if (disTower <= disDemonic && disTower <= disPlayer && tower != null)
                    {
                        targetDemonic = null;
                        targetTower = tower;
                        targetPlayer = null;
                        return true;
                    }
                    else if (disPlayer <= disDemonic && disPlayer <= disTower && player != null)
                    {
                        targetDemonic = null;
                        targetTower = null;
                        targetPlayer = player;
                        return true;
                    }
                    break;
                case EnemyTargetType.Demonic:
                    demonic = searchTrigger.GetMinDisDemonic(canHitFly, out disDemonic);
                    if (demonic != null)
                    {
                        targetDemonic = demonic;
                        targetTower = null;
                        targetPlayer = null;
                        return true;
                    }
                    break;
                case EnemyTargetType.LowHPDemonic:
                    demonic = searchTrigger.GetMinHPDemonic(canHitFly);
                    if (demonic != null)
                    {
                        targetDemonic = demonic;
                        targetTower = null;
                        targetPlayer = null;
                        return true;
                    }
                    break;
                case EnemyTargetType.Tower:
                    tower = searchTrigger.GetMinDisTower(out disTower);
                    if (tower != null)
                    {
                        targetDemonic = null;
                        targetTower = tower;
                        targetPlayer = null;
                        return true;
                    }
                    break;
                case EnemyTargetType.Player:
                    player = searchTrigger.GetPlayer(out disPlayer);
                    if (player != null)
                    {
                        targetDemonic = null;
                        targetTower = null;
                        targetPlayer = player;
                        return true;
                    }
                    break;
                default:
                    break;
            }
        }
        return false;
    }

    public void OnSearchState()
    {
        switch (searchState)
        {
            case SearchState.NoTarget:
                if (SearchTarget())
                {
                    ChangeSearchState(SearchState.InSearchScope);
                    break;
                }
                //向玩家基地移动
                break;
            case SearchState.InSearchScope:
                if (!SearchTarget())
                {
                    targetDemonic = null;
                    targetTower = null;
                    targetPlayer = null;
                    ChangeSearchState(SearchState.NoTarget);
                    break;
                }
                if (targetDemonic != null && Mathf.Abs(targetDemonic.transform.position.x - transform.position.x) <= attackDistance)
                {
                    ChangeSearchState(SearchState.InAttackScope);
                    break;
                }
                if (targetTower != null && Mathf.Abs(targetTower.transform.position.x - transform.position.x) <= attackDistance)
                {
                    ChangeSearchState(SearchState.InAttackScope);
                    break;
                }
                if (targetPlayer != null && Mathf.Abs(targetPlayer.transform.position.x - transform.position.x) <= attackDistance)
                {
                    ChangeSearchState(SearchState.InAttackScope);
                    break;
                }
                break;
            case SearchState.InAttackScope:
                if (targetDemonic != null && Mathf.Abs(targetDemonic.transform.position.x - transform.position.x) > attackDistance)
                {
                    ChangeSearchState(SearchState.NoTarget);
                    break;
                }
                if (targetTower != null && Mathf.Abs(targetTower.transform.position.x - transform.position.x) > attackDistance)
                {
                    ChangeSearchState(SearchState.NoTarget);
                    break;
                }
                if (targetPlayer != null && Mathf.Abs(targetPlayer.transform.position.x - transform.position.x) > attackDistance)
                {
                    ChangeSearchState(SearchState.NoTarget);
                    break;
                }
                break;
            default:
                break;
        }
    }

    public void BeHit(int damage, Vector3 force)
    {
        hp -= damage;
        uiHp.ShowHP(hp, totalHp);
        rb.AddForce(force);
        if (hp < 0)
        {
            ChangeState(EnemyState.Die);
        }
        else
        {
            ChangeState(EnemyState.Hurt);
        }
    }

    public void Attack1()
    {
        ani.Play("attack1", 0, 0);
        aniCollider.Play("Attack1", 1, 0);
        attackTime = totalAttack1Time;
        for (int i = 0; i < attack1Infos.Count; i++)
        {
            attackTriggers[i].damage = attack1Infos[i].damage;
            Vector3 attackDir = attack1Infos[i].attackDir.normalized;
            if (bodyTrans.localScale.x < 0)
            {
                attackDir.x = -attackDir.x;
            }
            attackTriggers[i].force = attackDir * attack1Infos[i].force;
        }
        ChangeState(EnemyState.Attack);
    }

    void Attack2()
    {
        ani.Play("attack2", 0, 0);
        aniCollider.Play("Attack2", 1, 0);
        attackTime = totalAttack2Time;
        for (int i = 0; i < attack2Infos.Count; i++)
        {
            attackTriggers[i].damage = attack2Infos[i].damage;
            Vector3 attackDir = attack2Infos[i].attackDir.normalized;
            if (bodyTrans.localScale.x < 0)
            {
                attackDir.x = -attackDir.x;
            }
            attackTriggers[i].force = attackDir * attack2Infos[i].force;
        }
        ChangeState(EnemyState.Attack);
    }

    void BeCreate(int tHp)
    {
        totalHp = tHp;
        hp = totalHp;
        ChangeState(EnemyState.Idle);
        ChangeSearchState(SearchState.NoTarget);
    }
}
