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


[System.Serializable]
public class SpawnPoint
{
    public GameObject go;
    public int period;
}

public enum SpawnMethod
{
    Random,
    Ordered
}

public class GameManager : MonoBehaviour
{
    public static GameManager instance = null;

    public GameObject Kid;

    public List<int> KidsInWave;
    public List<SpawnPoint> SpawnPoints;
    public SpawnMethod spawnMethod;
    public float KidDeployRate;
    public float TimeBetweenWaves = 0;

    public float startingKids;

    public State currentState;

    public MenuController menuController;

    public Transform tidePodTransform;
        
    public Text Pods;
    public Text HarvKids;
    public Text TimeAndKidsLeft;
    public Text GameOver;
    public Text KidsToLose;
    public Text PeriodText;

    public int Lives;
    public float HarvestedKids { get; set; } //Kids to spend
    public int KidsLeft;// { get; internal set; }//In Wave
    public int KidsAlive;// { get; internal set; }//On Screen
    public int Period;//{ get; internal set; }
    public float SetupTimeLeft { get; internal set; }

    public string HarvestedKidsOverride = null;

    [Header("Sound")]
    public AudioClip BellRing;

    void Awake()
    {
        if(instance == null)
        {
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
    }
    private void Start()
    {
        currentState = new InitGame();
        currentState.Start();
    }

    public void SwitchState(State newState)
    {
        currentState.End();
        currentState = newState;
        newState.Start();
    }

	// Update is called once per frame  
	void Update ()
    {
        Pods.text = "Pods : " + Lives.ToString();
        HarvKids.text = "Kids : " + Mathf.FloorToInt(HarvestedKids);
        KidsToLose.text = HarvestedKidsOverride;

        PeriodText.text = "Period " + (GameManager.instance.Period+1) + " of " + KidsInWave.Count;

        instance.currentState.Update();
	}

    //Callback Function
    public void KillKid()
    {
        if(--KidsAlive <= 0)
        {
            if (++GameManager.instance.Period == GameManager.instance.KidsInWave.Count)
            {
                GameManager.instance.SwitchState(new GameOver() { Won = true });
                return;
            }
            else
            { 
                GameManager.instance.SwitchState(new TransitionPhase() { Cooldown = TimeBetweenWaves });
            }
        }
    }
}

public class State
{
    public virtual void Start() { }
    public virtual void Update() { }
    public virtual void End() { }
}
public class InitGame : State
{
    public override void Start()
    {
        GameManager.instance.Period = 0;
        GameManager.instance.Lives = 10;
        GameManager.instance.HarvestedKids = GameManager.instance.startingKids;
        GameManager.instance.SwitchState(new TransitionPhase() { Cooldown = GameManager.instance.TimeBetweenWaves });
    }
}
public class TransitionPhase : State
{
    public float Cooldown { get; set; }
    float time;

    public override void Start()
    {

        time = Time.time;
    }

    public override void Update()
    {
        GameManager.instance.TimeAndKidsLeft.text = "Passing Period : " + (Cooldown - (Time.time - time)).ToString("N2");
        //MonoBehaviour.print("Time left in cooldown phase : " + (Cooldown - (Time.time - time)));
        if (Time.time - time >= Cooldown)
        {
            GameManager.instance.SwitchState(new EnemyPhase() { KidDeployRate = GameManager.instance.KidDeployRate });
        }
    }
}
public class EnemyPhase : State
{
    public float KidDeployRate { get; set; } //Deploy a kid every X seconds.

    List<SpawnPoint> spawnPointsThisPeriod;
    public override void End()
    {
        GameManager.instance.StopCoroutine(SpawnKids());
        spawnPointsThisPeriod.Clear();
    }

    public override void Update()
    {
        GameManager.instance.TimeAndKidsLeft.text = "Kids Left : " + GameManager.instance.KidsLeft.ToString();
    }

    public override void Start()
    {
        spawnPointsThisPeriod = new List<SpawnPoint>();
        KidDeployRate = 1f-(GameManager.instance.Period*0.1f);

        foreach (SpawnPoint sp in GameManager.instance.SpawnPoints)
        {
            if (sp.period <= GameManager.instance.Period)
                spawnPointsThisPeriod.Add(sp);
        }

        if (spawnPointsThisPeriod.Count == 0)
            spawnPointsThisPeriod.Add(GameManager.instance.SpawnPoints[0]);

        GameManager.instance.KidsLeft = GameManager.instance.KidsInWave[GameManager.instance.Period];
        GameManager.instance.KidsAlive = GameManager.instance.KidsLeft;

        GameManager.instance.StartCoroutine(SpawnKids());

        if(GameManager.instance.BellRing != null && Camera.main.gameObject.GetComponent<AudioSource>() != null)
            Camera.main.gameObject.GetComponent<AudioSource>().PlayOneShot(GameManager.instance.BellRing,0.2f);
    }

    Transform PickSpawn(int minIndex, int maxIndex)
    {
        if (GameManager.instance.spawnMethod == SpawnMethod.Random)
            return GameManager.instance.SpawnPoints[Random.Range(minIndex, maxIndex)].go.transform;
        else
            return spawnPointsThisPeriod[Random.Range(0, spawnPointsThisPeriod.Count)].go.transform;
    }

    IEnumerator SpawnKids()
    {
        //HACK: ONLY SPAWNS AT SPAWN POINT 1 FOR NOW.
        while (GameManager.instance.KidsLeft > 0)
        {
            GameManager.instance.KidsLeft--;
            Transform chosenSpawn = PickSpawn(0, GameManager.instance.SpawnPoints.Count);
            GameManager.Instantiate(GameManager.instance.Kid, chosenSpawn.position, chosenSpawn.rotation).GetComponent<KidController>().destination = GameManager.instance.tidePodTransform;
            yield return new WaitForSeconds(KidDeployRate);
        }
    }
}
public class GameOver : State
{
    public bool Won { get; set; }
    public override void Start()
    {
        GameManager.instance.StopCoroutine("SpawnKids");
        GameManager.instance.GameOver.gameObject.SetActive(true);
        if (Won)
        {
            GameManager.instance.menuController.Win();
            GameManager.instance.GameOver.text = "You win?";
        }
        else
        {
            GameManager.instance.menuController.Lose();
            GameManager.instance.GameOver.text = "You lose!";
        }
    }

    public override void End()
    {
        GameManager.instance.GameOver.enabled = false;
    }
}
