using System.Collections;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField]
    private float jumpForce;

    [SerializeField]
    private float jumpAccel;

    [SerializeField]
    private float jumpTime; //time player can ascend in seconds (for dynamic jumping)

    [SerializeField]
    private float smashCooldownTime; //time player can ascend in seconds (for dynamic jumping)

    [SerializeField]
    private LayerMask collisionLayers;

    [SerializeField]
    private float swapTime = 0.5f;

    [SerializeField]
    private float maxVelocity = 6.0f;

    private Rigidbody2D rb2D;
    private bool normalGravity;
    private bool justSwapped;
    private bool isGrounded;
    private KeyCode swapKey;
    private bool jumpDown;

    //ParticleSystem slamParticleSystem;
    private Animator animator;

    private SpriteRenderer spriteRenderer;
    private float jumpTimer; //used to count time in air in seconds(for dynamic jumping)
    private float smashCooldownTimer;
    private bool isJumping;
    private bool canIncreaseAltitude; //prevent player for ascending after reaching a peak
    private bool slamming; //if player is slamming the ground
    private bool canSwap;
    private Vector2 preSwapVel;
    private bool currentlySwapping;

    public bool isUp
    {
        get
        {
            return normalGravity;
        }
    }

    private void Awake()
    {
        rb2D = GetComponent<Rigidbody2D>();
        print("first awake");
        //rb2D.velocity = Vector2.zero;
        rb2D.velocity = Vector2.down*5.0f;
        normalGravity = true;
        justSwapped = false;
        isGrounded = false;
        jumpDown = false;
        currentlySwapping = false;
        swapKey = KeyCode.DownArrow;
        jumpTimer = 0.0f;
        animator = GetComponent<Animator>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        animator.Play("Run");
    }

    private void Update()
    {

        if (Input.GetKeyDown(KeyCode.Space) && !isGrounded && canSwap)
        {
            StartCoroutine(swapSides());
            canSwap = false;
        }

        jumpDown = Input.GetKey(KeyCode.Space);
        animator.SetFloat("yVelocity", rb2D.velocity.y);
    }



    private void FixedUpdate()
    {
        print(normalGravity);
        float missPlacement = Mathf.Abs(rb2D.position.x - WaveData.Instance.charPos);
        if (missPlacement > GameManager.Instance.dieMargin)
        {
            GameManager.Instance.Die();
        }
        if (missPlacement <= GameManager.Instance.dieMargin)
        {
            Vector2 newPos = rb2D.position;
            newPos.x = WaveData.Instance.charPos;
            rb2D.position = (newPos);
        }
        if (isGrounded ||
            (isJumping && !jumpDown))
        {
            isJumping = false;
            slamming = false;
        }

        bool ascending = false;


        int velocityCheckMultiplier = normalGravity ? 1 : -1;
        float yVelocity = rb2D.velocity.y;
        if (normalGravity)
        {
            if (yVelocity > 6.0f)
            {
                Vector2 newVel = rb2D.velocity;
                newVel.y = 6.0f;
                rb2D.velocity = newVel;
            }
        }

        if (!normalGravity)
        {
            if (yVelocity < -6.0f)
            {
                Vector2 newVel = rb2D.velocity;
                newVel.y = -6.0f;
                rb2D.velocity = newVel;
            }
        }
        if (!normalGravity && (rb2D.velocity.y >= 0.0f))
        {
            //print("Normal: " + rb2D.velocity.y);
            ascending = true;
        }

        if (normalGravity && (rb2D.velocity.y <= 0.0f))
        {
            //print("notnormal: " +rb2D.velocity.y);
            ascending = true;
        }

        if (!isGrounded && !currentlySwapping && isJumping)// && ascending)
        {
            canSwap = true;
        }

        if (jumpDown && isGrounded)
        {
            animator.Play("Jump");
            isJumping = true;
            jumpTimer = 0.0f;
            Vector2 forceDirection = normalGravity ? Vector2.up : Vector2.down;
            rb2D.AddForce(forceDirection * jumpForce, ForceMode2D.Impulse);
        }

        if (jumpDown && isJumping && jumpTimer < jumpTime)
        {
            Vector2 forceDirection = normalGravity ? Vector2.up : Vector2.down;
            rb2D.AddForce(forceDirection * jumpAccel, ForceMode2D.Force);
            jumpTimer += Time.fixedDeltaTime;
        }

        if (justSwapped)
        {
            spriteRenderer.flipY = !spriteRenderer.flipY;
            rb2D.gravityScale *= -1;
            Vector2 newVel = rb2D.velocity;
            newVel.y = preSwapVel.y * -1;
            rb2D.velocity = newVel;
            justSwapped = false;
            currentlySwapping = false;
            normalGravity = !normalGravity;
        }

        //if (Input.GetKeyDown(swapKey))
        //{
        //    if (isGrounded)
        //    {
        //        normalGravity = !normalGravity;
        //        transform.position *= -1;
        //        Physics2D.gravity *= -1;
        //        swapKey = normalGravity ? KeyCode.DownArrow : KeyCode.UpArrow; //if player swapped to normal gravity, he uses down to swap/slam
        //    }
        //    if (!isGrounded && !slamming)
        //    {
        //        Vector2 forceDirection = normalGravity ? Vector2.down : Vector2.up;
        //        rb2D.AddForce(forceDirection * 18.0f, ForceMode2D.Impulse);
        //        slamming = true;
        //    }
        //}
        //if (Input.GetKeyDown(KeyCode.LeftControl) && !(smashCooldownTimer > smashCooldownTime))
        //{
        //    smashCooldownTimer = 0.0f;
        //    animator.Play("Smash");
        //    jumpTimer = 0.0f;
        //    Vector2 forceDirection = normalGravity ? Vector2.up : Vector2.down;
        //    rb2D.AddForce(forceDirection * jumpForce, ForceMode2D.Impulse);
        //}
        //smashCooldownTime += Time.fixedDeltaTime;
    }

    private IEnumerator swapSides()
    {
        animator.SetTrigger("Swap");
        currentlySwapping = true;
        Vector3 originalPos = transform.position;
        preSwapVel = rb2D.velocity;
        Vector3 newPos = originalPos;
        newPos.y *= -1;
        float f = 0.0f;
        while (f < swapTime)
        {
            transform.position = Vector3.Lerp(originalPos, newPos, f / swapTime);
            f += Time.deltaTime;
            yield return null;
        }
        justSwapped = true;
    }

    private bool checkIfGrounded()
    {

        //Vector2 positionToCheck = useCurrentFrame ? (Vector2)transform.position : nextPosition;
        //positionToCheck.y -= extents.y / 2.0f;
        //Vector2 size = new Vector2(extents.x * 2, extents.y);
        //float angle = rb2D.rotation;
        //aboveCol = default(RaycastHit2D);
        //aboveColDiff = 10.0f;
        ////only need one result if the world is guaranteed to be tiled
        //RaycastHit2D[] boxHits = Physics2D.BoxCastAll(positionToCheck, size, angle, groundNormal * -1.0f, 0.02f, layerMask);



        //Vector2 size = new Vector2(1.0f - 0.2f, 1.0f);
        Vector2 size = new Vector2((GetComponent<Collider2D>().bounds.extents.x * 2) - 0.01f, GetComponent<Collider2D>().bounds.extents.y * 2);
        RaycastHit2D hit = Physics2D.BoxCast(rb2D.position, size, transform.eulerAngles.z, Vector2.down, 0.03f, collisionLayers);
        return (bool)hit;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {

        if (!isGrounded)
        {
            Debug.Log("Grounded");
            if (collision.GetComponent<WaveMiddle>())
            {
                GameManager.Instance.Die();
            }
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        
        if (collision.collider.GetComponent<WaveRenderer>())
        {
            isGrounded = true;
        }
    }
    private void OnCollisionExit2D(Collision2D collision)
    {

        if (collision.collider.GetComponent<WaveRenderer>())
        {
            isGrounded = false;
        }
    }

    private void OnDrawGizmos()
    {
    }
}