using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    public static GameManager instance{get; private set;}
    void Awake(){
        instance=this;
    }
    public Rigidbody2D ball;
    public float holeCheckRadius =1;
    public Transform cam;
    public Vector3 camTargetPos;    
    public float cameraSmoothness = 0.1f;
    public Vector3 cameraOffset ;
    public float inputSensitivity = 100f;
    public float BallFriction = 0.1f;
    public float BallFrictionStop = 0.1f;
    public float StopVelocity = 0.01f;
    public float SlowVelocity = 1f;

    public float StopTime = 0.1f;

    public float curVelocity;
    public float forceMultiplier;
    public Transform ballProjection;
    public float ballProjectionScaleMin, ballProjectionScaleMax;


    [Header("Game")]
    public int MaxStrokes;
    [SerializeField]private int m_curStrokes;
    public int CurStrokes{get{return m_curStrokes;} set{ m_curStrokes=value; UpdateUI();}}
    private int m_curScore;
    public int Score{get {return m_curScore;} set{ m_curScore = value; UpdateUI(); }}
    public Text StrokesTxt;
    public Text ScoreTxt;
    public GameObject GameOverUI;
    public Animator HoleInOne;
    public int curHoleIndex;
    void Start()
    {
        camTargetPos = ball.transform.position;
        CurStrokes =1;
        lastPosition = ball.transform.position;
        ball.transform.position = LevelGenerator.holes[3].transform.position;
        Debug.Log("Moving ball to " + LevelGenerator.holes[3].transform.position);
        curHoleIndex = 2;
    }
    float stopCooldown = 0;
    public bool isGrounded;

    public static Vector3 lastPosition;

    void Update(){
        float distToFirst = ball.transform.position.x - LevelGenerator.holes[curHoleIndex].transform.position.x;
        float distToLast = LevelGenerator.holes[curHoleIndex+1].transform.position.x - ball.transform.position.x;

        if(distToFirst < -11 || distToLast < -11){
            //Out of bounds, return to safe
            ball.transform.position = lastPosition;
            ball.velocity=Vector2.zero;
            ball.simulated=false;
        }
    }
    void FixedUpdate(){
        Collider2D[] cols = Physics2D.OverlapCircleAll(ball.transform.position, holeCheckRadius);
        isGrounded=false;
        foreach(Collider2D col in cols){
            if(col.tag == "Ground"){
                isGrounded=true;
            }
        }

        curVelocity = ball.velocity.magnitude;
        ball.velocity = Vector2.Lerp(ball.velocity, new Vector2(0, ball.velocity.y), BallFriction);
        if(isGrounded){ ball.velocity = Vector2.Lerp(ball.velocity, new Vector2(0, ball.velocity.y), ball.velocity.y > 0 ? BallFrictionStop : BallFrictionStop/10f);}
        if(Mathf.Abs(ball.velocity.magnitude) <  StopVelocity){
            if(stopCooldown > StopTime){
                ball.simulated=false;
                CheckHole();
                lastPosition=ball.transform.position;
            }else{
                stopCooldown+=Time.deltaTime;
            }
        }else{
            stopCooldown=0;
        }
    }
    
    void LateUpdate()
    {
        cam.position = Vector3.Lerp(cam.position, new Vector3(camTargetPos.x, cam.position.y,cam.position.z) + cameraOffset, cameraSmoothness);
    }

    private static bool cancelledHole = false;
    public static void CancelHole(){
        cancelledHole = true;
    }

    void CheckHole(){
        
        Collider2D[] cols = Physics2D.OverlapCircleAll(ball.transform.position, holeCheckRadius);
        foreach(Collider2D col in cols){
            if(col.tag == "Hole"){
                Hole(col.transform.position);
                curHoleIndex++;
                camTargetPos = (Vector2)col.transform.position;
                Destroy(col.gameObject);
                break;
            }
        }

        //No hole found
        if(CurStrokes <=0){
            GameOverUI.SetActive(true);
        }
    }
    public static async void Hole(Vector2 position){
        while(instance.ball.simulated){
            await Task.Delay(100);
            if(cancelledHole){return;}
        }

        instance.ball.transform.position = position + new Vector2(0.6f, 0.75f);
        instance.Score++;

        if(instance.CurStrokes >= instance.MaxStrokes-1){
            instance.HoleInOne.CrossFadeInFixedTime("Play",0.01f);
            instance.Score++;
        }
        instance.CurStrokes = instance.MaxStrokes;

    }


    bool dragging = false;
    Vector2 startPos;
    public void OnMouseDown(BaseEventData e){
        if(CurStrokes <= 0){return;}
        if(ball.simulated){return;}
        PointerEventData ped = (PointerEventData) e as PointerEventData;

        startPos = ped.position;
        dragging = true;
    }

    public void OnMouseUp(BaseEventData e){
        if(CurStrokes <= 0){return;}

        PointerEventData ped = (PointerEventData) e as PointerEventData;
        if(dragging){
            Vector2 v = ((ped.position-startPos)/inputSensitivity);

            Shoot(v);
        }
        dragging = false;
        ballProjection.position = Vector3.zero;
    }

    void Shoot(Vector2 v){
        if(v.magnitude > 1){v = v.normalized;}
        stopCooldown=0;

        ball.simulated=true;
        ball.AddForce(-v * forceMultiplier);
        CurStrokes--;

        AudioManager.HitSfx(v.magnitude);
    }

    public void OnMouseDrag(BaseEventData e){
        if(CurStrokes <= 0){return;}

        if(ball.simulated){return;}

        ballProjection.position = ball.position;
        PointerEventData ped = (PointerEventData) e as PointerEventData;
        Vector2 v = ((ped.position-startPos)/inputSensitivity);
        // Debug.Log(v.magnitude);

        if(v.magnitude > 1){v = v.normalized;}

        Vector3 direction = (ped.position - startPos).normalized;
        float rot_z = Mathf.Atan2(direction.y,direction.x) * Mathf.Rad2Deg;
        ballProjection.rotation = Quaternion.Euler(0,0,rot_z+180);

        float scaleDiff = ballProjectionScaleMax - ballProjectionScaleMin;
        ballProjection.GetChild(0).localScale = new Vector3(ballProjection.GetChild(0).localScale.x,ballProjectionScaleMin + (scaleDiff*v.magnitude));
    }

    int _tempScore;
    int _tempStrokes;

    public void UpdateUI(){
        if(Score != _tempScore){
            LeanTween.scale(ScoreTxt.gameObject, ScoreTxt.transform.localScale * 1.5f , 0.5f).setEasePunch();
            _tempScore = Score;

        }
        
        if(CurStrokes != _tempStrokes){
            _tempStrokes = CurStrokes;
            LeanTween.scale(StrokesTxt.gameObject, StrokesTxt.transform.localScale * 1.5f, 0.5f).setEasePunch();
        }
        ScoreTxt.text = Score.ToString();
        StrokesTxt.text = CurStrokes.ToString();
    }


    void OnDrawGizmos(){
        Gizmos.DrawWireSphere(ball.transform.position, holeCheckRadius);
    }

    public void Restrt(){
        LoadingScreen.LoadLevel(SceneManager.GetActiveScene().name);
    }

    public void MainMenu(){
        LoadingScreen.LoadLevel("MainMenu");
    }

}
