using UnityEngine;
using System.Collections;

public class GamePlayManager : MonoBehaviour
{
    private enum State
    {
        Inactive,
        Intro,
        WaitForInput,
        TurnResult,
        GameFinished,
    };

    public PlayerController[] Players;

    public GameObject[] WinPlayer;
    public GameObject WinDraw;

    //private State _currentState;
    private IEnumerator _currentState;
    private int _roundCount;
    private float _inputTime;
    private LevelSpawner _levelSpawner;
    private CountdownTimer _timer;
    private int _winningPlayer;

    // Use this for initialization
    void Start()
    {
        _levelSpawner = GetComponent<LevelSpawner>();
    }

    // Update is called once per frame
    void Update()
    {

    }

    public void InitGame()
    {
        foreach (PlayerController player in Players)
        {
            player.Initialise(6, 3, 0);
        }

        _levelSpawner.InitLevel();

        Players[0].CurrentTarget = Players[1];
        Players[1].CurrentTarget = Players[0];
        _roundCount = 0;
        _inputTime = 2f;
        _winningPlayer = -1;

        Players[0].KeyInputs = new KeyCode[] { KeyCode.A, KeyCode.S, KeyCode.D };
        Players[0].PadInputs = new KeyCode[] { GetPadCode(1, 1), GetPadCode(1, 2), GetPadCode(1, 0) };

        Players[1].KeyInputs = new KeyCode[] { KeyCode.J, KeyCode.K, KeyCode.L };
        Players[1].PadInputs = new KeyCode[] { GetPadCode(2, 1), GetPadCode(2, 2), GetPadCode(2, 0) };

        foreach(GameObject winText in WinPlayer)
        {
            winText.SetActive(false);
        }

        WinDraw.SetActive(false);

        SetState(State.Intro);
    }

    public void SetTimerObject(CountdownTimer timer)
    {
        _timer = timer;
    }

    // Private methods.

    private void SetState(State newState)
    {
        if (_currentState != null)
        {
            StopCoroutine(_currentState);
        }

        switch (newState)
        {
            case State.Intro:
                _currentState = Intro();
                break;

            case State.WaitForInput:
                _currentState = WaitForInput();
                break;

            case State.TurnResult:
                _currentState = TurnResult();
                break;

            case State.GameFinished:
                _currentState = GameFinished();
                break;

            default:
                _levelSpawner.ClearLevel();

                foreach (GameObject winText in WinPlayer)
                {
                    winText.SetActive(false);
                }

                WinDraw.SetActive(false);

                _currentState = null;
                break;
        }

        if (_currentState != null)
        {
            StartCoroutine(_currentState);
        }
    }

    private IEnumerator Intro()
    {
        yield return null;

        SetState(State.WaitForInput);
    }

    private IEnumerator WaitForInput()
    {
        float currentTime = 0;

        while (_inputTime > currentTime)
        {
            _timer.SetCurrentTimeDelta(currentTime / _inputTime);

            foreach (var player in Players)
            {
                player.UpdateInput();
            }

            yield return null;

            currentTime += Time.deltaTime;
        }

        SetState(State.TurnResult);
    }

    private IEnumerator TurnResult()
    {
        yield return null;


        // Process Attacks

        foreach (PlayerController player in Players)
        {
            player.InputDisplay.SetActiveMove(player.GetNextMove());

            if (player.GetNextMove() == PlayerController.MoveType.Attack)
            {
                player.CurrentTarget.TakeDamage(1);
            }
        }

        foreach (PlayerController player in Players)
        {
            if (player.GetNextMove() == PlayerController.MoveType.Ritual)
            {
                player.IncreaseRitualLevel(1);
            }
        }

        foreach (PlayerController player in Players)
        {
            if (player.IsSummoning())
            {
                player.CurrentTarget.TakeSummonDamage();
            }
        }

        bool gameFinsihed = false;
        _winningPlayer = -1;

        if (Players[0].IsDead())
        {
            if (Players[1].IsDead())
            {
                // Draw

                gameFinsihed = true;
            }
            else
            {
                // Player 1 wins.

                _winningPlayer = 1;
                gameFinsihed = true;
            }
        }
        else if (Players[1].IsDead())
        {
            // Player 0 wins.

            _winningPlayer = 0;
            gameFinsihed = true;
        }

        foreach (PlayerController player in Players)
        {
            player.EndTurn();
        }

        bool turnActive = true;

        while (turnActive)
        {
            yield return null;

            turnActive = false;

            foreach (PlayerController player in Players)
            {
                if (player.IsTurnActive())
                {
                    turnActive = true;
                }
            }
        }

        // Next Turn.

       // Debug.Log("---END OF ROUND " + _roundCount + "-------");

        if (gameFinsihed)
        {
            Debug.Log("------GAME OVER-------");
            if (_winningPlayer == -1)
            {
                Debug.Log("------DRAW!-------");
            }
            else
            {
                Debug.Log("-----PLAYER " + (_winningPlayer + 1) + " WINS!!!!-----");
            }

            SetState(State.GameFinished);
        }
        else
        {
            float delay = 1f;

            while (delay > 0)
            {
                yield return null;
                delay -= Time.deltaTime;
            }

            _roundCount++;
            SetState(State.WaitForInput);
        }
    }

    private IEnumerator GameFinished()
    {
        if (_winningPlayer == -1)
        {
            WinDraw.SetActive(true);
        }
        else
        {
            WinPlayer[_winningPlayer].SetActive(true);
        }

        while (!Input.anyKeyDown)
        {
            yield return null;
        }

        SetState(State.Inactive);

        GameManager.instance.SetState(GameManager.State.TitleScreen);
    }

    private static KeyCode GetPadCode(int joystickIndex, int buttonIndex)
    {
        var keyString = ("Joystick" + joystickIndex + "Button" + buttonIndex);
        return (KeyCode)System.Enum.Parse(typeof(KeyCode), keyString);
    }
}
