using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using TMPro;

public class GameManager : MonoBehaviour
{

    public static Action<Puck> OnSelectedPuckChanged;
    public static Action<Team> OnTeamChanged;
    public static bool isMoving{
        get{
            return instance.IsMoving();
        }
    }
    public bool m_isMoving =false;
    public static Team SelectedTeam = Team.Red;
    public static bool NoPuckSelected {
        get{
            return instance.selectedPuck == null;
        }
    }
    public EventTrigger gameInputPanel;
    public Rigidbody2D ball;
    public float puckForce = 1f;
    public float ballMoveTime = 3f;
    public float puckDragClamp = 5f;

    public int redScore,blueScore=0;

    [Header("UI")]
    public TMP_Text redScoreText;
    public TMP_Text blueScoreText;

    [Header("Misc")]
    public List<Puck> pucks = new List<Puck>();

    public static GameManager instance;
    void Awake()
    {
        instance = this;
    }

    void Start()
    {
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.PointerDown;
        entry.callback.AddListener(OnPointerDown);
        gameInputPanel.triggers.Add(entry);

        entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.PointerUp;
        entry.callback.AddListener(OnPointerUp);
        gameInputPanel.triggers.Add(entry);

        entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.Drag;
        entry.callback.AddListener(OnDrag);
        gameInputPanel.triggers.Add(entry);

        OnSelectedPuckChanged?.Invoke(null);
    }


    public void RegisterPuck(Puck puck){
        pucks.Add(puck);
    }

    public void DisposePuck(Puck puck){
        pucks.Remove(puck);
    }


    public Vector2 startPosition;
    public Vector2 curPosition;
    Puck selectedPuck;
    void OnPointerDown(BaseEventData eventData)
    {
        if(IsMoving()){return;} //Do not do anything if shits moving
        PointerEventData pointerEventData = eventData as PointerEventData;
        startPosition = pointerEventData.position;
        curPosition = startPosition;

        // Convert screen position to world position
        Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(pointerEventData.position.x, pointerEventData.position.y, Camera.main.nearClipPlane));
        
        // Find all pucks in the scene
        Puck[] pucks = FindObjectsOfType<Puck>();
        float minDistance = float.MaxValue;
        Puck closestPuck = null;

        foreach (Puck puck in pucks)
        {
            if(puck.team != SelectedTeam){continue;}
            float dist = Vector2.Distance(worldPosition, puck.transform.position);
            if (dist < minDistance)
            {
                minDistance = dist;
                closestPuck = puck;
            }
        }

        selectedPuck = closestPuck;
        OnSelectedPuckChanged?.Invoke(selectedPuck);
    }
    Coroutine coroutinePostLaunch;
    void OnPointerUp(BaseEventData eventData)
    {
        Debug.Log("Pointer up");
        PointerEventData pointerEventData = eventData as PointerEventData;
        Vector2 endPosition = pointerEventData.position;
        Vector2 direction = endPosition - startPosition;
        if(coroutinePostLaunch != null){
            StopCoroutine(coroutinePostLaunch);
        }
        coroutinePostLaunch = StartCoroutine(CoroutinePostLaunch());

        selectedPuck.GetComponent<Rigidbody2D>().AddForce(-direction * puckForce * Time.deltaTime, ForceMode2D.Impulse);

        startPosition = Vector2.zero;
        selectedPuck = null;
        OnSelectedPuckChanged?.Invoke(null);
        SelectedTeam = SelectedTeam == Team.Red ? Team.Blue : Team.Red;
        OnTeamChanged?.Invoke(SelectedTeam);
    }

    void OnDrag(BaseEventData eventData)
    {
        PointerEventData pointerEventData = eventData as PointerEventData;
        curPosition = pointerEventData.position;
    }


    IEnumerator CoroutinePostLaunch(){
        float t = 0;
        while ( t < 1){
            t += Time.deltaTime / ballMoveTime;
            ball.linearDamping = Mathf.Lerp(0, 10, t);
            yield return null;
        }
    }

    bool IsMoving(){
        if(freezeInput){return true;}
        float minMagnitude = 0.01f;
        foreach(Puck puck in pucks){
            if(puck.rb.linearVelocity.magnitude > minMagnitude){
                return true;
            }
        }

        if(ball.linearVelocity.magnitude > minMagnitude){
            return true;
        }

        return false;
    }

    void Update()
    {
      m_isMoving=IsMoving();   
    }

    public void OnGoal(Team team){
        freezeInput=true;

        if(team == SelectedTeam){
            blueScore++;
            blueScoreText.text = blueScore.ToString();
        }else{
            redScore++;
            redScoreText.text = redScore.ToString();
        }

        StartCoroutine(CoroutineOnGoal(team));
    }

    bool freezeInput = false;

    IEnumerator CoroutineOnGoal(Team team){
        if(coroutinePostLaunch!=null){
            StopCoroutine(coroutinePostLaunch);
        }

        float t=0;
        while(t < 1){
            t +=Time.deltaTime * 2f;
            ball.linearDamping = Mathf.Lerp(0, 100, t);
            yield return null;
        }

        yield return new WaitForSeconds(2f);

        Reset();
    }


    public void Reset()
    {
        StartCoroutine(CoroutineReset());
    }

    IEnumerator CoroutineReset(){
        float resetDuration = 0.5f;
        foreach(Puck puck in pucks){
            puck.Reset(resetDuration);
        }

        ball.GetComponent<Ball>().Reset(resetDuration);

        yield return new WaitForSeconds(resetDuration);

        freezeInput=false;
    }

}
