using System.Text;

namespace GravCoin;

public static class DailyRewardSecurity
{
	// v2 pepper — legacy, kept only for reading old saves during migration.
	private const string PepperV2 = "sandmoney.daily.v2";

	// v3 pepper — current format that does NOT include PlayerName.
	// PlayerName was removed because it is inconsistent across sessions:
	// Network.Owner is null in singleplayer (PlayerName → "Trader") but is
	// Connection.Local in multiplayer (PlayerName → Steam display name).
	// This mismatch caused the daily streak to reset to day 1 on every load
	// whenever the player switched between singleplayer and multiplayer.
	private const string PepperV3 = "sandmoney.daily.v3";

	/// <summary>Computes a daily reward integrity hash (current v3 format, no PlayerName).</summary>
	public static string ComputeHash( int streak, long lastClaimTs, long anchorTs, int rollbackStrikes )
	{
		var payload = Encoding.UTF8.GetBytes(
			$"{PepperV3}|{streak}|{lastClaimTs}|{anchorTs}|{rollbackStrikes}" );
		return PlayerSaveHasher.ComputeHex( payload );
	}

	private static string ComputeHashLegacy( int streak, long lastClaimTs, long anchorTs, int rollbackStrikes, string playerName )
	{
		var payload = Encoding.UTF8.GetBytes(
			$"{PepperV2}|{streak}|{lastClaimTs}|{anchorTs}|{rollbackStrikes}|{playerName ?? ""}" );
		return PlayerSaveHasher.ComputeHex( payload );
	}

	/// <summary>
	/// Verifies the integrity hash for the daily reward payload.
	/// Tries the current v3 format first, then falls back to the legacy v2 format
	/// with several PlayerName candidates so that saves from old game versions
	/// (or inconsistent display-name states) are still accepted after an update.
	/// </summary>
	public static bool Verify( int streak, long lastClaimTs, long anchorTs, int rollbackStrikes, string playerName, string expectedHash )
	{
		if ( string.IsNullOrWhiteSpace( expectedHash ) )
			return false;

		// Current v3 format (no PlayerName dependency)
		if ( string.Equals( ComputeHash( streak, lastClaimTs, anchorTs, rollbackStrikes ),
				expectedHash, System.StringComparison.OrdinalIgnoreCase ) )
			return true;

		// Legacy v2 fallback — try the player's current name, empty string, and the
		// "Trader" default to cover saves that were written when the display name was
		// unavailable or different from its current value.
		foreach ( var name in new[] { playerName ?? "", "", "Trader" } )
		{
			if ( string.Equals( ComputeHashLegacy( streak, lastClaimTs, anchorTs, rollbackStrikes, name ),
					expectedHash, System.StringComparison.OrdinalIgnoreCase ) )
				return true;
		}

		return false;
	}
}
