using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine;
using Spine.Unity;
using UnityEngine.LowLevel;
using UnityEngine.Playables;
using System.ComponentModel;
using Unity.VisualScripting;
using System;

[Serializable]
public struct AttackInfo
{
    public int damage;
    public Vector3 attackDir;
    public float force;
}
public enum PlayerState
{
    None = 0,
    Idle = 1,
    Run = 2,
    Rise = 3,//空中上升
    Fall = 4,//空中下落
    Hurt = 5,
    Attack = 6,
    Summon = 7,
    Rush = 8,
    Die = 9,
}
public class PlayerController : 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 List<GameObject> demonicPrefabs;
    public List<Vector3> demonicSummonPos;

    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 float rushSpeed = 100;

    public PlayerState state = PlayerState.Idle;
    [HideInInspector]
    public float invincibleTime;
    public float totalInvincibleTime = 2f;
    [HideInInspector]
    public float canJumpTime; //离开平台后仍然可以跳跃的时间，用于提升手感
    public float leaveGroundCanJumpTime = 0.1f;
    [HideInInspector]
    public float cacheJumpTime; //即将落地时按下跳跃键不会跳跃，手感不好，缓存几帧，在这几帧内落地会立即跳跃;
    public float totalCacheJumpTime = 0.1f;
    [HideInInspector]
    public float hurtKeepTime;
    public float totalHurtKeepTime = 0.5f;
    [HideInInspector]
    public float attackTime;
    public float totalAttackTime = 0.5f;
    [HideInInspector]
    public float summonTime;
    public float totalSummonTime = 0.5f;
    [HideInInspector]
    public float cacheAttackTime; //无法攻击时按下攻击键不会攻击，手感不好，缓存几帧，在这几帧内落地会立即攻击;
    public float totalCacheAttackTime = 0.1f;
    [HideInInspector]
    public float cacheSummonTime; //无法召唤时按下召唤键不会召唤，手感不好，缓存几帧，在这几帧内落地会立即召唤;
    public float totalCacheSummonTime = 0.1f;
    [HideInInspector]
    public int cacheSummonId;
    [HideInInspector]
    public float rushTime;
    public float totalRushTime = 0.5f;
    [HideInInspector]
    public float cacheRushTime; //无法Rush时按下Rush键不会Rush，手感不好，缓存几帧，在这几帧内落地会立即Rush;
    public float totalCacheRushTime = 0.1f;
    [HideInInspector]
    public bool airJumped;

    public bool isDie = false;
    public int totalHp = 100;
    public int hp;
    public List<AttackInfo> attack1Infos;
    public List<AttackTrigger> attackTriggers;

    public bool btnJumpPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.Space) || isClickBtnJump;
        }
    }
    [HideInInspector]
    public bool isClickBtnJump;
    public bool btnRushPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.LeftShift) || isClickBtnRush;
        }
    }
    [HideInInspector]
    public bool isClickBtnRush;
    public bool btnSouthPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.K) || isClickBtnSouth;
        }
    }
    [HideInInspector]
    public bool isClickBtnSouth;
    public bool btnEastPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.L) || isClickBtnEast;
        }
    }
    [HideInInspector]
    public bool isClickBtnEast;
    public bool btnWestPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.J) || isClickBtnWest;
        }
    }
    [HideInInspector]
    public bool isClickBtnWest;
    public bool btnNorthPress
    {
        get
        {
            return Input.GetKeyDown(KeyCode.I) || isClickBtnNorth;
        }
    }
    [HideInInspector]
    public bool isClickBtnNorth;

    public Vector2 leftDir
    {
        get
        {
            int x = 0;
            int y = 0;
            if (Input.GetKey(KeyCode.A))
            {
                x--;
            }
            if (Input.GetKey(KeyCode.D))
            {
                x++;
            }
            if (Input.GetKey(KeyCode.S))
            {
                y--;
            }
            if (Input.GetKey(KeyCode.W))
            {
                y++;
            }
            return new Vector2(x, y);
        }
    }

    private void Awake()
    {
        if (!mecanim)
        {
            mecanim = GetComponentInChildren<SkeletonMecanim>();
            skeleton = mecanim.skeleton;
        }
        if (!ani)
        {
            ani = GetComponentInChildren<Animator>();
        }
        hp = totalHp;
        ChangeState(PlayerState.Idle);
        uiHp.ShowHP(hp, totalHp);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            isClickBtnRush = true;
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            isClickBtnJump = true;
        }
        if (Input.GetKeyDown(KeyCode.J))
        {
            isClickBtnWest = true;
        }
        if (Input.GetKeyDown(KeyCode.K))
        {
            isClickBtnSouth = true;
        }
        if (Input.GetKeyDown(KeyCode.L))
        {
            isClickBtnEast = true;
        }
        if (Input.GetKeyDown(KeyCode.I))
        {
            isClickBtnNorth = true;
        }
    }

    private void FixedUpdate()
    {
        OnState();
    }

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

    public void AirJump()
    {
        SetUpSpeed(airJumpSpeed);
        ani.Play("jump", 0, 0);
    }

    public void SetUpSpeed(float speed)
    {
        ChangeState(PlayerState.Rise);
        Vector3 velocity = rb.velocity;
        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 Turn()
    {
        bodyTrans.localScale = new Vector3(-bodyTrans.localScale.x, bodyTrans.localScale.y, bodyTrans.localScale.z);
    }

    //角色处于可自由活动状态时的通用切换状态逻辑，如Idle、Run状态，以及别的状态结束时准备回到Idle状态前
    public bool CheckPlayerChangeState(PlayerState excludeState = PlayerState.None)
    {
        if (!foot.TrigGround)
        {
            if (rb.velocity.y > 0)
            {
                if (excludeState != PlayerState.Rise)
                {
                    ChangeState(PlayerState.Rise);
                    return true;
                }
            }
            else
            {
                if (excludeState != PlayerState.Fall)
                {
                    ChangeState(PlayerState.Fall);
                    return true;
                }
            }
        }
        else
        {
            airJumped = false;
            if (btnWestPress || cacheAttackTime > 0)
            {
                if (excludeState != PlayerState.Attack)
                {
                    Attack1();
                    return true;
                }
            }
            if (cacheSummonTime > 0)
            {
                if (excludeState != PlayerState.Summon)
                {
                    Summon(cacheSummonId);
                    ChangeState(PlayerState.Summon);
                    return true;
                }
            }
            if (btnNorthPress)
            {
                if (excludeState != PlayerState.Summon)
                {
                    Summon(0);
                    ChangeState(PlayerState.Summon);
                    return true;
                }
            }
            if (btnSouthPress)
            {
                if (excludeState != PlayerState.Summon)
                {
                    Summon(1);
                    ChangeState(PlayerState.Summon);
                    return true;
                }
            }
            if (btnEastPress)
            {
                if (excludeState != PlayerState.Summon)
                {
                    Summon(2);
                    ChangeState(PlayerState.Summon);
                    return true;
                }
            }
            if (btnRushPress || cacheRushTime > 0)
            {
                if (excludeState != PlayerState.Rush)
                {
                    ChangeState(PlayerState.Rush);
                    return true;
                }
            }
            if (btnJumpPress || cacheJumpTime > 0)
            {
                if (excludeState != PlayerState.Rise)
                {
                    Jump();
                    ChangeState(PlayerState.Rise);
                    return true;
                }
            }
            if (leftDir.x > 0.3f || leftDir.x < -0.3f)
            {
                if (excludeState != PlayerState.Run)
                {
                    ChangeState(PlayerState.Run);
                    return true;
                }
            }
            else
            {
                if (excludeState != PlayerState.Idle)
                {
                    ChangeState(PlayerState.Idle);
                    return true;
                }
            }
        }
        return false;
    }

    void Attack1()
    {
        ani.Play("attack1", 0, 0);
        aniCollider.Play("Attack1", 1, 0);
        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(PlayerState.Attack);
    }

    public void CachedPlayerInput()
    {
        if (btnRushPress)
        {
            cacheRushTime = totalCacheRushTime;
        }
        if (btnJumpPress)
        {
            cacheJumpTime = totalCacheJumpTime;
        }
        if (btnWestPress)
        {
            cacheAttackTime = totalCacheAttackTime;
        }
        if (btnNorthPress)
        {
            cacheSummonTime = totalCacheSummonTime;
            cacheSummonId = 0;
        }
        if (btnSouthPress)
        {
            cacheSummonTime = totalCacheSummonTime;
            cacheSummonId = 1;
        }
        if (btnEastPress)
        {
            cacheSummonTime = totalCacheSummonTime;
            cacheSummonId = 2;
        }
    }

    public void OnState()
    {
        cacheJumpTime -= Time.deltaTime;
        cacheAttackTime -= Time.deltaTime;
        cacheSummonTime -= Time.deltaTime;
        canJumpTime -= Time.deltaTime;
        invincibleTime -= Time.deltaTime;
        hurtKeepTime -= Time.deltaTime;
        attackTime -= Time.deltaTime;
        summonTime -= Time.deltaTime;
        rushTime -= Time.deltaTime;
        cacheRushTime -= Time.deltaTime;
        switch (state)
        {
            case PlayerState.Idle:
                if (CheckPlayerChangeState(PlayerState.Idle))
                {
                    break;
                }
                canJumpTime = leaveGroundCanJumpTime;
                //rb.velocity = Vector3.zero;
                break;
            case PlayerState.Run:
                if (CheckPlayerChangeState(PlayerState.Run))
                {
                    break;
                }
                canJumpTime = leaveGroundCanJumpTime;
                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 PlayerState.Rise:
                if (btnRushPress || cacheRushTime > 0)
                {
                    ChangeState(PlayerState.Rush);
                    break;
                }
                if (rb.velocity.y <= 0)
                {
                    ChangeState(PlayerState.Fall);
                    break;
                }
                if (btnJumpPress || cacheJumpTime > 0)
                {
                    if (!airJumped && rb.velocity.y < airJumpSpeed)
                    {
                        airJumped = true;
                        AirJump();
                        break;
                    }
                }
                CachedPlayerInput();
                rb.velocity += Vector3.up * extraRiseGravity * Time.deltaTime;
                AirMove();
                break;
            case PlayerState.Fall:
                if (btnRushPress || cacheRushTime > 0)
                {
                    ChangeState(PlayerState.Rush);
                    break;
                }
                if (foot.TrigGround)
                {
                    if (CheckPlayerChangeState())
                    {
                        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 (canJumpTime > 0)
                    {
                        Jump();
                        break;
                    }
                    else if (!airJumped)
                    {
                        airJumped = true;
                        AirJump();
                        break;
                    }
                }
                CachedPlayerInput();
                rb.velocity += Vector3.up * extraFallGravity * Time.deltaTime;
                AirMove();
                break;
            case PlayerState.Hurt:
                if (hurtKeepTime <= 0)
                {
                    if (CheckPlayerChangeState())
                    {
                        break;
                    }
                }
                CachedPlayerInput();
                if (!foot.TrigGround)
                {
                    rb.velocity += Vector3.up * extraFallGravity * Time.deltaTime;
                }
                rb.velocity = rb.velocity / 5 * 4;
                break;
            case PlayerState.Attack:
                if (attackTime <= 0)
                {
                    if (CheckPlayerChangeState())
                    {
                        break;
                    }
                }
                CachedPlayerInput();
                break;
            case PlayerState.Summon:
                if (summonTime <= 0)
                {
                    if (CheckPlayerChangeState())
                    {
                        break;
                    }
                }
                
                break;
            case PlayerState.Rush:
                if (rushTime <= 0)
                {
                    if (CheckPlayerChangeState())
                    {
                        break;
                    }
                }
                CachedPlayerInput();
                if (bodyTrans.localScale.x > 0)
                {
                    rb.velocity = Vector3.left * rushSpeed;
                }
                else
                {
                    rb.velocity = Vector3.right * rushSpeed;
                }
                break;
            default:
                break;
        }
        isClickBtnRush = false;
        isClickBtnJump = false;
        isClickBtnSouth = false;
        isClickBtnEast = false;
        isClickBtnNorth = false;
        isClickBtnWest = false;
    }

    public void ChangeState(PlayerState newState)
    {
        switch (state)
        {
            case PlayerState.Idle:
                break;
            case PlayerState.Run:
                rb.velocity = Vector3.zero;
                break;
            case PlayerState.Rise:
                break;
            case PlayerState.Fall:
                rb.velocity = Vector3.zero;
                break;
            case PlayerState.Hurt:
                break;
            case PlayerState.Attack:
                aniCollider.Play("NotAttack", 1, 0);
                break;
            case PlayerState.Summon:
                break;
            case PlayerState.Rush:
                rb.velocity = Vector3.zero;
                break;
            case PlayerState.Die:
                isDie = false;
                break;
            default:
                break;
        }
        PlayerState oldState = state;
        state = newState;
        switch (newState)
        {
            case PlayerState.Idle:
                aniCollider.Play("Idle", 0, 0);
                if (oldState == PlayerState.Fall)
                {
                    ani.Play("fall_end", 0, 0);
                }
                else
                {
                    ani.Play("idle", 0, 0);
                }
                rb.velocity = Vector3.zero;
                //animalAni.SetInteger("state", (int)PlayerState.Idle);
                break;
            case PlayerState.Run:
                aniCollider.Play("Run", 0, 0);
                ani.Play("run_start", 0, 0);
                //animalAni.SetInteger("state", (int)PlayerState.Walk);
                break;
            case PlayerState.Rise:
                aniCollider.Play("Rise", 0, 0);
                canJumpTime = 0;
                break;
            case PlayerState.Fall:
                aniCollider.Play("Fall", 0, 0);
                ani.Play("fall", 0, 0);
                //animalAni.SetInteger("state", (int)PlayerState.Fall);
                break;
            case PlayerState.Hurt:
                aniCollider.Play("Hurt", 0, 0);
                ani.Play("hitted", 0, 0);
                hurtKeepTime = totalHurtKeepTime;
                invincibleTime = totalInvincibleTime;
                //ani.Play("Invincible", 2, 0);
                break;
            case PlayerState.Attack:
                attackTime = totalAttackTime;
                break;
            case PlayerState.Summon:
                aniCollider.Play("Summon", 0, 0);
                ani.Play("summon", 0, 0);
                summonTime = totalSummonTime;
                break;
            case PlayerState.Rush:
                aniCollider.Play("Rush", 0, 0);
                ani.Play("rush_loop", 0, 0);
                rushTime = totalRushTime;
                break;
            case PlayerState.Die:
                aniCollider.Play("Die", 0, 0);
                ani.Play("die", 0, 0);
                isDie = true;
                break;
            default:
                break;
        }
    }

    public void AirMove()
    {
        if (leftDir.x > 0.3f)
        {
            //rb.velocity += Vector3.right * airMoveAcc * 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 * airMoveAcc * 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();
            }
        }
        else
        {
            rb.velocity = new Vector3(0, rb.velocity.y, rb.velocity.z);
        }
    }

    public void Summon(int id)
    {
        print("Summon:" + id);
        if (id >= demonicPrefabs.Count)
        {
            Debug.LogError("未配置" + id + "号使魔");
            return;
        }
        if (id >= demonicSummonPos.Count)
        {
            Debug.LogError("未配置" + id + "号使魔召唤位置");
            return;
        }
        GameObject prefab = demonicPrefabs[id];
        GameObject demonicObj = Instantiate(prefab);
        Demonic demonic = demonicObj.GetComponent<Demonic>();
        demonicObj.transform.parent = null;
        demonicObj.transform.localEulerAngles = Vector3.zero;
        Vector3 offset = demonicSummonPos[id];
        if (bodyTrans.localScale.x > 0)
        {
            demonicObj.transform.position = transform.position + offset;
            demonicObj.transform.localScale = new Vector3(1, 1, 1);
        }
        else
        {
            demonicObj.transform.position = transform.position + new Vector3(-offset.x, offset.y, offset.z);
            demonicObj.transform.localScale = new Vector3(-1, 1, 1);
        }
        demonic.BeSummon(100);
        demonic.Attack1();
    }

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