using LehrerApp.Core.Interfaces; using LehrerApp.Core.Services; using LehrerApp.Data; using LehrerApp.Data.Repositories; using LehrerApp.Desktop.ViewModels; using LehrerApp.Desktop.ViewModels.Groups; using LehrerApp.Desktop.ViewModels.Students; using LehrerApp.Sync; using LehrerApp.Sync.Crypto; using LehrerApp.Sync.Models; using Microsoft.Extensions.DependencyInjection; namespace LehrerApp.Desktop; /// /// Konfiguriert den DI-Container für den Desktop-Client. /// /// WICHTIG: Alle Repositories sind Singleton – eine LiteDB-Datei pro Nutzer. /// Sync-Services werden nur registriert wenn eine Server-URL konfiguriert ist. /// public static class AppBootstrapper { public static string DbPath { get; private set; } = ""; public static string AppDataPath { get; private set; } = ""; public static IServiceProvider BuildServices() { var services = new ServiceCollection(); // ── Pfade ───────────────────────────────────────────────────────────── var appData = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LehrerApp"); Directory.CreateDirectory(appData); AppDataPath = appData; DbPath = Path.Combine(appData, "lehrerapp.db"); var queuePath = Path.Combine(appData, "syncqueue.db"); var keyPath = Path.Combine(appData, "sync.key"); // ── Datenbank ───────────────────────────────────────────────────────── services.AddSingleton(_ => new LiteDbContext(DbPath)); // ── Repositories ────────────────────────────────────────────────────── services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // ── Services ────────────────────────────────────────────────────────── services.AddSingleton(); services.AddSingleton(); // ── Sync (optional – nur wenn Server konfiguriert) ──────────────────── services.AddSingleton(_ => new EventQueue(queuePath)); services.AddSingleton(sp => new ConflictResolver(sp.GetRequiredService())); services.AddSingleton(_ => { var key = SyncCrypto.LoadKey(keyPath) ?? SyncCrypto.GenerateKey(); SyncCrypto.SaveKey(key, keyPath); return key; }); var serverUrl = LoadServerUrl(appData); var deviceId = LoadOrCreateDeviceId(appData); if (!string.IsNullOrEmpty(serverUrl)) { services.AddSingleton(sp => new SyncEngine( sp.GetRequiredService(), sp.GetRequiredService(), BuildHttp(serverUrl, appData), new SyncConfig { ServerUrl = serverUrl, DeviceId = deviceId, DeviceType = DeviceType.Desktop, AutoSyncIntervalMinutes = 5, })); services.AddSingleton(sp => new SnapshotService( BuildHttp(serverUrl, appData), sp.GetRequiredService(), sp.GetRequiredService(), DeviceType.Desktop, DbPath, keyPath)); } // ── ViewModels ──────────────────────────────────────────────────────── // Singleton: einmal erstellt, überall dieselbe Instanz services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => new SyncStatusViewModel(sp.GetService())); services.AddSingleton(); services.AddSingleton(); // Transient: neue Instanz pro Navigation (für Detailseiten) services.AddTransient(); services.AddTransient(); services.AddTransient(); return services.BuildServiceProvider(); } // ── Hilfsmethoden ───────────────────────────────────────────────────────── private static HttpClient BuildHttp(string url, string appData) { var http = new HttpClient { BaseAddress = new Uri(url) }; var tokenPath = Path.Combine(appData, "auth.token"); if (File.Exists(tokenPath)) http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Bearer", File.ReadAllText(tokenPath).Trim()); return http; } public static string LoadServerUrl(string? path = null) => File.Exists(Path.Combine(path ?? AppDataPath, "server.txt")) ? File.ReadAllText(Path.Combine(path ?? AppDataPath, "server.txt")).Trim() : ""; public static void SaveServerUrl(string url) => File.WriteAllText(Path.Combine(AppDataPath, "server.txt"), url); private static string LoadOrCreateDeviceId(string appData) { var p = Path.Combine(appData, "device.id"); if (File.Exists(p)) return File.ReadAllText(p).Trim(); var id = Guid.NewGuid().ToString(); File.WriteAllText(p, id); return id; } }