using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using RelicGGJ;
using Rewired;

[System.Serializable]
public class GameManager : MonoBehaviour
{

    public Text m_scoreText;
    public Text m_winText;
    public Text m_loseText;

    [SerializeField] public LayerReferences.objArray[] m_layerObjects;

    public static GameManager Instance;

    public PlayerController m_player;
    public LevelLayerFiles.objArray[] m_levelFiles;
    public GridController[] m_levels;
    public GameObject m_levelPrefab;
    public GridController m_currentLevel;
    public int m_levelIndex;

    public Player m_rewiredPlayer;
    public int m_rewiredPlayerIndex = 0;

    public int m_score = 0;

    static bool m_initialized = false;
    
    // Do game-winning stuff here.
    public void Win(GridObject source)
    {
        if (m_winText != null)
        {
            m_winText.text = m_winText.text + m_score.ToString();
        }
        Vibrate(1f, 2.0f);
        PlayerController.Instance.m_level = null;
        StartCoroutine(FlashPlayer(source.GetComponent<SpriteRenderer>(), new Color(0f, 1f, 0f, 0.4f), m_winText));
    }

    void Vibrate(float intensity, float duration)
    {
        foreach (Joystick j in m_rewiredPlayer.controllers.Joysticks)
        {
            if (!j.supportsVibration)
            {
                continue;
            }
            if (j.vibrationMotorCount > 0)
            {
                j.SetVibration(0, intensity, duration);
            }
            if (j.vibrationMotorCount > 1)
            {
                j.SetVibration(1, intensity, duration);
            }
        }
    }

    IEnumerator FlashPlayer(SpriteRenderer endObject, Color playerColor, Text displayText)
    {
        SpriteRenderer playerSprite = PlayerController.Instance.GetComponent<SpriteRenderer>();
        GameObject floorTile = m_currentLevel.GetObjectAt(PlayerController.Instance.m_position.x, 
            PlayerController.Instance.m_position.y, gridLayer.BACKGROUND);
        if (floorTile != null)
        {
            SpriteRenderer floorSprite = floorTile.GetComponent<SpriteRenderer>();
            if (floorSprite != null)
            {
                floorSprite.color = Color.black;
            }
        }
        endObject.gameObject.SetActive(true);
        playerSprite.color = playerColor;
        if (playerSprite != null)
        {
            float totalFlashTime = 3.0f;
            float perFlashTime = 0.25f;
            float flashElapsed = 0.0f, totalElapsed = 0.0f;
            while (totalElapsed < totalFlashTime)
            {
                endObject.color = Color.white;
                flashElapsed += Time.deltaTime;
                totalElapsed += Time.deltaTime;
                if (flashElapsed >= perFlashTime)
                {
                    flashElapsed = 0.0f;
                    if (playerSprite.color == playerColor)
                    {
                        playerSprite.color = Color.black;
                    }
                    else
                    {
                        playerSprite.color = playerColor;
                    }
                }
                yield return null;
            }
            Destroy(endObject.gameObject);
        }
        
        m_initialized = false;
        Destroy(PlayerController.Instance.gameObject);
        if (displayText != null)
        {
            displayText.gameObject.SetActive(true);
        }
    }

    // Do game-losing stuff here.
    public void Lose(GridObject source)
    {
        if (m_loseText != null)
        {
            m_loseText.text = m_loseText.text + "\nFinal Score: " + m_score.ToString();
            
        }
        Vibrate(0.5f, 3.0f);
        PlayerController.Instance.m_level = null;
        StartCoroutine(FlashPlayer(source.GetComponent<SpriteRenderer>(), new Color(1f, 0f, 0f, 0.6f), m_loseText));
        
    }

    public void AddScore(int score)
    {
        m_score += score;
        m_scoreText.text = "Score: " + m_score.ToString();
    }

	// Use this for initialization
	void Awake ()
    {
        m_rewiredPlayer = ReInput.players.GetPlayer(m_rewiredPlayerIndex);
        m_scoreText.text = "Score: " + m_score.ToString();
        if (Instance == null)
        {
            Instance = this;
		    if (!m_initialized)
            {
                m_levels = new GridController[m_levelFiles.Length];

                GameObject obj = Instantiate(m_levelPrefab) as GameObject;
                obj.transform.parent = transform;
                m_currentLevel = obj.GetComponent<GridController>();
                if (m_currentLevel != null)
                {
                    m_currentLevel.m_levelFile = new TextAsset[(int)gridLayer.COUNT];
                    for (int i = (int)gridLayer.BACKGROUND; i < (int)gridLayer.COUNT; ++i)
                    {
                        m_currentLevel.m_levelFile[i] = m_levelFiles[0].arr[i];                       
                    }
                    if (m_currentLevel.Load())
                    {
                        m_levels[0] = m_currentLevel;
                        m_initialized = true;
                        m_levelIndex = 0;
                    }
                }    
            }
        }
        else
        {
            Destroy(gameObject);
        }
            
    }

    public void ChangeLevelNumber(int levelIndex)
    {
        if (levelIndex > m_levels.Length - 1 || levelIndex < 0)
        {
            Debug.Log("Could not go to level. Out of range!");
            return;
        }

        bool exitUp = levelIndex <= m_levelIndex;
        m_levelIndex = levelIndex;

        m_currentLevel.SetObjectAt(PlayerController.Instance.m_position.x, PlayerController.Instance.m_position.y, 
            null, gridLayer.PLAYER);

        PlayerController.Instance.m_level = null;

        m_currentLevel.gameObject.SetActive(false);
        m_currentLevel = null;
        if (m_levels[m_levelIndex] == null)
        {
            GameObject obj = Instantiate(m_levelPrefab) as GameObject;
            obj.transform.parent = transform;
            m_currentLevel = obj.GetComponent<GridController>();
            m_levels[m_levelIndex] = m_currentLevel;
            if (m_currentLevel != null)
            {
                PlayerController.Instance.m_level = m_currentLevel;
                m_currentLevel.m_levelFile = new TextAsset[(int)gridLayer.COUNT];
                for (int i = (int)gridLayer.BACKGROUND; i < (int)gridLayer.COUNT; ++i)
                {
                    m_currentLevel.m_levelFile[i] = m_levelFiles[m_levelIndex].arr[i];
                }
                m_currentLevel.Load(exitUp ? enteredFrom.DOWN : enteredFrom.UP);
            }
        }
        else
        {
            m_currentLevel = m_levels[m_levelIndex];
            m_currentLevel.gameObject.SetActive(true);
            m_currentLevel.ReenterLevel(exitUp ? false : true);
        }
    }

    public void ChangeLevel(bool exitUp)
    {
        if (exitUp)
        {
            if (m_levelIndex > 0)
            {
                ChangeLevelNumber(m_levelIndex - 1);
            }
        }
        else
        {
            if (m_levelIndex < m_levels.Length - 1)
            {
                ChangeLevelNumber(m_levelIndex + 1);
            }
        }
    }
	
	// Update is called once per frame
	void Update ()
    {
        if (m_rewiredPlayer.GetButtonUp("Back"))
        {
            if (m_initialized == false)
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
            }
            else
            {
                Application.Quit();
            }
        }

	    if (m_rewiredPlayer.GetButtonUp("Previous Level"))
	    {
	        if (m_initialized)
	        {
	            ChangeLevel(true);
	        }
	    }

	    if (m_rewiredPlayer.GetButtonUp("Next Level"))
	    {
	        if (m_initialized)
	        {
	            ChangeLevel(false);
	        }
	    }
		

	}
}
