KoogleApp/src/Koogle.Web/Components/Game/GameSetupDialog.razor

278 lines
9.5 KiB
Plaintext

@using Fluxor
@using Koogle.Application.DTOs
@using Koogle.Application.Games
@using Koogle.Application.Games.Shit
@using Koogle.Application.Games.Training
@using Koogle.Application.Interfaces
@using Koogle.Domain.Enums
@using Koogle.Domain.Interfaces
@using Koogle.Web.Store.DayState
@using Koogle.Web.Store.GameState
@using MudBlazor
@inject IState<DayState> DayState
@inject IDispatcher Dispatcher
@inject GameDefinitionRegistry GameRegistry
<MudDialog>
<DialogContent>
<MudStack Spacing="4" Style="min-width: 400px; max-width: 600px;">
@* Step 1: Game Type Selection *@
<MudExpansionPanels MultiExpansion="false" Elevation="0">
<MudExpansionPanel Text="1. Spieltyp" IsExpanded="@(_currentStep == 1)">
<GameTypeSelector @bind-SelectedGameType="_selectedGameType"
OnGameDefinitionChanged="OnGameDefinitionChanged" />
</MudExpansionPanel>
@* Step 2: Participant Selection *@
<MudExpansionPanel Text="2. Teilnehmer"
IsExpanded="@(_currentStep == 3)"
Disabled="@(_selectedDefinition == null)">
<ParticipantSelector AvailableParticipants="@_availableParticipants"
@bind-SelectedParticipantIds="_selectedParticipantIds"
MinimumParticipants="1" />
</MudExpansionPanel>
@* Step 3: Game-specific Setup *@
<MudExpansionPanel Text="3. Spieleinstellungen"
IsExpanded="@(_currentStep == 2)"
Disabled="@(_selectedDefinition == null)">
@if (_selectedDefinition != null)
{
<DynamicComponent Type="@_selectedDefinition.SetupComponentType"
@ref="dynamicComponentRef"
Parameters="@GetSetupParameters()" />
}
else
{
<MudText Color="Color.Secondary">
Wähle zuerst einen Spieltyp aus.
</MudText>
}
</MudExpansionPanel>
@* Step 4: Common Options *@
@* <MudExpansionPanel Text="4. Grundeinstellungen"
IsExpanded="@(_currentStep == 4)"
Disabled="@(_selectedParticipantIds.Count == 0)">
<CommonSetupOptions @bind-ThrowMode="_throwMode"
@bind-ThrowsPerRound="_throwsPerRound"
@bind-ParticipantsMode="_participantsMode" />
</MudExpansionPanel> *@
</MudExpansionPanels>
@* Validation errors *@
@if (!string.IsNullOrEmpty(_validationError))
{
<MudAlert Severity="Severity.Error" Dense="true">
@_validationError
</MudAlert>
}
@* Game info summary *@
@if (CanStartGame())
{
<MudPaper Class="pa-3" Elevation="0" Style="background-color: var(--mud-palette-background-grey);">
<MudStack Spacing="1">
<MudText Typo="Typo.body2">
<strong>Spieltyp:</strong> @_selectedDefinition?.DisplayName
</MudText>
<MudText Typo="Typo.body2">
<strong>Teilnehmer:</strong> @_selectedParticipantIds.Count Spieler
</MudText>
<MudText Typo="Typo.body2">
<strong>Modus:</strong> @GetThrowModeLabel()
</MudText>
</MudStack>
</MudPaper>
}
</MudStack>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel" Variant="Variant.Text">Abbrechen</MudButton>
<MudButton OnClick="StartGame"
Color="Color.Primary"
Variant="Variant.Filled"
Disabled="@(!CanStartGame() || _isStarting)"
StartIcon="@Icons.Material.Filled.PlayArrow">
@if (_isStarting)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="mr-2" />
<span>Starte...</span>
}
else
{
<span>Spiel starten</span>
}
</MudButton>
</DialogActions>
</MudDialog>
@code {
private DynamicComponent? dynamicComponentRef;
/// <summary>
/// ID of the day to start the game for.
/// </summary>
[Parameter]
public Guid DayId { get; set; }
/// <summary>
/// Cascade parameter for the dialog instance.
/// </summary>
[CascadingParameter]
private IMudDialogInstance? MudDialog { get; set; }
// State
private int _currentStep = 1;
private string? _selectedGameType;
private IGameDefinition? _selectedDefinition;
private IReadOnlyList<DayParticipantDto> _availableParticipants = [];
private IReadOnlyList<Guid> _selectedParticipantIds = [];
// private object? _gameSpecificSetupOptions;
// private ThrowMode _throwMode = ThrowMode.Reposition;
// private int _throwsPerRound = 3;
// private ParticipantsMode _participantsMode = ParticipantsMode.GameLogic;
private string? _validationError;
private bool _isStarting;
protected override void OnInitialized()
{
// Get available participants from the selected day
var selectedDay = DayState.Value.SelectedDay;
if (selectedDay != null)
{
_availableParticipants = selectedDay.Participants;
// Pre-select all participants
_selectedParticipantIds = selectedDay.Participants.Select(p => p.PersonId).ToList();
}
}
private void OnGameDefinitionChanged(IGameDefinition? definition)
{
_selectedDefinition = definition;
// _gameSpecificSetupOptions = null;
_validationError = null;
if (definition != null)
{
_currentStep = 2;
}
}
private Dictionary<string, object> GetSetupParameters()
{
return new Dictionary<string, object>
{
["OnOptionsChanged"] = EventCallback.Factory.Create<object>(this, OnSetupOptionsChanged),
// ["InitialOptions"] = _gameSpecificSetupOptions!
};
}
private void OnSetupOptionsChanged(object options)
{
// _gameSpecificSetupOptions = options;
_validationError = null;
}
private bool CanStartGame()
{
if (_selectedDefinition == null)
return false;
if (_selectedParticipantIds.Count == 0)
return false;
return true;
}
private Task StartGame()
{
if (!CanStartGame() || _selectedDefinition == null)
return Task.CompletedTask;
_isStarting = true;
_validationError = null;
try
{
// Create typed setup model based on game type
IGameSetupModel? setup = CreateSetupModel(_selectedDefinition.Name);
// Validate setup options
var logicService = GameRegistry.GetLogicService(_selectedDefinition.Name);
var validationResult = logicService.ValidateSetup(setup);
if (!validationResult.IsValid)
{
_validationError = string.Join(", ", validationResult.Errors);
_isStarting = false;
return Task.CompletedTask;
}
// Create initial game model and setup
var playerIds = _selectedParticipantIds.ToArray();
var initialModel = logicService.CreateInitialModel(playerIds, setup);
// Dispatch start game action
var action = new StartGameAction(
DayId: DayId,
GameTypeName: _selectedDefinition.Name,
PlayerIds: playerIds,
ThrowMode: setup.ThrowMode,
ThrowsPerRound: setup.ThrowsPerRound,
ParticipantsMode: setup.ParticipantsMode,
InitialGameModel: initialModel,
Setup: setup);
Dispatcher.Dispatch(action);
// Close dialog
MudDialog?.Close(DialogResult.Ok(true));
}
catch (Exception ex)
{
_validationError = $"Fehler beim Starten: {ex.Message}";
}
finally
{
_isStarting = false;
}
return Task.CompletedTask;
}
private void Cancel()
{
MudDialog?.Cancel();
}
private string GetThrowModeLabel()
{
IGameSetupModel? setup = CreateSetupModel(_selectedDefinition.Name);
switch (setup.ThrowMode)
{
case ThrowMode.Reposition:
return "In die Vollen";
case ThrowMode.Decrease:
return "Abräumen";
}
return "";
}
private IGameSetupModel? CreateSetupModel(string gameTypeName)
{
var setupModel = (dynamicComponentRef.Instance as IGameSetupControl).GameSetupModel;
// setupModel.DayId = DayState.Value.Id;
// setupModel.KnownGameType = SetupState.Value.Game.GetType().Name;
// setupModel.Participants = PlayerIds;
return setupModel;
}
}