using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.EntityFrameworkCore; using TournamentOrganizer.Models; namespace TournamentOrganizer.ViewModels; public partial class GamesViewModel : ViewModelBase { private readonly TournamentContext _context; [ObservableProperty] private ObservableCollection _games = []; [ObservableProperty] private GameDisplay? _selectedGame; [ObservableProperty] private string _gameName = string.Empty; [ObservableProperty] private string _gameDescription = string.Empty; [ObservableProperty] private RuleSetOption? _selectedS1RuleSet; [ObservableProperty] private int? _s1Groups; [ObservableProperty] private int? _s1GroupAdvances; [ObservableProperty] private RuleSetOption? _selectedS2RuleSet; [ObservableProperty] private string _filterGameName = string.Empty; [ObservableProperty] private bool _isEditing; [ObservableProperty] private string _statusMessage = string.Empty; public ObservableCollection S1RuleSetOptions { get; } = []; public ObservableCollection S2RuleSetOptions { get; } = [new RuleSetOption(null, "(None)")]; public bool ShowStage1GroupSettings => SelectedS2RuleSet?.Value != null; public GamesViewModel() { _context = new TournamentContext(); foreach (var rs in Enum.GetValues()) { S1RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName())); S2RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName())); } SelectedS1RuleSet = S1RuleSetOptions.First(); SelectedS2RuleSet = S2RuleSetOptions.First(); } partial void OnSelectedS2RuleSetChanged(RuleSetOption? value) { OnPropertyChanged(nameof(ShowStage1GroupSettings)); if (value?.Value == null) { S1Groups = null; S1GroupAdvances = null; } } partial void OnFilterGameNameChanged(string value) => ApplyFilters(); private async void ApplyFilters() { await LoadGames(); } public async Task LoadGames() { var allGames = await _context.Games .Include(g => g.Tournaments) .ThenInclude(t => t.Event) .ToListAsync(); var filtered = allGames.AsEnumerable(); if (!string.IsNullOrWhiteSpace(FilterGameName)) { var filter = FilterGameName.ToLower(); filtered = filtered.Where(g => g.Name.ToLower().Contains(filter)); } Games.Clear(); foreach (var game in filtered) { Games.Add(new GameDisplay(game)); } SelectedGame = null; IsEditing = false; } [RelayCommand] private async Task RefreshGames() { await LoadGames(); } [RelayCommand] private void CreateNewGame() { GameName = "New Game"; GameDescription = string.Empty; SelectedS1RuleSet = S1RuleSetOptions.FirstOrDefault(o => o.Value == RuleSet.SingleElimination); S1Groups = null; S1GroupAdvances = null; SelectedS2RuleSet = S2RuleSetOptions.First(); IsEditing = true; SelectedGame = null; StatusMessage = "Creating new game"; } [RelayCommand] private async Task SaveGame() { if (string.IsNullOrWhiteSpace(GameName)) { StatusMessage = "Game name is required"; return; } Game? game; if (SelectedGame != null && SelectedGame.Id > 0) { game = await _context.Games.FirstOrDefaultAsync(g => g.Id == SelectedGame.Id); if (game == null) { StatusMessage = "Game not found"; return; } game.Name = GameName; game.Description = GameDescription; game.S1RuleSet = SelectedS1RuleSet!.Value!.Value; game.S1Groups = ShowStage1GroupSettings ? S1Groups : null; game.S1GroupAdvances = ShowStage1GroupSettings ? S1GroupAdvances : null; game.S2RuleSet = SelectedS2RuleSet?.Value; } else { game = new Game { Name = GameName, Description = GameDescription, S1RuleSet = SelectedS1RuleSet!.Value!.Value, S1Groups = ShowStage1GroupSettings ? S1Groups : null, S1GroupAdvances = ShowStage1GroupSettings ? S1GroupAdvances : null, S2RuleSet = SelectedS2RuleSet?.Value, Tournaments = [] }; _context.Games.Add(game); } await _context.SaveChangesAsync(); StatusMessage = $"Game '{GameName}' saved successfully"; await LoadGames(); } [RelayCommand] private async Task DeleteGame() { if (SelectedGame == null || SelectedGame.Id == 0) { StatusMessage = "Select a game to delete"; return; } var game = await _context.Games.FirstOrDefaultAsync(g => g.Id == SelectedGame.Id); if (game == null) { StatusMessage = "Game not found"; return; } _context.Games.Remove(game); await _context.SaveChangesAsync(); StatusMessage = $"Game '{game.Name}' deleted"; await LoadGames(); } partial void OnSelectedGameChanged(GameDisplay? value) { if (value == null) { IsEditing = false; return; } GameName = value.Name; GameDescription = value.Description; SelectedS1RuleSet = S1RuleSetOptions.FirstOrDefault(o => o.Value == value.S1RuleSet) ?? S1RuleSetOptions.First(); S1Groups = value.S1Groups; S1GroupAdvances = value.S1GroupAdvances; SelectedS2RuleSet = S2RuleSetOptions.FirstOrDefault(o => o.Value == value.S2RuleSet) ?? S2RuleSetOptions.First(); IsEditing = true; StatusMessage = $"Editing game '{value.Name}'"; } } public class GameDisplay { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; public RuleSet S1RuleSet { get; set; } public string S1RuleSetName => S1RuleSet.ToDisplayName(); public int? S1Groups { get; set; } public int? S1GroupAdvances { get; set; } public RuleSet? S2RuleSet { get; set; } public string? S2RuleSetName => S2RuleSet?.ToDisplayName(); public List AssociatedEvents { get; set; } = []; public GameDisplay() { } public GameDisplay(Game game) { Id = game.Id; Name = game.Name; Description = game.Description; S1RuleSet = game.S1RuleSet; S1Groups = game.S1Groups; S1GroupAdvances = game.S1GroupAdvances; S2RuleSet = game.S2RuleSet; var events = new HashSet(); if (game.Tournaments != null) { foreach (var t in game.Tournaments) { if (t.Event != null) { events.Add(t.Event.Name); } } } AssociatedEvents = events.ToList(); } } public class RuleSetOption { public RuleSet? Value { get; set; } public string Label { get; set; } = string.Empty; public RuleSetOption() { } public RuleSetOption(RuleSet? value, string label) { Value = value; Label = label; } public override string ToString() => Label; }