using GamepadInput;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using UnityEngine.EventSystems;

public class PartyController : MonoBehaviour
{
    #region ATTRIBUTES
    public delegate void PlayerChanged(int playerIndex);
    public delegate void PlayersReady();

    public static event PlayersReady AllPlayersReady;
    public static event PlayerChanged PlayerAdded;
    public static event PlayerChanged PlayerReady;
    public static event PlayerChanged PlayerNotReady;
    public static event PlayerChanged PlayerRemoved;
    public static event PlayerChanged PlayerCharacterChanged;

    /*Arreglo con los jugadores*/
    public List<PlayerInput> players;

    /*Utilizada para controlar el acceso de los jugadores*/
    public int currentControllerIndex = 0;

    /*Referencia estatica para acceder*/
    public static PartyController Instance;

    /*No necesaria*/
    public bool playersReady = false;

    public bool[] coldDowns = new bool[] { true, true, true, true };

    /*Establece si se pueden leer las entradas*/
    public bool readingControls = false;

    public GamePad.Index[] controllers = new GamePad.Index[] { GamePad.Index.One, GamePad.Index.Two, GamePad.Index.Three, GamePad.Index.Four };

    public KeyCode cancelButton = KeyCode.Escape;
    public KeyCode joinButton = KeyCode.Space;
    #endregion

    IEnumerator StarColdDown(int control)
    {
        coldDowns[control] = false;
        yield return new WaitForSeconds(.3f);
        coldDowns[control] = true;
    }

    /*Check if controller has joinned*/
    public bool IsControllIn(bool keyb, GamePad.Index k)
    {
        if (players == null || players.Count == 0)
            return false;
        for (int i = 0; i < players.Count; i++)
        {
            if (keyb)
            {
                if (players[i].useKeyboard)
                    return true;
            }
            else
            {
                if (players[i].controlIndex == k)
                    return true;
            }
        }
        return false;
    }

    private void Start()
    {
        if (Instance)
        {
            Destroy(Instance.gameObject);
        }
        players = new List<PlayerInput>();
        Instance = this;
        DontDestroyOnLoad(gameObject);
        readingControls = true;
    }

    private void ChangeCharacter(bool useKeyboard, GamepadInput.GamePad.Index playerIndex, int direction)
    {
        for (int i = 0; i < players.Count; i++)
        {
            if(!coldDowns[i]){
                continue;
            }
            if (!players[i].ready)
                if ((players[i].useKeyboard && useKeyboard) || (!useKeyboard && players[i].controlIndex == playerIndex))
                {
                    StartCoroutine(StarColdDown(i));
                    players[i].selectedCharacter += direction;
                    if (players[i].selectedCharacter > 4)
                        players[i].selectedCharacter = 0;
                    if (players[i].selectedCharacter < 0)
                        players[i].selectedCharacter = 4;
                    if (PlayerCharacterChanged != null)
                    {
                        PlayerCharacterChanged(players[i].realIndex);
                    }
                }
        }
    }

    private void Update()
    {
        if (readingControls)
        {
            foreach (var item in controllers)
            {
                if (GamePad.GetAxis(GamePad.Axis.LeftStick, item).x > 0)
                    ChangeCharacter(false, item, 1);
                if (GamePad.GetAxis(GamePad.Axis.LeftStick, item).x < 0)
                    ChangeCharacter(false, item, -1);
            }
            if (Input.anyKeyDown)
            {
                if (Input.GetKeyDown(cancelButton))
                {
                    if (IsControllIn(true, GamePad.Index.Any))
                    {

                        RemovePlayer(true, GamePad.Index.Any);
                    }
                }
                if (Input.GetAxis("Horizontal") > 0)
                {
                    ChangeCharacter(true, GamePad.Index.Any, 1);
                }
                if (Input.GetAxis("Horizontal") < 0)
                {
                    ChangeCharacter(true, GamePad.Index.Any, -1);
                }
                if (Input.GetKeyDown(joinButton))
                {
                    if (!IsControllIn(true, GamePad.Index.Any))
                    {
                        AddPlayer(true, GamePad.Index.Any);

                        Debug.Log("Keyboard added");
                    }
                    else
                    {
                        for (int i = 0; i < players.Count; i++)
                        {
                            if (players[i].useKeyboard)
                            {
                                if (PlayerReady != null)
                                    PlayerReady(i);
                                players[i].ready = true;
                            }
                        }
                    }
                }

                foreach (var item in controllers)
                {
                    CheckController(item);
                    CheckControllerQuit(item);
                }

                if (players != null)
                {
                    var res = players.Count > 1;

                    for (int i = 0; i < players.Count; i++)
                    {
                        res &= players[i].ready;
                    }

                    playersReady = res;
                    if (playersReady)
                    {
                        readingControls = false;
                        if (AllPlayersReady != null)
                            AllPlayersReady();

                    }
                }
            }

        }

    }

    /*Check players lock*/
    private void CheckController(GamePad.Index index)
    {
        if (GamePad.GetButtonDown(GamePad.Button.A, index))
        {
            if (!IsControllIn(false, index))
            {
                AddPlayer(false, index);

                Debug.Log("Control added");
            }
            else
            {
                for (int i = 0; i < players.Count; i++)
                {
                    if (players[i].controlIndex == index)
                    {
                        if (PlayerReady != null)
                            PlayerReady(i);
                        players[i].ready = true;
                    }
                }
            }
        }


    }

    private void CheckControllerQuit(GamePad.Index index)
    {
        if (GamePad.GetButtonDown(GamePad.Button.B, index))
        {
            if (IsControllIn(false, index))
            {
                RemovePlayer(false, index);
            }
        }
    }

    private void RemovePlayer(bool usek, GamePad.Index index)
    {
        if (usek)
        {
            for (int i = 0; i < players.Count; i++)
            {
                if (players[i].ready && players[i].useKeyboard)
                {
                    players[i].ready = false;
                    if (PlayerNotReady != null)
                        PlayerNotReady(i);
                    return;
                }
            }
        }
        else
        {
            for (int i = 0; i < players.Count; i++)
            {
                if (players[i].ready && !players[i].useKeyboard && players[i].controlIndex == index)
                {
                    players[i].ready = false;
                    if (PlayerNotReady != null)
                        PlayerNotReady(i);
                    return;
                }
            }
        }
        if (!usek)
            currentControllerIndex--;
        PlayerInput cont;
        if (usek)
        {
            cont = (from p in players where p.useKeyboard == usek select p).First();

        }
        else
        {
            cont = (from p in players where p.useKeyboard == false && p.controlIndex == index select p).First();
        }
        for (int i = cont.realIndex + 1; i < players.Count; i++)
        {
            players[i].realIndex--;

        }
        players.Remove(cont);
        if (PlayerRemoved != null)
            PlayerRemoved(cont.realIndex);
    }

    private void AddPlayer(bool usek, GamePad.Index index)
    {
        if (players == null)
            players = new List<PlayerInput>();
        if (!usek)
            currentControllerIndex++;

        var cont = new PlayerInput();
        cont.controlIndex = index;
        cont.realIndex = players.Count;
        cont.useKeyboard = usek;
        cont.ready = false;

        players.Add(cont);
        if (PlayerAdded != null)
            PlayerAdded(cont.realIndex);
        if (PlayerNotReady != null)
            PlayerNotReady(cont.realIndex);
        if (PlayerCharacterChanged != null)
            PlayerCharacterChanged(cont.realIndex);

    }

    IEnumerator DetectControllers()
    {
        playersReady = false;
        yield return new WaitForSeconds(1);
        readingControls = true;
    }
    
    void ComoLeerEntradas()
    {
        //Para entrar es space o (a,x)
        //para desconectar un control es escape o back
        //los jugadores estan en el array players
        //Saber de cual jugador vamos a pedir las entradas   jugador=1 -> 0

        //Saber si se trata de un jugador con teclado
        if (players[0/*jugador*/].useKeyboard)
        {
            //En este caso simplemente utilizar el sistema de unity
            var res = Input.GetButton("Jump");
            //O
            var resKey = Input.GetKeyDown(KeyCode.A);
        }
        else//El jugador esta utilizando controll
        {
            var res = GamePad.GetButtonDown(GamePad.Button.A, players[0/*jugador*/].controlIndex);
        }
    }

    
}
