UI/OnlinePage.razor
@using System;
@using Sandbox;
@using Sandbox.UI;
@using Sandbox.UI.Navigation;
@inherits Panel
@attribute [Route( "/online" )]

<root class="menu-page online-page">

	<label class="page-heading">
		ONLINE 1V1
	</label>

	@if ( _showSettings )
	{
		<div class="online-subheading">
			LOCAL SETTINGS
		</div>

		<label class="page-copy">
			These preferences affect only your local player.
		</label>

		<SettingsPanel />

		<div class="menu-back" onclick=@CloseSettings>
			BACK TO LOBBY
		</div>
	}
	else if ( FlowManager is null )
	{
		<div class="online-status-label error">
			NETWORK FLOW UNAVAILABLE
		</div>

		<a
			href="/play"
			class="menu-back"
		>
			BACK
		</a>
	}
	else if (
		FlowManager.OnlineState ==
			OnlineFlowState.Searching
	)
	{
		<div class="online-status-label">
			SEARCHING FOR MATCH
		</div>

		<div class="online-spinner">
			•••
		</div>

		<label class="page-copy">
			Looking for another available One More Round player.
		</label>

		<div class="menu-back" onclick=@Cancel>
			CANCEL
		</div>
	}
	else if (
		FlowManager.OnlineState ==
			OnlineFlowState.Connecting
	)
	{
		<div class="online-status-label">
			JOINING MATCH
		</div>

		<div class="online-spinner">
			•••
		</div>

		<label class="page-copy">
			Connecting to an available opponent.
		</label>

		<div class="menu-back" onclick=@Cancel>
			CANCEL
		</div>
	}
	else if (
		FlowManager.OnlineState ==
			OnlineFlowState.WaitingForOpponent
	)
	{
		<div class="online-status-label">
			SEARCHING FOR OPPONENT
		</div>

		<div class="player-card-row">

			<div class="player-card ready">
				<div class="player-card-label">YOU</div>
				<div class="player-card-name">@LocalConnectionName</div>
				<div class="player-card-state">CONNECTED</div>
			</div>

			<div class="versus">
				VS
			</div>

			<div class="player-card searching">
				<div class="player-card-label">OPPONENT</div>
				<div class="player-card-name">SEARCHING...</div>
				<div class="player-card-state">WAITING</div>
			</div>

		</div>

		<label class="page-copy">
			Lobby open · @ConnectedPlayerCount/2 players connected
		</label>

		<div class="menu-primary secondary-action" onclick=@OpenSettings>
			SETTINGS
		</div>

		<div class="menu-back" onclick=@Cancel>
			CANCEL
		</div>
	}
	else if (
		FlowManager.OnlineState ==
			OnlineFlowState.Lobby
	)
	{
		<div class="online-status-label found">
			PRE-MATCH LOBBY
		</div>

		<label class="page-copy">
			The match begins only when both players are ready.
		</label>

		<div class="player-card-row lobby-cards">

			<div class="player-card @LocalCardClass">
				<div class="player-card-label">YOU</div>
				<div class="player-card-name">@LocalConnectionName</div>
				<div class="player-card-state">@LocalStateText</div>
			</div>

			<div class="versus">
				VS
			</div>

			<div class="player-card opponent-card @OpponentCardClass">
				<div class="player-card-label">OPPONENT</div>
				<div class="player-card-name">@OpponentConnectionName</div>
				<div class="player-card-state">@OpponentStateText</div>
			</div>

		</div>

		<div class="lobby-weapon-panel">

			<div class="setup-label">
				WARMUP WEAPON
			</div>

			<div class="setup-selector">

				<div
					class="selector-arrow"
					onclick=@PreviousWeapon
				>
					‹
				</div>

				<div class="selector-value">
					@LocalWarmupWeapon
				</div>

				<div
					class="selector-arrow"
					onclick=@NextWeapon
				>
					›
				</div>

			</div>

			<div class="lobby-note">
				This selection is only for pre-match practice. Competitive round loadouts remain controlled by the game.
			</div>

		</div>

		<div class="lobby-actions">

			<div class="menu-primary warmup-action" onclick=@ToggleWarmup>
				@(LocalState == PreMatchPlayerState.Warmup ? "RETURN TO LOBBY" : "WARMUP")
			</div>

			<div class="menu-primary secondary-action" onclick=@OpenSettings>
				SETTINGS
			</div>

			<div class="menu-primary ready-action @(LocalState == PreMatchPlayerState.Ready ? "active" : "")" onclick=@ToggleReady>
				@(LocalState == PreMatchPlayerState.Ready ? "NOT READY" : "READY")
			</div>

		</div>

		<div class="lobby-ready-summary">
			@ReadySummary
		</div>

		<div class="menu-back" onclick=@Cancel>
			LEAVE LOBBY
		</div>
	}
	else if (
		FlowManager.OnlineState ==
			OnlineFlowState.Error
	)
	{
		<div class="online-status-label error">
			MATCHMAKING ERROR
		</div>

		<label class="page-copy error-copy">
			@FlowManager.ErrorMessage
		</label>

		<div class="menu-primary" onclick=@Retry>
			TRY AGAIN
		</div>

		<div class="menu-back" onclick=@Cancel>
			BACK
		</div>
	}
	else
	{
		<div class="online-status-label">
			READY
		</div>

		<a
			href="/play"
			class="menu-back"
		>
			BACK
		</a>
	}

</root>

@code
{
	private bool _showSettings;

	private MainMenuHost Host =>
		MainMenuHost.Current;

	private GameFlowManager FlowManager =>
		Host?.
			FlowManager;

	private PlayerState LocalPlayer =>
		Host?.
			LocalPlayerState;

	private PlayerState OpponentPlayer =>
		Host?.
			OpponentPlayerState;

	private int ConnectedPlayerCount =>
		Host?.
			ConnectedPlayerCount ??
		0;

	private string LocalConnectionName =>
		Host?.
			LocalConnectionName ??
		"YOU";

	private string OpponentConnectionName =>
		Host?.
			OpponentConnectionName ??
		"OPPONENT";

	private PreMatchPlayerState LocalState =>
		LocalPlayer?.
			PreMatchState ??
		PreMatchPlayerState.Lobby;

	private PreMatchPlayerState OpponentState =>
		OpponentPlayer?.
			PreMatchState ??
		PreMatchPlayerState.Lobby;

	private string LocalStateText =>
		StateText(
			LocalState
		);

	private string OpponentStateText =>
		StateText(
			OpponentState
		);

	private string LocalCardClass =>
		StateClass(
			LocalState
		);

	private string OpponentCardClass =>
		StateClass(
			OpponentState
		);

	private string LocalWarmupWeapon =>
		Host?.
			GetPreMatchWeaponName(
				LocalPlayer
			) ??
		"NO WEAPON";

	private string ReadySummary
	{
		get
		{
			bool localReady =
				LocalState ==
					PreMatchPlayerState.Ready;

			bool opponentReady =
				OpponentState ==
					PreMatchPlayerState.Ready;

			if (
				localReady &&
				opponentReady
			)
				return "BOTH READY · STARTING MATCH";

			if ( localReady )
				return "WAITING FOR OPPONENT";

			if ( opponentReady )
				return "OPPONENT READY · YOUR DECISION";

			return "BOTH PLAYERS NOT READY";
		}
	}

	private string StateText(
		PreMatchPlayerState state
	)
	{
		return state switch
		{
			PreMatchPlayerState.Warmup =>
				"WARMUP",

			PreMatchPlayerState.Ready =>
				"READY",

			_ =>
				"IN LOBBY"
		};
	}

	private string StateClass(
		PreMatchPlayerState state
	)
	{
		return state switch
		{
			PreMatchPlayerState.Warmup =>
				"practicing",

			PreMatchPlayerState.Ready =>
				"ready",

			_ =>
				""
		};
	}

	private void PreviousWeapon() =>
		Host?.
			CyclePreMatchWeapon(
				-1
			);

	private void NextWeapon() =>
		Host?.
			CyclePreMatchWeapon(
				1
			);

	private void ToggleWarmup() =>
		Host?.
			TogglePreMatchWarmup();

	private void ToggleReady() =>
		Host?.
			TogglePreMatchReady();

	private void OpenSettings()
	{
		_showSettings =
			true;
	}

	private void CloseSettings()
	{
		_showSettings =
			false;
	}

	private void Retry()
	{
		_showSettings =
			false;

		Host?.
			FindMatch();
	}

	private void Cancel()
	{
		_showSettings =
			false;

		Host?.
			CancelMatchmaking();
	}

	protected override int BuildHash()
	{
		HashCode hash =
			new();

		hash.Add(
			_showSettings
		);

		hash.Add(
			FlowManager?.
				OnlineState
		);

		hash.Add(
			FlowManager?.
				ErrorMessage
		);

		hash.Add(
			ConnectedPlayerCount
		);

		hash.Add(
			LocalConnectionName
		);

		hash.Add(
			OpponentConnectionName
		);

		hash.Add(
			LocalState
		);

		hash.Add(
			OpponentState
		);

		hash.Add(
			LocalPlayer?.
				WarmupWeaponIndex
		);

		hash.Add(
			OpponentPlayer?.
				WarmupWeaponIndex
		);

		return hash.ToHashCode();
	}
}