using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LehrerApp.Core.Interfaces;
using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
namespace LehrerApp.Desktop.ViewModels.Planning;
/// Zuweisen/Bearbeiten/Entfernen eines Stundenplan-Termins (4.3.3).
public partial class TimetableSlotDialogViewModel : ObservableObject
{
private readonly ITimetableSlotRepository _slots;
private readonly Dictionary _groupIdsByLabel;
private readonly TimetableSlot? _editing;
public DayOfWeek Weekday { get; }
public int PeriodNumber { get; }
public string WeekdayLabel { get; }
public string DialogTitle { get; }
public bool IsEditing => _editing is not null;
[ObservableProperty] private string _selectedGroupName = "";
[ObservableProperty] private string _room = "";
[ObservableProperty] private string _groupError = "";
public string[] GroupOptions { get; }
/// null = unverändert/Abbruch, sonst das neue/aktualisierte Ergebnis.
public TimetableSlot? Result { get; private set; }
public bool Deleted { get; private set; }
public TimetableSlotDialogViewModel(ITimetableSlotRepository slots, IGroupRepository groups,
ISubjectRepository subjects, SchoolYearService schoolYear, DayOfWeek weekday, int periodNumber,
TimetableSlot? editing)
{
_slots = slots;
_editing = editing;
Weekday = weekday;
PeriodNumber = periodNumber;
WeekdayLabel = weekday switch
{
DayOfWeek.Monday => "Montag", DayOfWeek.Tuesday => "Dienstag",
DayOfWeek.Wednesday => "Mittwoch", DayOfWeek.Thursday => "Donnerstag",
DayOfWeek.Friday => "Freitag", _ => weekday.ToString(),
};
DialogTitle = $"{WeekdayLabel}, {periodNumber}. Stunde";
var availableGroups = groups.GetBySchoolYear(schoolYear.CurrentSchoolYear()).OrderBy(g => g.Name).ToList();
var subjectNames = subjects.GetAll().ToDictionary(s => s.Id, s => s.Name);
var nameCounts = availableGroups.GroupBy(g => g.Name).ToDictionary(g => g.Key, g => g.Count());
// Der Gruppenname allein ist nicht eindeutig: dieselbe Klasse in mehreren Fächern hat
// mehrere LearningGroup-Datensätze mit demselben Namen. Bei einem Namenskonflikt wird
// deshalb das Fach angehängt ("10c (Chemie)") — ohne diese Absicherung würde die
// Dictionary-Befüllung unten mit einer ArgumentException abstürzen (echter Nutzer-Fehler).
_groupIdsByLabel = new Dictionary();
var labeledGroups = new List<(string Label, Guid Id)>();
foreach (var g in availableGroups)
{
var label = nameCounts[g.Name] > 1
? $"{g.Name} ({(g.SubjectId is { } sid && subjectNames.TryGetValue(sid, out var sn) ? sn : "ohne Fach")})"
: g.Name;
var uniqueLabel = label;
var suffix = 2;
while (_groupIdsByLabel.ContainsKey(uniqueLabel)) uniqueLabel = $"{label} ({suffix++})";
_groupIdsByLabel[uniqueLabel] = g.Id;
labeledGroups.Add((uniqueLabel, g.Id));
}
GroupOptions = labeledGroups.Select(x => x.Label).ToArray();
if (editing is not null)
{
SelectedGroupName = labeledGroups.FirstOrDefault(x => x.Id == editing.GroupId).Label ?? "";
Room = editing.Room ?? "";
}
}
[RelayCommand]
private void Save()
{
GroupError = "";
if (string.IsNullOrWhiteSpace(SelectedGroupName) || !_groupIdsByLabel.TryGetValue(SelectedGroupName, out var groupId))
{
GroupError = "Bitte eine Gruppe auswählen.";
return;
}
var slot = _editing ?? new TimetableSlot { Weekday = Weekday, PeriodNumber = PeriodNumber };
slot.GroupId = groupId;
slot.Room = string.IsNullOrWhiteSpace(Room) ? null : Room.Trim();
try
{
_slots.Save(slot);
Result = slot;
}
catch (InvalidOperationException ex)
{
GroupError = ex.Message;
}
}
[RelayCommand]
private void Delete()
{
if (_editing is null) return;
_slots.Delete(_editing.Id);
Deleted = true;
}
}