Editor/SubTerrainBrushSize.cs
// Copyright (c) 2026 SubZero Studios LLC. All rights reserved.

using System;

namespace Editor.SubTerrain;

/// <summary>
/// Brush Size limits and piecewise track mapping.
/// Fine band stays precise; larger sizes take less track and bigger nudges.
/// </summary>
public static class SubTerrainBrushSize
{
	public const int Min = 8;
	public const int FineMax = 3500;
	public const int MidMax = 18000;
	public const int Max = 35000;

	public const int FineStep = 50;
	public const int MidStep = 500;
	public const int CoarseStep = 1000;

	/// <summary>Fraction of the slider track for the fine band (8..FineMax).</summary>
	public const float FineTrack = 0.70f;

	/// <summary>End of mid band on the track (FineMax..MidMax). Coarse is the rest to 1.</summary>
	public const float MidTrack = 0.90f;

	public static int Clamp( int size ) => Math.Clamp( size, Min, Max );

	public static int StepFor( int size )
	{
		if ( size < FineMax )
			return FineStep;
		if ( size < MidMax )
			return MidStep;
		return CoarseStep;
	}

	public static int Nudge( int size, int direction )
	{
		if ( direction == 0 )
			return Clamp( size );

		size = Clamp( size );
		int step = StepFor( size );
		return Clamp( size + direction * step );
	}

	public static int SizeFromTrack( float t01 )
	{
		t01 = Math.Clamp( t01, 0f, 1f );

		int raw;
		if ( t01 <= FineTrack )
		{
			float u = FineTrack <= 0f ? 0f : t01 / FineTrack;
			raw = (int)MathF.Round( Lerp( Min, FineMax, u ) );
		}
		else if ( t01 <= MidTrack )
		{
			float u = (t01 - FineTrack) / (MidTrack - FineTrack);
			raw = (int)MathF.Round( Lerp( FineMax, MidMax, u ) );
		}
		else
		{
			float u = (t01 - MidTrack) / (1f - MidTrack);
			raw = (int)MathF.Round( Lerp( MidMax, Max, u ) );
		}

		return Snap( raw );
	}

	public static float TrackFromSize( int size )
	{
		size = Clamp( size );

		if ( size <= FineMax )
		{
			float u = (size - Min) / (float)(FineMax - Min);
			return u * FineTrack;
		}

		if ( size <= MidMax )
		{
			float u = (size - FineMax) / (float)(MidMax - FineMax);
			return FineTrack + u * (MidTrack - FineTrack);
		}

		{
			float u = (size - MidMax) / (float)(Max - MidMax);
			return MidTrack + u * (1f - MidTrack);
		}
	}

	public static int Snap( int size )
	{
		size = Clamp( size );
		int step = StepFor( size );
		int snapped = (int)MathF.Round( size / (float)step ) * step;
		return Clamp( snapped );
	}

	static float Lerp( float a, float b, float t ) => a + (b - a) * Math.Clamp( t, 0f, 1f );
}