using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;

[System.Serializable] public class Move : UnityEvent { }

public class PlayerController : MonoBehaviour{

    [SerializeField] GameObject deathParticles;
    [SerializeField] GameObject visualContainer;
    bool dead;
    [HideInInspector] public Move onMove;
    bool canMove = true;
    bool isWinding;

    [Range(0f, .3f)] [SerializeField] float movementSmoothingTime;
    [HideInInspector] public Vector3 positionToGo;
    Vector3 currentPosition;
    Vector3 velocity;

    Vector2 movementInput;
    bool hasMoved;
    bool moveAllowed;

    Animator anim;

    [SerializeField] LayerMask whatIsEnemy;

    [Space]
    bool alreadyBeenDamaged;
    bool lowHealth;
    [SerializeField] Volume damageVolume;
    [SerializeField] Volume lowHealthVolume;
    [SerializeField] int health = 9;
    [SerializeField] GameObject[] hearts;

    [SerializeField] GameOverCanvas gameOverCanvas;
    CanvasManager canvasManager;
    int movementsDone;
    int enemiesKilled;

    void Awake(){
        anim = GetComponent<Animator>();
        canvasManager = FindObjectOfType<CanvasManager>();
    }

    // Start is called before the first frame update
    void Start(){
        positionToGo = currentPosition = transform.position;
    }

    public void SetDifficulty(){
        moveAllowed = canvasManager.difficulty != CanvasManager.CanvasDifficulty.Hard;
        if (!moveAllowed){
            canvasManager.onHardMoveIn.AddListener(() => AllowHardMovment());
            canvasManager.onHardMoveOut.AddListener(() => DenyHardMovement());
        }
    }

    // Update is called once per frame
    void Update(){
        movementInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

        if (moveAllowed){
            if (canMove && !isWinding && !dead){
                if (movementInput == Vector2.zero){
                    hasMoved = false;
                }else if (movementInput != Vector2.zero && !hasMoved){
                    StartCoroutine(GetMovementDirection());
                    hasMoved = true;
                    canMove = false;
                }
            }
        }
        if(Vector3.Distance(transform.position, positionToGo) > .1f){
            transform.position = Vector3.SmoothDamp(transform.position, positionToGo, ref velocity, movementSmoothingTime);
        }else if(Vector3.Distance(transform.position, positionToGo) < .1f){
            transform.position = positionToGo;
        }

        damageVolume.weight -= Time.deltaTime;
        if (lowHealth){
            lowHealthVolume.weight = Mathf.PingPong(Time.time, 1);
        }

        if (health <= 0 && !dead){
            AudioManager.instance.PlayOneShot("Death", true);
            canvasManager.dead = true;

            hearts[0].SetActive(false);
            lowHealth = false;
            lowHealthVolume.weight = 0;

            gameOverCanvas.movementsDone = movementsDone;
            gameOverCanvas.enemiesKilled = enemiesKilled;
            gameOverCanvas.gameObject.SetActive(true);

            visualContainer.SetActive(false);
            Instantiate(deathParticles, transform.position + Vector3.up, Quaternion.identity);
            dead = true;
        }
    }

    IEnumerator GetMovementDirection(){
        movementsDone += 1;
        if(canvasManager.difficulty == CanvasManager.CanvasDifficulty.Hard){
            moveAllowed = false;
        }

        alreadyBeenDamaged = false;

        if(movementInput.x > 0){
            yield return new WaitForSeconds(.1f);
            if (movementInput.y > 0){
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(1.25f, 0, 0);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if(cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }else if(movementInput.y < 0){
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(0, 0, -1.25f);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if (cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }else{
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(1.25f, 0, -1.25f);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if (cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }
            anim.SetTrigger("Moving");
            onMove.Invoke();
            yield return new WaitForSeconds(.2f);
            canMove = true;
        }else if(movementInput.x < 0){
            yield return new WaitForSeconds(.1f);
            if (movementInput.y > 0){
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(0, 0, 1.25f);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if (cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }else if (movementInput.y < 0){
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(-1.25f, 0, 0);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if (cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }else{
                currentPosition = positionToGo;
                positionToGo = currentPosition + new Vector3(-1.25f, 0, 1.25f);
                Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                if (cols.Length != 0){
                    yield return new WaitForSeconds(.05f);
                    ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                    PlayYesOrYeah();
                    AudioManager.instance.PlayOneShot("Death", true);
                    enemiesKilled += 1;
                    cols[0].gameObject.SetActive(false);
                }
            }
            anim.SetTrigger("Moving");
            onMove.Invoke();
            yield return new WaitForSeconds(.2f);
            canMove = true;
        }else{
            if (movementInput.y > 0){
                yield return new WaitForSeconds(.1f);
                if (movementInput.x > 0){
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(1.25f, 0, 0);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }else if (movementInput.x < 0){
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(0, 0, 1.25f);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }else{
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(1.25f, 0, 1.25f);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }
                anim.SetTrigger("Moving");
                onMove.Invoke();
                yield return new WaitForSeconds(.2f);
                canMove = true;
            }else if(movementInput.y < 0){
                yield return new WaitForSeconds(.1f);
                if (movementInput.x > 0){
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(0, 0, -1.25f);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }else if (movementInput.x < 0){
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(-1.25f, 0, 0);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }else{
                    currentPosition = positionToGo;
                    positionToGo = currentPosition + new Vector3(-1.25f, 0, -1.25f);
                    Collider[] cols = Physics.OverlapSphere(positionToGo, .3f, whatIsEnemy);
                    if (cols.Length != 0){
                        yield return new WaitForSeconds(.05f);
                        ObjectPooler.instance.SpawnFromPool("EnemyDeath", new Vector3(positionToGo.x, 1, positionToGo.z), Quaternion.identity);
                        PlayYesOrYeah();
                        AudioManager.instance.PlayOneShot("Death", true);
                        enemiesKilled += 1;
                        cols[0].gameObject.SetActive(false);
                    }
                }

                anim.SetTrigger("Moving");
                onMove.Invoke();
                yield return new WaitForSeconds(.2f);
                canMove = true;
            }
        }
    }

    void PlayYesOrYeah(){
        float canRandomPlay = Random.Range(0, 100);
        if (canRandomPlay > 20 && canRandomPlay < 80){
            float whichPlay = Random.Range(0, 100);
            if (whichPlay > 50){
                AudioManager.instance.Play("Yes", true);
            }else{
                AudioManager.instance.Play("Yeah", true);
            }
        }
    }

    public void PlayMoveSoundRandomPitch(){
        AudioManager.instance.Play("PlayerStep", true);
    }

    public void StartWind(){
        currentPosition = positionToGo;
        isWinding = true;
        alreadyBeenDamaged = false;
    }

    public void MoveWind(Vector3 direction, int grids){
        positionToGo = transform.position + direction * grids;
        AudioManager.instance.Play("WindMove", true);
    }

    public void EndWind(){
        isWinding = false;
    }

    public void Damage(){
        if (!alreadyBeenDamaged){
            if (health > 0){
                hearts[health - 1].SetActive(false);
                health--;
                if (health <= 3){
                    lowHealth = true;
                }
                if (health > 1){
                    damageVolume.weight = 1;
                }

                alreadyBeenDamaged = true;
            }
        }
    }

    void OnCollisionEnter(Collision col){
        if (col.gameObject.layer == Mathf.RoundToInt(Mathf.Log(whatIsEnemy.value, 2)) && isWinding){
            BishopController bishop = col.gameObject.GetComponent<BishopController>();
            KnightController knight = col.gameObject.GetComponent<KnightController>();
            PawnController pawn = col.gameObject.GetComponent<PawnController>();
            RookController rook = col.gameObject.GetComponent<RookController>();
            if (bishop != null){
                if (bishop.positionToGo == positionToGo){
                    positionToGo = currentPosition;
                    Damage();
                }
            }else if (knight != null){
                if (knight.positionToGo == positionToGo){
                    positionToGo = currentPosition;
                    Damage();
                }
            }else if (pawn != null){
                if (pawn.positionToGo == positionToGo){
                    positionToGo = currentPosition;
                    Damage();
                }
            }else if (rook != null){
                if (rook.positionToGo == positionToGo){
                    positionToGo = currentPosition;
                    Damage();
                }
            }
        }
    }

    void AllowHardMovment(){
        moveAllowed = true;
    }

    void DenyHardMovement(){
        if (moveAllowed){
            onMove.Invoke();
            moveAllowed = false;
        }
    }

    void OnTriggerEnter(Collider col){
        if (col.CompareTag("Limits")){
            positionToGo = currentPosition;
        }
    }

    void OnDrawGizmos(){
        if (!Application.isPlaying){
            Gizmos.DrawWireSphere(transform.position + new Vector3(0, 0, 1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(0, 0, -1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(1.25f, 0, 1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(1.25f, 0, -1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(1.25f, 0, 0), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(-1.25f, 0, 1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(-1.25f, 0, -1.25f), .3f);
            Gizmos.DrawWireSphere(transform.position + new Vector3(-1.25f, 0, 0), .3f);
        }
    }
}
