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

/// <summary>
/// The top level manager of the game. Controls game progression.
/// </summary>
public class GameManager : EventBehaviour
{

	[SerializeField]
	private float progressionGainedPerMission = 0.02f;

	[SerializeField]
	private int startingInfluencePoints = 10;
	[SerializeField]
	private int influencePerMission = 10;

	[SerializeField, Tooltip("Gain 1 influence every time this amount of time in seconds passes")]
	private float gainInfluencePointInterval = 5;

	private float currentProgressionLevel;

	private MissionManager missionManager;
	private AgentManager agentManager;

	private int influencePoints;

	public int InfluencePoints { get { return influencePoints; } }

	public float ProgressionLevel { get { return currentProgressionLevel; } }

	protected override void Awake()
	{
		base.Awake();

		ReferenceManager.GetBehaviours(ref missionManager, ref agentManager);

		gameEvents.Subscribe(GAME_EVENT.MissionCompleted, this);

		StartCoroutine(_InfluenceTick());
	}
	
	private void Start()
	{
		if (missionManager != null)
			missionManager.AddNewMissions(currentProgressionLevel);
		if (agentManager != null)
			agentManager.AddInitialAgents();

		AddInfluencePoints(startingInfluencePoints);
	}

	public override void OnGameEvent(GAME_EVENT eventType, object args)
	{
		base.OnGameEvent(eventType, args);

		switch(eventType)
		{
			case GAME_EVENT.MissionCompleted:
				OnMissionCompleted((Mission)args);
				break;
		}
	}

	public void AddInfluencePoints(int amount)
	{
		if(amount < 0)
		{
			LogError("Cannot add negative influence points");
			return;
		}

		influencePoints += amount;

		gameEvents.Publish(GAME_EVENT.InfluencePointsChanged, influencePoints);
	}

	public void RemoveInfluencePoints(int amount)
	{
		if (amount < 0)
		{
			LogError("Cannot remove negative influence points");
			return;
		}

		influencePoints -= amount;
		if (influencePoints < 0)
			influencePoints = 0;

		gameEvents.Publish(GAME_EVENT.InfluencePointsChanged, influencePoints);
	}

	private void OnMissionCompleted(Mission mission)
	{
		if (mission.Status == MissionStatus.Success)
		{
			currentProgressionLevel += progressionGainedPerMission;
			AddInfluencePoints(influencePerMission);
		}

		currentProgressionLevel = Mathf.Clamp01(currentProgressionLevel);

		if (missionManager != null)
		{
			missionManager.RemoveMission(mission);

			if (currentProgressionLevel < 1)
			{
				missionManager.AddNewMissions(currentProgressionLevel);
			}
			else
			{
				// TODO if at the maximum progression level, spawn the final mission.
				missionManager.AddNewMissions(currentProgressionLevel);
			}
		}

		gameEvents.Publish(GAME_EVENT.ProgressionLevelChanged);
	}

	private IEnumerator _InfluenceTick()
	{
		while(true)
		{
			yield return new WaitForSeconds(gainInfluencePointInterval);
			AddInfluencePoints(1);
		}
	}
}
