using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using LehrerApp.Core.Interfaces; using LehrerApp.Core.Models; using System.Collections.ObjectModel; using System.Text.Json; using System.Text.Json.Serialization; namespace LehrerApp.Desktop.ViewModels.Settings; // ── Haupt-ViewModel ─────────────────────────────────────────────────────────── public partial class SettingsViewModel : ObservableObject { private readonly ISubjectRepository _subjects; private readonly ICompetencyDomainRepository _domainRepo; // ── Fächer ──────────────────────────────────────────────────────────────── [ObservableProperty] private string _newName = ""; [ObservableProperty] private string _newShort = ""; [ObservableProperty] private string _validationMessage = ""; public ObservableCollection Subjects { get; } = []; // ── Kompetenzkatalog ────────────────────────────────────────────────────── [ObservableProperty] private SubjectListItem? _catalogSubject; [ObservableProperty] private int _catalogGradeLevel = 10; [ObservableProperty] private string _newDomainName = ""; [ObservableProperty] private string _newDomainCode = ""; [ObservableProperty] private string _catalogValidation = ""; public ObservableCollection Domains { get; } = []; // ── Konstruktor ─────────────────────────────────────────────────────────── public SettingsViewModel(ISubjectRepository subjects, ICompetencyDomainRepository domainRepo) { _subjects = subjects; _domainRepo = domainRepo; LoadSubjects(); } // ── Fächer: Laden / Hinzufügen / Löschen ───────────────────────────────── public void LoadSubjects() { Subjects.Clear(); foreach (var s in _subjects.GetAll()) Subjects.Add(new SubjectListItem(s)); } [RelayCommand] private void AddSubject() { if (string.IsNullOrWhiteSpace(NewName)) { ValidationMessage = "Name erforderlich."; return; } _subjects.Save(new Subject { Name = NewName.Trim(), ShortName = NewShort.Trim() }); NewName = ""; NewShort = ""; ValidationMessage = ""; LoadSubjects(); } [RelayCommand] private void DeleteSubject(SubjectListItem? item) { if (item is null) return; _subjects.Delete(item.Id); if (CatalogSubject?.Id == item.Id) CatalogSubject = null; LoadSubjects(); } // ── Katalog: Laden ──────────────────────────────────────────────────────── partial void OnCatalogSubjectChanged(SubjectListItem? value) => LoadCatalog(); partial void OnCatalogGradeLevelChanged(int value) => LoadCatalog(); private void LoadCatalog() { Domains.Clear(); CatalogValidation = ""; if (CatalogSubject is null) return; foreach (var d in _domainRepo.GetBySubjectAndGrade(CatalogSubject.Id, CatalogGradeLevel)) Domains.Add(new DomainEditItem(d, _domainRepo)); } // ── Katalog: Bereich hinzufügen / löschen ──────────────────────────────── [RelayCommand] private void AddDomain() { if (CatalogSubject is null) { CatalogValidation = "Bitte zuerst ein Fach auswählen."; return; } if (string.IsNullOrWhiteSpace(NewDomainName)) { CatalogValidation = "Bereichsname erforderlich."; return; } var domain = new CompetencyDomain { SubjectId = CatalogSubject.Id, GradeLevel = CatalogGradeLevel, Name = NewDomainName.Trim(), Code = NewDomainCode.Trim(), SortOrder = Domains.Count, }; _domainRepo.Save(domain); Domains.Add(new DomainEditItem(domain, _domainRepo)); NewDomainName = ""; NewDomainCode = ""; CatalogValidation = ""; } [RelayCommand] private void DeleteDomain(DomainEditItem? item) { if (item is null) return; _domainRepo.Delete(item.Id); Domains.Remove(item); } // ── JSON Import / Export ────────────────────────────────────────────────── public void ImportCatalog(string json) { if (CatalogSubject is null) { CatalogValidation = "Bitte zuerst ein Fach auswählen."; return; } try { var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var dto = JsonSerializer.Deserialize(json, opts); if (dto?.Domains is null) { CatalogValidation = "Ungültiges JSON-Format."; return; } _domainRepo.DeleteBySubjectAndGrade(CatalogSubject.Id, CatalogGradeLevel); for (int i = 0; i < dto.Domains.Count; i++) { var d = dto.Domains[i]; var domain = new CompetencyDomain { SubjectId = CatalogSubject.Id, GradeLevel = CatalogGradeLevel, Name = d.Name ?? "", Code = d.Code ?? "", SortOrder = i, Items = (d.Competencies ?? []) .Select((c, j) => new CompetencyItem { Code = c.Code ?? "", Description = c.Description ?? "", SortOrder = j, }).ToList(), }; _domainRepo.Save(domain); } CatalogValidation = ""; LoadCatalog(); } catch { CatalogValidation = "Import fehlgeschlagen – bitte JSON-Format prüfen."; } } public string ExportCatalog() { var dto = new CatalogDto { Subject = CatalogSubject?.Name ?? "", GradeLevel = CatalogGradeLevel, Domains = Domains.Select(d => new DomainDto { Name = d.Name, Code = d.Code, Competencies = d.Items.Select(i => new CompetencyDto { Code = i.Code, Description = i.Description, }).ToList(), }).ToList(), }; return JsonSerializer.Serialize(dto, new JsonSerializerOptions { WriteIndented = true }); } } // ── DomainEditItem ──────────────────────────────────────────────────────────── public partial class DomainEditItem : ObservableObject { private readonly CompetencyDomain _domain; private readonly ICompetencyDomainRepository _repo; public Guid Id { get; } public string Name { get; } public string Code { get; } public string DisplayName { get; } [ObservableProperty] private string _newItemCode = ""; [ObservableProperty] private string _newItemDesc = ""; public ObservableCollection Items { get; } = []; public DomainEditItem(CompetencyDomain domain, ICompetencyDomainRepository repo) { _domain = domain; _repo = repo; Id = domain.Id; Name = domain.Name; Code = domain.Code; DisplayName = string.IsNullOrEmpty(domain.Code) ? domain.Name : $"{domain.Name} ({domain.Code})"; foreach (var item in domain.Items.OrderBy(i => i.SortOrder)) Items.Add(new CompetencyItemVm(item, DeleteItem)); } [RelayCommand] private void AddItem() { if (string.IsNullOrWhiteSpace(NewItemDesc)) return; var item = new CompetencyItem { Code = NewItemCode.Trim(), Description = NewItemDesc.Trim(), SortOrder = _domain.Items.Count, }; _domain.Items.Add(item); _repo.Save(_domain); Items.Add(new CompetencyItemVm(item, DeleteItem)); NewItemCode = ""; NewItemDesc = ""; } private void DeleteItem(CompetencyItemVm vm) { _domain.Items.RemoveAll(i => i.Id == vm.ItemId); _repo.Save(_domain); Items.Remove(vm); } } // ── CompetencyItemVm ────────────────────────────────────────────────────────── public class CompetencyItemVm { public Guid ItemId { get; } public string Code { get; } public string Description { get; } public string Display { get; } public IRelayCommand DeleteCommand { get; } public CompetencyItemVm(CompetencyItem item, Action onDelete) { ItemId = item.Id; Code = item.Code; Description = item.Description; Display = string.IsNullOrEmpty(item.Code) ? item.Description : $"[{item.Code}] {item.Description}"; DeleteCommand = new RelayCommand(() => onDelete(this)); } } // ── Hilfklassen ─────────────────────────────────────────────────────────────── public class SubjectListItem(Subject s) { public Guid Id { get; } = s.Id; public string Name { get; } = s.Name; public string ShortName { get; } = s.ShortName; } // ── JSON DTOs ───────────────────────────────────────────────────────────────── internal class CatalogDto { [JsonPropertyName("subject")] public string? Subject { get; set; } [JsonPropertyName("gradeLevel")] public int GradeLevel { get; set; } [JsonPropertyName("domains")] public List? Domains { get; set; } } internal class DomainDto { [JsonPropertyName("name")] public string? Name { get; set; } [JsonPropertyName("code")] public string? Code { get; set; } [JsonPropertyName("competencies")] public List? Competencies { get; set; } } internal class CompetencyDto { [JsonPropertyName("code")] public string? Code { get; set; } [JsonPropertyName("description")] public string? Description { get; set; } }