using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class LevelController : MonoBehaviour {

    public GUIText countdownText;
    public Camera mainCamera;
    public Camera pauseCamera;
    public GameObject pauseMenu;
    public GameObject hud;

    private enum LevelState {
        Running,
        Complete
    }

    private LevelState state;
    private int points;
    private GameObject timer;
    private MultiplierBar multiplierBar;
    private Text timerText;

    // Times in seconds
    private int startDelay = 5;
    private float timeLimit = 200f;
    private float countdown;

    private bool isTimeUp = false;

    // Gravity
    private const float ACCELERATION_MAX_X = .4f;
    private const float GRAVITY = 9.81f;
    
    private delegate IEnumerator Game();

    /**
     * Called when player collects a reward
     *
     * This function will handle the point multiplier
     *
     * @param basePointValue Value of the reward
     * @return the points 
     */
    public int collectPoints(int basePointValue) {
        int pointsCollected = basePointValue * multiplierBar.getMultiplier();

        // Add new point then update the multiplier
        points += pointsCollected;
        multiplierBar.setScore(points);

        multiplierBar.multiplierHit();

        print("Collected points, total: " + points);

        return pointsCollected;
    }

    void Awake() {
        timer = GameObject.Find("Countdown");
        timerText = timer.GetComponent<Text>();
        countdown = timeLimit;

        // Ensure not paused on startup
        SetPauseEnabled(false);
    }

    void OnGUI() {
        if (isTimeUp) {
            var timeUp = "<color=\"#ff0000\"><size=75>OUT OF TIME!</size></color>";
            GUIScaler.Begin();
            GUI.Label (new Rect((Screen.width/2)-60, (Screen.height/2 - 250 ),700,75), timeUp);
            GUIScaler.End();
        }
    }

    private IEnumerator TimeUp() {
        isTimeUp = true;
        yield return new WaitForSeconds(3);
        Application.LoadLevel("title_screen");
        
    }

    private void SetGameObjectVisible(GameObject gameObject, bool setVisible) {
        gameObject.SetActive(setVisible);
    }

    void SetPauseEnabled(bool pauseEnabled) {
        pauseCamera.enabled = pauseEnabled;
        pauseMenu.SetActive(pauseEnabled);

        mainCamera.enabled = !pauseEnabled;
        hud.SetActive(!pauseEnabled);
            
        Time.timeScale = (pauseEnabled ? 0 : 1);
    }

    void Start() {
        GUIScaler.Initialize();

        Game defaultGame = BasicGame;
        points = 0;

        GameObject mycam = GameObject.Find("Main Camera");
        multiplierBar = mycam.GetComponent<MultiplierBar>();

        StartCoroutine(Launch(defaultGame));
    }

    bool IsPaused() {
        return (Time.timeScale == 0);
    }

    void TogglePause() {
        SetPauseEnabled(!IsPaused());
    }

    void Update() {
        if (state == LevelState.Running) {
            if (Input.GetKeyDown(KeyCode.Escape)) {
                // Escape also maps to Android's back button
                TogglePause();
                return;
            }

            countdown -= Time.deltaTime;
            if (countdown <= 0) {
                countdown = 0;
                LevelComplete(false);
            } 
            timerText.text = Mathf.CeilToInt(countdown).ToString();
        }
    }

    void FixedUpdate() {
        if (state == LevelState.Running) {
            UpdateGravity();
        }
    }

    private IEnumerator Launch(Game toLaunch) {
        yield return new WaitForSeconds(startDelay);
        StartCoroutine(toLaunch());
        state = LevelState.Running;
            
    }
    
    private IEnumerator BasicGame() {
        while (state == LevelState.Running) {
            yield return new WaitForSeconds(5);

            // We can initiate some random actions here
            // Maybe shoot at the player?
        }
    }

    public void LevelComplete(bool success) {
        state = LevelState.Complete;

        int playerTime = Mathf.CeilToInt(timeLimit - countdown);
        if (success) {
            var manager = GameManager.active;
            manager.UpdateScores(playerTime, points);
            Application.LoadLevel ("scoreboard");
         } else {
            StartCoroutine(TimeUp());
         }
    }

    private void UpdateGravity() {
        float accelerationX = 0;
        if (Input.GetKey(KeyCode.A)) {
            accelerationX = -ACCELERATION_MAX_X;
        } else if (Input.GetKey(KeyCode.D)) {
            accelerationX = ACCELERATION_MAX_X;
        } else {
            // Keep accelerometer.x input at within [-MAX_X, MAX_X]
            accelerationX = Mathf.Max(Mathf.Min(Input.acceleration.x, ACCELERATION_MAX_X), -ACCELERATION_MAX_X);
        }

        float gravityX = accelerationX * GRAVITY;

        // Keep gravity Y within [-1, -(1 - MAX_X)]
        float gravityY = (Mathf.Abs(accelerationX) - 1f) * GRAVITY;

        Physics2D.gravity = new Vector2(gravityX, gravityY);
    }
}
