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

public class PlayerScript2 : MonoBehaviour
{

    public KeyCode[] keys;
    /*
     * order: left right jump
     */

    float jumptime;
    bool jumping;
    float jumpmoved;
    float lastmovevector;

    int jumpdir;

    bool freefall;
    float touchtime;
    float fallspeed;

    int dir;

    public int playernumber;

    public GameObject currentground;
    bool currentlyonground;

    List<float> lastys;

    bool leftground;
    bool rightground;

    Animator aniharva;
    bool gotsthemanims;

    GameObject freefallbound;

    bool dead;
    public AudioClip deadsound;

    bool movementstartedfromzero;
    float movementstartfromzerotime;
    bool stopped;

    float lastactualxspeed;

    float downingnorm;

    bool inair;

    bool justjump;
    bool finished;

    void Awake()
    {
        lastmovevector = 0;
        freefallbound = GameObject.Find("FreeFallBound");
        touchtime = Time.time;
        Animator[] anims = transform.GetComponentsInChildren<Animator>();
        if (anims.Length == 1)
        {
            aniharva = anims[0];
            gotsthemanims = true;
        }
    }

    public void LevelEnded()
    {
        //print("maybe something happens here");
        finished = true;
    }

    // Update is called once per frame
    void Update()
    {
        if (finished) { dir = 0; return;  }

        bool getkey = false;
        if (Input.GetKey(keys[0]))
        {
            getkey = true;
            dir = -1;
            if ((freefall || jumping) && leftground)
                dir = 0;
        }
        else if (Input.GetKey(keys[1]))
        {
            getkey = true;
            dir = 1;
            if ((freefall || jumping) && rightground)
                dir = 0;
        }
        else
        {
            dir = 0;
        }

        if (dir != 0 && stopped)
        {
            stopped = false;
            movementstartedfromzero = true;
            movementstartfromzerotime = Time.time;
        }

         // UnityEngine.Random.Range(-1, 2); }
        
        if(Time.time - jumptime > 0.25f)
        {
            if (dir != 0 && jumpdir != 0 && dir != jumpdir)
            {
                jumpdir = 0;
            }
        }

        if (getkey) { 
            if (!jumping && !freefall)
            {
                //GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.right *dir * 0.05f);
                
                lastmovevector = Mathf.MoveTowards(lastmovevector, dir*5, 0.05f);
                
                //GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.right * dir * 0.01f /* + Vector3.up*1f*/);
            }
            else //if (!freefall)
            {
                lastmovevector = Mathf.MoveTowards(lastmovevector, dir*5, 0.25f);
            }
            //else if (freefall)
            //{
            //    GetComponent<Rigidbody2D>().AddForce(Vector3.right * dir * 1f);
            //}
        }
        else
        {
            lastmovevector = Mathf.MoveTowards(lastmovevector, 0, 0.05f);
        }

        if ((Input.GetKeyDown(keys[2]) || justjump) && !jumping && (!freefall || (freefall && Time.time - touchtime < 0.3f && Time.time - jumptime > 0.3f)))
        {
            Jump();
            

        
            //GetComponent<Rigidbody2D>().gravityScale = 0;
            //GetComponent<Rigidbody2D>().velocity = new Vector3(lastmovevector,0,0);
        }

        if (Input.GetKeyUp(keys[2]) && !freefall)
        {
            FreeFall();
        }

        if (Input.GetKeyDown(keys[3]))
        {
            float r = GetComponent<ShowerScript>().myRadius;
            if (Mathf.Abs(r-4) < 0.001f) r = 2;
            else if (Mathf.Abs(r - 2) < 0.001f) r = 4;
            GetComponent<ShowerScript>().myRadius = r;
        }
        //print(freefall.ToString() + " " + fallspeed.ToString());

    }

    void Jump()
    {
        if (rightground && !leftground && !currentlyonground)
        {
            jumpdir = -1;
        }
        else if (leftground && !rightground && !currentlyonground)
        {
            jumpdir = 1;
        }
        else jumpdir = 0;

        freefall = false;
        jumptime = Time.time;
        jumping = true;
        jumpmoved = 0;
        currentground = null;
        currentlyonground = false;

        GetComponent<MusicPlayerScript>().PlayThisMany(3);
    }

    void FreeFall()
    {
        lastys = new List<float>();
        jumping = false;
        //GetComponent<Rigidbody2D>().gravityScale = 1;
        freefall = true;
        fallspeed = 0;
        currentground = null;
        currentlyonground = false;
        //GetComponent<Rigidbody2D>().velocity = Vector3.right * lastmovevector*0.25f;
    }

    void CancelFall()
    {
        touchtime = Time.time;
        freefall = false;
    }
    private void FixedUpdate()
    {

        if (dir == 0 && lastmovevector == 0 && !freefall && !jumping)
        {
            stopped = true;
            movementstartedfromzero = false;
        }

        if (!dead && freefallbound != null && transform.position.y < freefallbound.transform.position.y)
        {
            dead = true;
            freefallbound.GetComponent<FreeFallPlayer>().Play();
            freefall = true;
            return;
        }


        /*
        GameObject g = GameObject.CreatePrimitive(PrimitiveType.Cube);
        Destroy(g.GetComponent<Collider>());
        g.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
        g.transform.position = transform.position + Vector3.down * 0.45f + Vector3.left * 0.25f;*/

        leftground = false;
        for (float i = -0.4f; i <= 0.05f; i += 0.05f) // -0.425,0.125
        { 
            if (Physics2D.Raycast(transform.position + Vector3.up * i, Vector3.left, 0.28f, 1 << LayerMask.NameToLayer("Ground")))
            {
                leftground = true;
            }
        }
        rightground = false;
        for (float i = -0.4f; i <= 0.05f; i += 0.05f)
        {
            if (Physics2D.Raycast(transform.position + Vector3.up * i, Vector3.right, 0.28f, 1 << LayerMask.NameToLayer("Ground")))
            {
                rightground = true;
            }
        }


        //if (playernumber == 0) print(leftground.ToString() + " " + (currentlyonground).ToString() + " "+ rightground.ToString() + " "+ jumpdir.ToString());// print(freefall.ToString() + "\t" + jumping.ToString() + "\t" + (Time.time - touchtime).ToString());
        Vector3 followspeed = Vector3.zero;

        if (!freefall && currentground) followspeed = currentground.GetComponent<Velocitor>().GetVelocity();


        if (!jumping && !freefall)
        {
            //transform.position = transform.position + Vector3.right * dir * 0.1f;
            //print(followspeed);
            float spede = dir*5; /*Mathf.Abs(lastmovevector*2);
            spede = Mathf.Max(1, spede);
            spede = Mathf.Min(5, spede);
            spede = Mathf.Sign(dir) * spede;*/
            if (movementstartedfromzero && Time.time - movementstartfromzerotime < 0.6f)
                spede = dir*5*(Time.time - movementstartfromzerotime)/0.6f;

            lastactualxspeed = spede;
            if (Mathf.Abs(lastmovevector) > Mathf.Abs(lastactualxspeed)) lastmovevector = lastactualxspeed;
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.right * spede * 0.01f + followspeed);
        }

        if (!jumping && Time.time-touchtime > 0.1f && !freefall)
        {
            FreeFall();
            //GetComponent<Rigidbody2D>().velocity = Vector3.right * lastmovevector * 0.25f;
            //GetComponent<Rigidbody2D>().gravityScale = 1;
        
        }

        if ((jumping || freefall) && leftground && Mathf.Sign(lastmovevector) < 0) lastmovevector = 0;
        if ((jumping || freefall) && rightground && Mathf.Sign(lastmovevector) > 0) lastmovevector = 0;

        float downing = 0;
        downingnorm = 0;
        if (jumping || freefall)
        {
            if (jumping && Time.time - jumptime > 0.5f)
            {
                FreeFall();
            }
            else if (jumping)
            {
                if (jumpmoved < 40) {
                    float mmt = 0.2f;
                    //transform.position = transform.position + Vector3.up*mmt/2.2f*(1-jumpmoved*0.08f) +
                    //    lastmovevector*Vector3.right*0.01f;
                    downing = mmt / 2.2f * (1 - jumpmoved * 0.08f);
                    downingnorm = downing / (mmt / 2.2f);
                    GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.up * downing +
                        lastmovevector * Vector3.right * 0.01f /*+ Vector3.right*jumpdir*0.05f*/);
                    jumpmoved += mmt;
                }
            }
            else if (freefall)
            {
                fallspeed += 0.003f;
                if (fallspeed > 0.07f) fallspeed = 0.07f;


                lastys.Add(transform.position.y);
                if (lastys.Count > 5) lastys.RemoveAt(0);
                downing = -fallspeed;
                downingnorm = downing/0.07f;
                GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.up * downing +
                        lastmovevector * Vector3.right * 0.01f);

                if (fallspeed > 0.025f && lastys.Count == 5 && lastys[0] - lastys[4] < fallspeed*2)
                {
                    CancelFall();
                    //print("canceld " + (lastys[0] - lastys[4]).ToString() + " " + fallspeed.ToString());
                }

                //curry = transform.position.y;
                //movetry = transform.position.y - fallspeed;
                //transform.position = transform.position - Vector3.up * fallspeed +
                //        lastmovevector * Vector3.right * 0.01f;
            }
        }


        if (gotsthemanims)
        {
            
            aniharva.SetBool("inAir", (!currentlyonground && Mathf.Abs(downingnorm) > 0.07f));
            inair = (!currentlyonground && Mathf.Abs(downingnorm) > 0.07f);
            //if (!jumping && !freefall)
            //else

            //float spe = lastmovevector / 5;
            //if (Mathf.Sign(spe) != dir && !jumping && !freefall) spe = 0; 
            if (!freefall && !jumping)
                aniharva.SetFloat("xSpeed", lastactualxspeed);
            else
                aniharva.SetFloat("xSpeed", dir);
            //print(lastmovevector / 5);
            if (Mathf.Abs(downingnorm) > 0.07f)
            {
                float dd = downingnorm;
                if (dd > 0) dd = 1;// Mathf.Sqrt(dd);
                
                aniharva.SetFloat("ySpeed", dd);
            }
            else
                aniharva.SetFloat("ySpeed", 0);
            //print("kemm");

            
            //print((lastmovevector / 5) + " " + downingnorm);
        }
    }

    private void OnCollisionStay2D(Collision2D collision)
    {
        Vector3[] dirs = { Vector2.down, //new Vector2(-0.4f, -1) , new Vector2(0.4f, -1), new Vector2(-0.3f, -1),
        //new Vector2(-0.3f,-1),
            new Vector2(-0.075f,-1),new Vector2(0.075f,-1)};

        List<RaycastHit2D> rhs = new List<RaycastHit2D>();
        foreach(Vector3 v in dirs)
            rhs.Add(Physics2D.Raycast(transform.position, v, 0.5f, 1 << LayerMask.NameToLayer("Ground")));

        //print("isdot?");
        string s = "";
        foreach(RaycastHit2D rh in rhs)
        {
            s += rh.normal.ToString() + "\t";
            if (!rh) continue;
            if (Vector2.Dot(rh.normal, Vector2.up) < 0.5f) continue;
            //else print("wasdot");
            
            CancelFall();
            currentlyonground = true;
            if (rh.collider.gameObject.GetComponent<Velocitor>() != null) currentground = rh.collider.gameObject;
        }
        //if (playernumber == 1) print(s);


        //print(freefall);
        /*if (rh)
        {
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.down * 0.01f);
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.down * 0.01f);
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.down * 0.01f);
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.down * 0.01f);
            GetComponent<Rigidbody2D>().MovePosition(transform.position + Vector3.down * 0.01f);
        }*/

        // the below cancels jump if head hits
        if (jumping) {
            RaycastHit2D rhu = Physics2D.Raycast(transform.position, Vector2.up, 0.15f, 1 << LayerMask.NameToLayer("Ground"));
            RaycastHit2D rhu1 = Physics2D.Raycast(transform.position, Vector2.up+Vector2.right*0.05f, 0.15f, 1 << LayerMask.NameToLayer("Ground"));
            RaycastHit2D rhu2 = Physics2D.Raycast(transform.position, Vector2.up-Vector2.right * 0.05f, 0.15f, 1 << LayerMask.NameToLayer("Ground"));
            if (rhu || rhu1 || rhu2) FreeFall();
        }
    }

    private void OnGUI()
    {
        //if (playernumber == 0 && inair) //GUI.Label(new Rect(300,300 - downingnorm*100 ,300,300), (downingnorm).ToString());
         //   GUI.Label(new Rect(300, 300, 300, 300), freefall.ToString());
    }

}
// -0.15+-0.275 = -0.425,0.125
// 0.5 mol. suunt?
// 0.2 leveys


