Game/AudioSettings.cs
namespace Monolith;

/// <summary>
/// Sound and music volume, persisted separately from progress.
///
/// **Why its own file rather than a field on <c>SaveData</c>.** These are device settings, not
/// progress. Someone who collapses and starts a fresh run should not get their audio turned back
/// on, and more practically, the music component reads this during <c>OnStart</c>, which can run
/// before <see cref="PlayerProgress"/> has loaded anything. A static with its own file has no
/// ordering problem to solve.
///
/// **Why volumes and not booleans.** The request was for a mute, and mute is what the menu
/// offers, but storing a float costs nothing extra and means a later "50%" option is a UI change
/// rather than a save format change. Muted is simply zero.
/// </summary>
public static class AudioSettings
{
	private const string SettingsPath = "audio.json";

	/// <summary>The stored shape. Public because the JSON serialiser needs to see the fields.</summary>
	public sealed class Data
	{
		public float Music { get; set; } = 1f;
		public float Effects { get; set; } = 1f;
	}

	private static Data current;

	private static Data Current
	{
		get
		{
			if ( current != null )
				return current;

			try
			{
				current = FileSystem.Data.ReadJsonOrDefault<Data>( SettingsPath, null ) ?? new Data();
			}
			catch ( Exception e )
			{
				Log.Warning( $"Could not load audio settings, using defaults: {e.Message}" );
				current = new Data();
			}

			return current;
		}
	}

	/// <summary>Music volume, 0 to 1. Read every frame by <see cref="MonolithMusic"/>.</summary>
	public static float MusicVolume => Current.Music;

	/// <summary>Sound effect volume, 0 to 1. Applied inside <see cref="Audio"/>.</summary>
	public static float EffectsVolume => Current.Effects;

	public static bool MusicMuted => MusicVolume <= 0.001f;

	public static bool EffectsMuted => EffectsVolume <= 0.001f;

	public static void ToggleMusic()
	{
		Current.Music = MusicMuted ? 1f : 0f;
		Save();
	}

	public static void ToggleEffects()
	{
		Current.Effects = EffectsMuted ? 1f : 0f;
		Save();
	}

	private static void Save()
	{
		try
		{
			FileSystem.Data.WriteJson( SettingsPath, Current );
		}
		catch ( Exception e )
		{
			Log.Warning( $"Could not save audio settings: {e.Message}" );
		}
	}
}