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

/// <summary>
/// Holds all agents that have been recruited.
/// </summary>
public class AgentManager : EventBehaviour
{

	[SerializeField]
	private int minAgents = 3;
	[SerializeField]
	private int maxAgents = 7;
	[SerializeField]
	private float maxAngerGainFromFalseAccusation = 0.2f;
	[SerializeField]
	private float hatesAccussationsMultiplier = 2;

	private GameManager gameManager;
	private AgentGenerator agentGen;
	private ViewAgentsPanel viewAgentsPanel;
	private NotificationPanel notificationPanel;

	private List<Agent> agentList;

	/// <summary>
	/// All agents that have been recruited.
	/// </summary>
	public List<Agent> AgentList { get { return agentList; } }

	public bool AgentsAtMaxLimit
	{
		get
		{
			return agentList.Count >= MaxAgents;
		}
	}

	public int MaxAgents { get { return minAgents + Mathf.RoundToInt((maxAgents - minAgents) * gameManager.ProgressionLevel); } }

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

		ReferenceManager.GetBehaviours(ref agentGen, ref viewAgentsPanel, ref notificationPanel);
		ReferenceManager.GetBehaviours(ref gameManager);

		agentList = new List<Agent>();
	}

	public void AddInitialAgents()
	{
		int numberOfAgents = MaxAgents;
		if (agentList.Count >= numberOfAgents) return;

		int agentsToAdd = numberOfAgents - agentList.Count;
		for (int i = 0; i < agentsToAdd; i++)
			RecruitAgent();
	}

	public void RecruitAgent()
	{
		if (agentList.Count >= MaxAgents) return;

		Agent newAgent = agentGen.CreateAgent();

		agentList.Add(newAgent);
		viewAgentsPanel.DisplayAgents(agentList);

		notificationPanel.ShowNotification(string.Format("{0} has joined the agency", newAgent.Name));
		gameEvents.Publish(GAME_EVENT.AgentCountChanged);
	}

	public void RemoveAgent(Agent agentInfo, List<HistoryWidget> evidenceList)
	{
		EvaluateEvidence(evidenceList);

		// remove the agent
		if (agentList.Remove(agentInfo))
		{
			viewAgentsPanel.DisplayAgents(agentList);
		}

		notificationPanel.ShowNotification(string.Format("{0} has been \"Dismissed\"", agentInfo.Name));
		gameEvents.Publish(GAME_EVENT.AgentCountChanged);
	}

	public void RemoveAgent(Agent agentInfo)
	{
		// remove the agent
		if (agentList.Remove(agentInfo))
		{
			viewAgentsPanel.DisplayAgents(agentList);
		}

		notificationPanel.ShowNotification(string.Format("{0} has been \"Dismissed\"", agentInfo.Name));
		gameEvents.Publish(GAME_EVENT.AgentCountChanged);
	}

	/// <summary>
	/// Disables an agent for a certain period of time (while they're away on a mission).
	/// </summary>
	public void SetAgentToAway(Agent agent, float duration)
	{
		StartCoroutine(_DisableAgent(agent, duration));
	}

	public void EvaluateEvidence(List<HistoryWidget> evidenceList)
	{
		bool firstAngerRising = true;

		for(int i = 0; i < evidenceList.Count; i++)
		{
			if (!evidenceList[i].Backstory.couldBeDoubleAgent)
			{
				if(firstAngerRising)
				{
					firstAngerRising = false;
					notificationPanel.ShowNotification("Some agents are angry about false accusations");
				}
				RiseAgentAngerLevels();
			}
		}
	}

	private void RiseAgentAngerLevels()
	{
		var agentsLeaving = new List<Agent>();

		for(int i = 0; i < agentList.Count; i++)
		{
			var currentAgent = agentList[i];
			var angerRise = Random.Range(0, maxAngerGainFromFalseAccusation);

			if (currentAgent.Traits.Contains(PersonalityTrait.HatesFalseAccusations))
				angerRise *= hatesAccussationsMultiplier;

			currentAgent.CurrentAngerLevel += angerRise;

			if (currentAgent.CurrentAngerLevel >= 1)
				agentsLeaving.Add(currentAgent);
		}

		for (int i = 0; i < agentsLeaving.Count; i++)
		{
			notificationPanel.ShowNotification(string.Format("{0} has resigned", agentsLeaving[i].Name));
			RemoveAgent(agentsLeaving[i]);
		}
	}

	private IEnumerator _DisableAgent(Agent agent, float duration)
	{
		agent.Away = true;
		gameEvents.Publish(GAME_EVENT.AgentAwayStatusChanged, agent);

		yield return new WaitForSeconds(duration);

		agent.Away = false;
		gameEvents.Publish(GAME_EVENT.AgentAwayStatusChanged, agent);
	}
}
