Player/Immersion/BreathingController.cs
namespace Opium;

public enum BreathingType
{
	Normal,
	Exerted,
	NoStamina,
	DyingHealth
}

public struct BreathingSound
{
	public BreathingType Type { get; set; }
	public SoundEvent Sound { get; set; }

	public override string ToString()
	{
		return $"{Type} - {Sound?.ResourceName ?? "No sound"}";
	}
}

public partial class BreathingController : Component
{
	[Property, ReadOnly] public BreathingType BreathingType { get; private set; }
	[Property] public List<BreathingSound> SoundEvents { get; set; }

	public Dictionary<BreathingType, SoundHandle> Handles { get; set; } = new();

	public Opium.PlayerController PlayerController => Components.Get<Opium.PlayerController>( FindMode.EverythingInSelfAndDescendants );
	
	public PlayerInformation PlayerInfo => Components.Get<PlayerInformation>( FindMode.EverythingInSelfAndDescendants );

	public float Health => PlayerController.Health;

	protected override void OnStart()
	{
		foreach ( var snd in SoundEvents )
		{
			var handle = Sound.Play( snd.Sound );
			handle.Volume = 0f;

			Handles[snd.Type] = handle;
		}
	}
	void UpdateHandles()
	{
		foreach ( var snd in Handles )
		{
			snd.Value.Position = Transform.Position;

			// We're favouring this sound.
			if ( BreathingType == snd.Key )
			{
				snd.Value.Volume = 1f;
			}
			else
			{
				snd.Value.Volume = 0f;
			}
		}
	}

	void UpdateState()
	{
		if ( PlayerController.IsMechanicActive<TakeoverAnimationMechanic>() )
		{
			BreathingType = BreathingType.Normal;
			return;
		}

		if ( Health <= 30f )
		{
			BreathingType = BreathingType.DyingHealth;
		}
		else if ( PlayerController.MechanicTags.Has( "exhausted" ) )
		{
			BreathingType = BreathingType.NoStamina;
		}
		else if ( PlayerController.Tags.Has( "exerted" ) )
		{
			BreathingType = BreathingType.Exerted;
		}
		else
		{
			BreathingType = BreathingType.Normal;
		}
	}

	protected override void OnUpdate()
	{
		UpdateState();
		UpdateHandles();
	}
}