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

public class PlayerController : MonoBehaviour{

    EnemyController[] enemies;
    public SceneLoader sceneLoader;

    public bool active;
    public GameObject otherPlayer;

    [Space]
    public GameObject bloodExplosion;

    [Space]
    public float shootSpeed = 2;
    public GameObject spiritPrefab;
    public float spawnOffset;

    [Space]
    public CinemachineVirtualCamera vCam;

    [Space]
    public float speed;
    [Range(0, .3f)] public float movementSmoothing = .05f;
    float horizontalMove;
    Vector2 velocity = Vector2.zero;

    [Header("Jump")]
    public float jumpForce;
    public float fallMultiplier = 2.5f;
    public float lowJumpMultiplier = 2f;
    float gravityScale;

    [Range(0, .3f)] public float jumpPressedRememberTime;
    float jumpPressedRemember;
    [Range(0, .3f)] public float groundedRememberTime;
    float groundedRemember;

    public Transform feetPos;
    [Range(0, .5f)] public float feetRadius;
    public LayerMask whatIsGround;
    bool isGrounded;
    bool wasGrounded;
    bool jump;

    [Header("Bounce")]
    public float bounceForce;
    public LayerMask whatIsBouncing;
    public float playerBounceForce;
    public LayerMask whatIsPlayerBouncing;
    bool bouncing;

    [Space]
    public Animator anim;
    public Animator bounce;
    public Animator lightController;

    Rigidbody2D rb2d;

    void Awake(){
        enemies = FindObjectsOfType<EnemyController>();
    }

    // Start is called before the first frame update
    void Start(){
        rb2d = GetComponent<Rigidbody2D>();
        gravityScale = rb2d.gravityScale;
        lightController.SetBool("Enabled", active);
    }

    bool canMove;
    int h;
    bool wasActive;

    // Update is called once per frame
    void Update(){
        if(active && !wasActive){
            foreach(EnemyController e in enemies){
                e.WhoIsPlayer(gameObject);
            }
            wasActive = true;
        }

        if (canMove){
            horizontalMove = Input.GetAxis("Horizontal") * speed;

            if (Input.GetAxisRaw("Horizontal") != 0){
                Flip(Input.GetAxisRaw("Horizontal"));
                h = Mathf.RoundToInt(Input.GetAxisRaw("Horizontal"));
            }

            if (Input.GetButtonDown("Fire1")){
                ShootSpirit((h == 0) ? 1 : h);
            }
        }else{
            horizontalMove = 0;
        }

        isGrounded = Physics2D.OverlapCircle(feetPos.position, feetRadius, whatIsGround);
        anim.SetBool("Grounded", isGrounded);

        if (active){
            canMove = true;
            lightController.SetBool("Enabled", true);
        }else{
            canMove = false;
            lightController.SetBool("Enabled", false);
        }

        #region Jump
        if (isGrounded && !wasGrounded){
            bounce.SetTrigger("Bounce");
            wasGrounded = true;
        }else if (!isGrounded){
            wasGrounded = false;
        }

        jumpPressedRemember -= Time.deltaTime;
        if (Input.GetButtonDown("Jump")){
            jumpPressedRemember = jumpPressedRememberTime;
        }

        groundedRemember -= Time.deltaTime;
        if (isGrounded){
            groundedRemember = groundedRememberTime;
            bouncing = false;
        }

        if ((jumpPressedRemember > 0) && (groundedRemember > 0)){
            if (canMove){
                jump = true;
                jumpPressedRemember = 0;
                groundedRemember = 0;
            }
        }
        #endregion

        bool isBouncing = Physics2D.OverlapCircle(feetPos.position, feetRadius, whatIsBouncing);

        if (isBouncing){
            Jump(bounceForce);
            bouncing = true;
            isBouncing = false;
        }

        bool isPlayerBouncing = Physics2D.OverlapCircle(feetPos.position, feetRadius, whatIsPlayerBouncing);

        if (isPlayerBouncing){
            Jump(playerBounceForce);
            otherPlayer.GetComponent<PlayerController>().PlayBounceAnimation();
            bouncing = true;
            isBouncing = false;
        }
    }

    void FixedUpdate(){
        Vector2 targetVelocity = new Vector2(horizontalMove, rb2d.velocity.y);
        rb2d.velocity = Vector2.SmoothDamp(rb2d.velocity, targetVelocity, ref velocity, movementSmoothing);
        anim.SetFloat("Velocity", Mathf.Abs(rb2d.velocity.x));

        #region Jump
        if(!bouncing && canMove){
            if (rb2d.velocity.y < 0){
                rb2d.gravityScale = fallMultiplier * gravityScale;
            }else if (rb2d.velocity.y > 0 && !Input.GetButton("Jump")){
                rb2d.gravityScale = lowJumpMultiplier * gravityScale;
            }else{
                rb2d.gravityScale = gravityScale;
            }
        }

        if (jump){
            Jump(jumpForce);
            jump = false;
        }
        #endregion
    }

    public void PlayBounceAnimation(){
        bounce.SetTrigger("Bounce");
    }

    void Jump(float force){
        bounce.SetTrigger("Bounce");
        rb2d.velocity = new Vector2(rb2d.velocity.x, 0);
        rb2d.AddForce(Vector2.up * force, ForceMode2D.Impulse);
    }

    void Flip(float h){
        transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x) * h, transform.localScale.y, transform.localScale.z);
    }

    void ShootSpirit(int direction){
        var spirit = Instantiate(spiritPrefab, transform.position, transform.rotation);
        Rigidbody2D rigidbody = spirit.GetComponent<Rigidbody2D>();

        spirit.transform.position += new Vector3(spawnOffset * direction, 0, 0);
        rigidbody.AddForce(new Vector2(shootSpeed * direction, 5), ForceMode2D.Impulse);

        vCam.Follow = spirit.transform;
        spirit.GetComponent<SpiritBall>().SetCamera(vCam, GetComponent<PlayerController>());

        foreach(EnemyController e in enemies){
            e.WhoIsPlayer(null);
        }
        wasActive = false;
        active = false;
    }

    void Die(){
        Instantiate(bloodExplosion, transform.position, Quaternion.identity);
        sceneLoader.LoadScene(0);
        gameObject.SetActive(false);
        otherPlayer.SetActive(false);
    }

    void OnTriggerEnter2D(Collider2D col){
        if(col.gameObject.tag == "InstantDeath"){
            Die();
        }
        if(col.gameObject.tag == "Win"){
            Time.timeScale = 0;
            sceneLoader.LoadScene(0);
        }
    }

    void OnCollisionEnter2D(Collision2D col){
        if(col.gameObject.tag == "Enemy"){
            Die();
        }
    }

    void OnDrawGizmos(){
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(feetPos.position, feetRadius);    
    }
}
