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

public enum CharacterState
{
    None = 0,
    Idle = 1,
    Run = 2,
    Rise = 3,//空中上升
    Fall = 4,//空中下落
    Hurt = 5,
    Attack = 6,
    KeepAttack = 7,
    Summon = 8,
    Rush = 9,
    Sprint = 10,
    Die = 11,
    Weak = 12,
    PullRope = 13,
    Spirits = 14,   //召唤英灵
    Float = 15,   //空中漂浮
    FindPlayer = 16,    //寻找玩家
    ReadyToRush = 17,   //瞄准准备冲刺
    ReadyToDownRush = 18,   //准备落地冲刺
    DownRush = 19,  //落地冲刺
    FinishRush = 20,    //结束冲刺
    Coma = 21,      //昏迷
    RushAttack, //带攻击的冲刺
    Transfiguration = 23,   //变身
}

public enum AttackType
{
    Melee = 0,//近战
    Shoot = 1,//射击
    Dash = 2,   //英灵刺客
}

public enum HpUpType
{
    Degree = 0,
    Add = 1,
    Fixed = 2,
}

public class Character : MonoBehaviour
{
    public GameObject[] HitCols;

    public int cookNum;   //能做成多少串肉

    public SkeletonMecanim mecanim;
    public Skeleton skeleton;
    public MeshRenderer meshRenderer;

    public Animator ani;
    public Animator aniCollider;
    public Rigidbody rb;
    public Transform bodyTrans;
    public BeSearchTrigger beSearchTrigger;
    public UIHP uiHp;

    public CharacterState state;
    [HideInInspector]
    public float attackTime;
    public float totalAttack1Time = 0.5f;
    public float totalAttack2Time = 0.5f;

    public bool isNonAttack = false;

    public HpUpType hptp;
    public bool isDie = false;
    public int totalHp = 100;
    public int hp;
    public List<AttackInfo> attack1Infos;
    public List<AttackInfo> attack2Infos;
    public List<AttackTrigger> attackTriggers;
    public AttackType attackType;
    public GameObject bulletPrefab;
    public List<Transform> shootPos;
    [HideInInspector]
    public float dieKeepTime;
    public float totalDieKeepTime = 2f;
    public Character attackTarget;
    public bool shootTrack = false;
    [HideInInspector]
    public float invincibleTime;
    public float totalInvincibleTime = 2f;
    public Character targetCharacter;
    public List<Character> beTargetCharacter = new List<Character>(); //被哪些锁定
    public SearchTrigger searchTrigger;
    public List<TargetType> targetTypes;
    public bool canHitFly;
    public bool linked;
    public RopeJoint joint;
    public CharacterRope rope;

    public bool hasHpUp = false;

    private float toLargeSize = 0;
    private Vector3 speed = new Vector3(1, 1, 0);
    public bool beLarger = false;

    public bool attackToFloat = false;      //攻击使敌方漂浮

    public virtual void Init()
    {
        if (!mecanim)
        {
            mecanim = GetComponentInChildren<SkeletonMecanim>();
        }
        if (mecanim && skeleton == null)
        {
            skeleton = mecanim.skeleton;
        }
        if (!meshRenderer)
        {
            meshRenderer = mecanim.GetComponent<MeshRenderer>();
        }
        if (!ani)
        {
            ani = GetComponentInChildren<Animator>();
        }

        hp = totalHp;
        if (!isNonAttack)
        {
            uiHp.Show(hp, totalHp);
        }
        ChangeState(CharacterState.Idle);

        linked = false;
        if (joint)
        {
            Destroy(joint);
            joint = null;
        }
        if (rope)
        {
            rope = null;
        }
    }

    public virtual void FixedUpdate()
    {
        OnState();
    }

    private void OnEnable()
    {
        for (int i = 0; i < attackTriggers.Count; i++)
        {
            attackTriggers[i].gameObject.SetActive(false);
        }
    }

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

    public virtual void OnState()
    {

    }

    public virtual void ChangeState(CharacterState newState)
    {

    }

    public virtual void BeHit(int damage, Vector3 force, bool changeHurt, float repelValue)
    {
        if (invincibleTime > 0)
        {
            return;
        }
        hp -= damage;
        uiHp.Show(hp, totalHp);
        if (hp <= 0)
        {
            rb.AddForce(force);
            ChangeState(CharacterState.Die);
            return;
        }
    }

    public virtual void AttackShootEvent(int attackId, int shootId)
    {
        AttackInfo attackInfo;
        if (attackId == 1)
        {
            attackInfo = attack1Infos[shootId];
        }
        else
        {
            attackInfo = attack2Infos[shootId];
        }
        GameObject bulletObj = PoolManager.Instantiate(bulletPrefab);
        Bullet bullet = bulletObj.GetComponent<Bullet>();
        if (attackToFloat)
        {
            bullet.toFloat = true;
        }
        Vector3 attackDir = attackInfo.attackDir.normalized;
        if (bodyTrans.localScale.x < 0)
        {
            attackDir.x = -attackDir.x;
        }
        bullet.BeShoot(this, shootPos[shootId].position, attackDir, attackInfo.damage, attackInfo.force, attackInfo.changeHurt, attackInfo.repelValue, shootTrack, attackTarget ? attackTarget : null);
    }

    public virtual Vector3 GetMoveDir()
    {
        Vector3 moveDir = Vector3.zero;
        return moveDir;
    }

    public virtual void Attack1()
    {
        ani.Play("attack_summon", 0, 0);
        if (!isNonAttack)
        {
            aniCollider.Play("Attack1", 1, 0);
            attackTime = totalAttack1Time;
            switch (attackType)
            {
                case AttackType.Melee:
                    for (int i = 0; i < attack1Infos.Count; i++)
                    {
                        attackTriggers[i].damage = attack1Infos[i].damage;
                        attackTriggers[i].changeHurt = attack1Infos[i].changeHurt;
                        attackTriggers[i].repelValue = attack1Infos[i].repelValue;
                        Vector3 attackDir = attack1Infos[i].attackDir.normalized;
                        if (bodyTrans.localScale.x < 0)
                        {
                            attackDir.x = -attackDir.x;
                        }
                        attackTriggers[i].force = attackDir * attack1Infos[i].force;
                    }
                    break;
                case AttackType.Shoot:
                case AttackType.Dash:
                    break;

                default:
                    break;
            }
            ChangeState(CharacterState.Attack);
        }
    }

    public virtual void Attack2()
    {
        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();
            }
        }

        ani.Play("attack_march", 0, 0);
        aniCollider.Play("Attack2", 1, 0);
        attackTime = totalAttack2Time;
        switch (attackType)
        {
            case AttackType.Melee:
            case AttackType.Dash:
                for (int i = 0; i < attack2Infos.Count; i++)
                {
                    attackTriggers[i].damage = attack2Infos[i].damage;
                    attackTriggers[i].changeHurt = attack2Infos[i].changeHurt;
                    attackTriggers[i].repelValue = attack2Infos[i].repelValue;
                    Vector3 attackDir = attack2Infos[i].attackDir.normalized;
                    if (bodyTrans.localScale.x < 0)
                    {
                        attackDir.x = -attackDir.x;
                    }
                    attackTriggers[i].force = attackDir * attack2Infos[i].force;
                }
                break;
            case AttackType.Shoot:
                break;
            default:
                break;
        }
        ChangeState(CharacterState.Attack);
    }

    public void SetSortingOrder(int order)
    {
        meshRenderer.sortingOrder = order;
    }

    public void HpUp(float value, float larger)
    {
        int add = 0;
        switch (hptp)
        {
            case HpUpType.Degree:
                value = value / 100;
                add = (int)(totalHp * value);
                break;
            case HpUpType.Add:
                add = (int)value;
                break;
            case HpUpType.Fixed:
                add = (int)(totalHp - value);
                break;
        }
        totalHp += add;
        hp += add;
        uiHp.Show(hp, totalHp);
        float cur = transform.localScale.x;
        toLargeSize = cur * larger;
        beLarger = true;
    }

    public void Enlarge()
    {
        transform.localScale = Vector3.SmoothDamp(transform.localScale, new Vector3(1, 1, 1) * toLargeSize, ref speed, 0.3f);
        if (transform.localScale.x >= toLargeSize + 0.1f)
        {
            beLarger = false;
            transform.localScale = new Vector3(toLargeSize, toLargeSize, 1);
            toLargeSize = 0;
            //print(transform.localScale);
        }
    }
}
