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

public class DogStatisticsHandler : MonoBehaviour
{
	public delegate void ChangeStatistic(Statistic statistic);
	public static event ChangeStatistic OnStatisticChanged;

	public delegate void DogActing(Action action, float progress);
	public static event DogActing OnDogAct;

	public void InitializeStatistics(List<Statistic> configuration)
	{
		if (healthType == null)
		{
			throw new System.Exception("Health Type not define");
		}

		StatisticType ageType = null;
		Health health = null;

		if (statistics.Count > 0)
		{
			statistics.Clear();
		}

		foreach (Statistic statistic in configuration)
		{
			Statistic clone = statistic.Clone() as Statistic;
			statistics.Add(clone);

			if (clone.type == healthType)
			{
				health = clone as Health;
				ageType = health.ageType;
			}
		}

		if (health == null)
		{
			throw new System.Exception("No statistic of type '" + healthType + "' found");
		}

		if (ageType == null)
		{
			throw new System.Exception("Age type not defined in '" + health + "'");
		}

		foreach (Statistic statistic in statistics)
		{
			if (statistic.type == ageType)
			{
				health.age = statistic;
			}
		}

		if (health.age == null)
		{
			throw new System.Exception("No statistic of type '" + ageType + "' found in '" + health + "'");
		}
	}

	[SerializeField] private StatisticType healthType = null;
	[SerializeField] private List<Statistic> statistics = new List<Statistic>();
	[SerializeField] private Action currentAction = null;
	[SerializeField] private float currentActionDuration = 0f;

	private void FixedUpdate()
	{
		TickStatistics(Time.fixedDeltaTime);
	}

	private void OnEnable()
	{
		Action.OnPerformed += SetCurrentAction;
	}

	private void OnDisable()
	{
		Action.OnPerformed -= SetCurrentAction;
	}

	private void SetCurrentAction(Action action)
	{
		if (action.statisticEffects.Count < 1)
		{
			return;
		}

		currentAction = action.Clone() as Action;
		currentActionDuration = currentAction.length;
	}

	private void Update()
	{
		if (currentAction != null && currentActionDuration > 0f)
		{
			PerformAction(Time.deltaTime);
		}

		if (currentAction != null && currentActionDuration <= 0f)
		{
			currentAction = null;
			currentActionDuration = 0f;
		}
	}

	private void PerformAction(float deltaTime)
	{
		deltaTime = Mathf.Clamp(deltaTime, 0f, currentActionDuration);
		currentActionDuration -= deltaTime;

		float tick = deltaTime / currentAction.length;

		foreach (StatisticEffect effect in currentAction.statisticEffects)
		{
			ModifyStatistic(effect.statisticType, effect.value * tick);
		}

		OnDogAct(currentAction, currentActionDuration / currentAction.length);
	}

	private void ModifyStatistic(StatisticType statisticType, float value)
	{
		foreach (Statistic statistic in statistics)
		{
			if (statistic.type == statisticType)
			{
				statistic.value += value;
				statistic.value = Mathf.Clamp(statistic.value, statistic.min, statistic.max);
				OnStatisticChanged(statistic);
			}
		}
	}

	private void SetStatistic(StatisticType statisticType, float value)
	{
		foreach (Statistic statistic in statistics)
		{
			if (statistic.type == statisticType)
			{
				statistic.value = Mathf.Clamp(value, statistic.min, statistic.max);
				OnStatisticChanged(statistic);
			}
		}
	}

	private void TickStatistics(float deltaTime)
	{
		foreach (Statistic statistic in statistics)
		{
			statistic.Tick(deltaTime);
			OnStatisticChanged(statistic);
		}
	}
}
