using System.Collections;
using UnityEngine;
using CorgiLabs.Utility;

public class InputHandler : MonoBehaviour
{
    private const int STICK_ROTATION_STEPS = 10;

    [SerializeField] private PlayerController[] m_Players;

    private float m_Horizontal;
    private float m_Vertical;

    private void Awake()
    {
        enabled = m_Players != null && m_Players.Length != 0;

        ServiceLocator.Provide(this);
    }

    private void OnEnable()
    {
        EventManager.StartListening(EventID.GameOver, OnGameOver);
    }

    private void OnDisable()
    {
        EventManager.StopListening(EventID.GameOver, OnGameOver);
    }

    private void OnGameOver()
    {
        enabled = false;
    }

    public void SetPlayers(PlayerController[] inPlayers)
    {
        m_Players = inPlayers;

        enabled = m_Players != null && m_Players.Length != 0;
    }

    public void RequireStickRotation(int playerIndex, Callback completionHandler)
    {
        StartCoroutine(StickRotationSampling(playerIndex, completionHandler));
    }

    public void RequireButtonMash(int playerIndex, int targetHits, float depleteDelay, Callback completionHandler)
    {
        StartCoroutine(ButtonMash(Controls.CONTROL_INTERACT[playerIndex], targetHits, depleteDelay, completionHandler));
    }

    private void Update()
    {
        for (int i = 0; i < m_Players.Length; i++)
        {
            m_Horizontal = Input.GetAxis(Controls.CONTROL_HORIZONTAL[i]);
            m_Vertical = Input.GetAxis(Controls.CONTROL_VERTICAL[i]);

            //Debug.Log(m_Horizontal + " " + m_Vertical);

            m_Players[i].SetVelocity(new Vector2(m_Horizontal, m_Vertical));

            if (Input.GetButtonDown(Controls.CONTROL_INTERACT[i]))
            {
                m_Players[i].Interact();
            }

            if (Input.GetButtonDown(Controls.CONTROL_GRAB[i]))
            {
                m_Players[i].Grab();
            }
        }

        //float x = Input.GetAxis("RotationX_0");
        //float y = Input.GetAxis("RotationY_0");

        //Debug.Log(x + "   " + y + "   " + Mathf.Atan2(y, x) * Mathf.Rad2Deg);
    }

    private IEnumerator StickRotationSampling(int playerIndex, Callback completionHandler)
    {
        float x;
        float y;

        float startingAngle = 0;
        float rotation = 0;

        float current = 0;
        float last = 0;
        int currentThreshold = 0;

        float step = 2 * Mathf.PI / STICK_ROTATION_STEPS;

        while (Application.isPlaying)
        {
            x = Input.GetAxis(Controls.ROTATION_X[playerIndex]);
            y = Input.GetAxis(Controls.ROTATION_Y[playerIndex]);

            if (x == 1 || x == -1 || y == 1 || y == -1)
            {
                StdAtan(y, x, out startingAngle);

                last = startingAngle;

                break;
            }

            yield return null;
        }

        while (currentThreshold < STICK_ROTATION_STEPS)
        {
            x = Input.GetAxis(Controls.ROTATION_X[playerIndex]);
            y = Input.GetAxis(Controls.ROTATION_Y[playerIndex]);

            if (x == 1 || x == -1 || y == 1 || y == -1)
            {
                StdAtan(y, x, out current);

                rotation = Mathf.Max(0, Mathf.Abs(startingAngle - (current <= startingAngle ? current + 2 * Mathf.PI : current)));

                if (!IsClockwise(last, rotation) && currentThreshold * step < rotation && rotation < (currentThreshold+1) * step)
                {
                    currentThreshold++;
                }

                Debug.Log("Valid: " + !IsClockwise(last, rotation) + " | Current is: " + currentThreshold + " | Rotation is: " + rotation * Mathf.Rad2Deg);

                last = rotation;
            }

            yield return null;
        }

        completionHandler?.Invoke();
    }

    private IEnumerator ButtonMash(string button, int targetHits, float depleteDelay, Callback completionHandler)
    {
        int hits = 0;

        float lastDeplete = Time.time;

        string message;

        while (hits < targetHits)
        {
            message = "";

            if (Input.GetButtonDown(button))
                hits++;

            if (Time.time - lastDeplete >= depleteDelay)
            {
                hits--;
                lastDeplete = Time.time;

                message = " | DEPLETED!";
            }

            message = "Hits: " + hits + message;

            Debug.Log(message);
            yield return null;
        }

        completionHandler?.Invoke();
    }

    private void StdAtan(float y, float x, out float angle)
    {
        angle = Mathf.Atan2(y,x);

        if (angle < 0) angle += 2 * Mathf.PI;
    }

    private bool IsClockwise(float from, float to)
    {
        float clockWise = 0f;
        float counterClockWise = 0f;

        if (from <= to)
        {
            counterClockWise = to - from;
            clockWise = from + 2 * Mathf.PI - to;
        }
        else
        {
            counterClockWise = 2* Mathf.PI - from + to;
            clockWise = from - to;
        }
        return clockWise <= counterClockWise;
    }
}
