UI/ShopPanel.razor
@using System
@using Sandbox
@using Sandbox.UI
@namespace DesertPump
@inherits Panel

<root class="shoppanel">

	<div class="scrim" onclick="@Close"></div>

	<div class="sheet">

		<div class="head">
			<div class="title"><i>storefront</i> SHOP</div>
			<div class="wallet">
				<div class="coin"></div>
				<div class="amount">@Numbers.Short( Game?.Coins ?? 0 )</div>
			</div>
			<div class="closebtn" onclick="@Close"><i>close</i></div>
		</div>

		<div class="tabs">
			<div class="tab @( tab == 0 ? "active" : "" )" onclick="@( () => SetTab( 0 ) )">
				<i>upgrade</i> UPGRADES
			</div>
			<div class="tab @( tab == 2 ? "active" : "" )" onclick="@( () => SetTab( 2 ) )">
				<i>groups</i> WORKERS
			</div>
			<div class="tab @( tab == 1 ? "active" : "" )" onclick="@( () => SetTab( 1 ) )">
				<i>image</i> BACKGROUNDS
			</div>
		</div>

		@if ( Game is not null && tab == 2 )
		{
			<div class="crewline">
				<i>water_drop</i>
				<span class="crewtext">The crew brings in @Numbers.Short( Game.WorkerWaterPerSecond )L/s</span>
				<span class="crewcount">@Game.HiredCount / @WorkerType.Count hired</span>
			</div>

			<div class="tracks">
				@foreach ( var worker in WorkerType.All )
				{
					var level = Game.WorkerLevel( worker );
					var hired = Game.IsHired( worker );
					var maxed = Game.IsWorkerMaxed( worker );
					var afford = Game.CanHire( worker );

					<div class="track @( maxed ? "maxed" : afford ? "afford" : "poor" ) @( hired ? "" : "unhired" )">

						<div class="glyph"><i>@worker.Icon</i></div>

						<div class="info">
							<div class="row">
								<div class="name">@worker.Name</div>
								@if ( hired )
								{
									<div class="level">Lv @level<span class="cap">/@WorkerType.MaxLevel</span></div>
								}
							</div>
							<div class="desc">@worker.Description</div>
							<div class="effect">@WorkerLine( worker )</div>
						</div>

						@if ( maxed )
						{
							<div class="buy maxedbtn"><div class="buylabel">MAXED</div></div>
						}
						else
						{
							<div class="buy @( afford ? "" : "disabled" )" onclick="@( () => Hire( worker ) )">
								<div class="buylabel">@( hired ? "PROMOTE" : "HIRE" )</div>
								<div class="buycost">@Numbers.Short( Game.WorkerCost( worker ) )</div>
							</div>
						}

					</div>
				}
			</div>

			<div class="foot">Workers keep pumping while the game is closed.</div>
		}
		else if ( Game is not null && tab == 1 )
		{
			<div class="tracks">
				@foreach ( var style in BackgroundStyle.All )
				{
					var owned = Game.OwnsBackground( style.Id );
					var active = Game.SelectedBackground == style.Id;
					var afford = Game.CanBuyBackground( style );

					<div class="track bg @( active ? "afford" : "" )">

						<div class="swatch" style="@SwatchStyle( style )">
							<div class="swatch-sun"></div>
							<div class="swatch-dune"></div>
						</div>

						<div class="info">
							<div class="row">
								<div class="name">@style.Name</div>
								@if ( active )
								{
									<div class="level">IN USE</div>
								}
							</div>
							<div class="desc">@style.Description</div>
						</div>

						@if ( active )
						{
							<div class="buy maxedbtn"><div class="buylabel">ACTIVE</div></div>
						}
						else if ( owned )
						{
							<div class="buy" onclick="@( () => Use( style ) )">
								<div class="buylabel">USE</div>
							</div>
						}
						else
						{
							<div class="buy @( afford ? "" : "disabled" )" onclick="@( () => BuyBg( style ) )">
								<div class="buylabel">BUY</div>
								<div class="buycost">@Numbers.Short( style.Cost )</div>
							</div>
						}

					</div>
				}
			</div>

			<div class="foot">Bought once, yours forever - swap whenever you like.</div>
		}
		else if ( Game is not null )
		{
			<div class="tracks">
				@foreach ( var track in UpgradeTrack.All )
				{
					var level = Game.LevelOf( track.Kind );
					var maxed = Game.IsMaxLevel( track.Kind );
					var afford = Game.CanBuy( track.Kind );

					<div class="track @( maxed ? "maxed" : afford ? "afford" : "poor" )">

						<div class="glyph"><i>@track.Icon</i></div>

						<div class="info">
							<div class="row">
								<div class="name">@track.Name</div>
								<div class="level">Lv @level<span class="cap">/@track.MaxLevel</span></div>
							</div>
							<div class="desc">@track.Description</div>
							<div class="effect">@EffectLine( track )</div>
						</div>

						@if ( maxed )
						{
							<div class="buy maxedbtn">
								<div class="buylabel">MAXED</div>
							</div>
						}
						else
						{
							<div class="buy @( afford ? "" : "disabled" )" onclick="@( () => Buy( track.Kind ) )">
								<div class="buylabel">@track.PerLevelText</div>
								<div class="buycost">@Numbers.Short( Game.CostOf( track.Kind ) )</div>
							</div>
						}

					</div>
				}
			</div>

			<div class="foot">Upgrades carry across every pump you buy.</div>
		}

	</div>

</root>

@code
{
	/// <summary>Raised when the player dismisses the shop.</summary>
	public Action OnClose { get; set; }

	static DesertPumpGame Game => DesertPumpGame.Current;

	/// <summary>0 = upgrades, 1 = backgrounds, 2 = workers.</summary>
	int tab;

	/// <summary>Lets the console jump straight to a tab for inspection.</summary>
	public void ShowTab( int which ) => SetTab( which );

	void SetTab( int which )
	{
		tab = which;
		StateHasChanged();
	}

	void Hire( WorkerType worker )
	{
		Game?.BuyWorker( worker );
		StateHasChanged();
	}

	/// <summary>What they make now, and what one more level would make it.</summary>
	string WorkerLine( WorkerType worker )
	{
		if ( Game is null ) return string.Empty;

		var level = Game.WorkerLevel( worker );
		var now = $"{Numbers.Short( worker.OutputAt( level ) )}L/s";

		if ( Game.IsWorkerMaxed( worker ) )
			return $"{now} - fully trained";

		return $"{now}  ->  {Numbers.Short( worker.OutputAt( level + 1 ) )}L/s";
	}

	void BuyBg( BackgroundStyle style )
	{
		Game?.BuyBackground( style );
		StateHasChanged();
	}

	void Use( BackgroundStyle style )
	{
		Game?.SelectBackground( style.Id );
		StateHasChanged();
	}

	static string SwatchStyle( BackgroundStyle style ) =>
		$"background-image: linear-gradient( to bottom, {style.PreviewTop}, {style.PreviewBottom} );";

	void Close() => OnClose?.Invoke();

	void Buy( UpgradeKind kind )
	{
		Game?.BuyUpgrade( kind );
		StateHasChanged();
	}

	/// <summary>Shows the stat as it is now and what the next level would make it.</summary>
	string EffectLine( UpgradeTrack track )
	{
		if ( Game is null ) return string.Empty;

		var level = Game.LevelOf( track.Kind );
		var now = Current( track.Kind, level );

		if ( Game.IsMaxLevel( track.Kind ) )
			return $"{now} - fully upgraded";

		return $"{now}  ->  {Current( track.Kind, level + 1 )}";
	}

	/// <summary>The real number this track controls, at a given level.</summary>
	string Current( UpgradeKind kind, int level )
	{
		var mult = UpgradeTrack.Get( kind ).MultiplierAt( level );
		var pump = Game.CurrentPump;

		return kind switch
		{
			UpgradeKind.Storage => $"{Numbers.Short( pump.Tank * mult )}L tank",
			UpgradeKind.Power => $"{Numbers.Short( pump.PerClick * mult )}L per pump",
			UpgradeKind.Value => $"{Numbers.Short( pump.PricePerLitre * mult )} per litre",
			_ => string.Empty
		};
	}

	protected override int BuildHash()
	{
		if ( Game is null ) return 0;

		// Bucketed rather than cast - the last worker makes 4.9e25 litres a second and
		// the wallet runs to 2.5e51, both of which cast to the same long every time.
		return HashCode.Combine(
			Numbers.Bucket( Game.Coins ),
			Game.PumpLevel,
			Game.LevelOf( UpgradeKind.Storage ),
			Game.LevelOf( UpgradeKind.Power ),
			Game.LevelOf( UpgradeKind.Value ),
			tab,
			HashCode.Combine( Game.SelectedBackground, Game.HiredCount,
				Numbers.Bucket( Game.WorkerWaterPerSecond ) ) );
	}
}