using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.Json; namespace UtopiaCanteenSystem.Services; /// /// Simple JSON-backed configuration stored alongside the app binaries. /// public class ConfigService : IConfigService { private readonly string _configPath; private AppConfig _config; public ConfigService() { _configPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); _config = LoadConfig(); } public string GetSyncApiEndpoint() => _config.SyncApiEndpoint ?? string.Empty; public void SetSyncApiEndpoint(string endpoint) { _config.SyncApiEndpoint = endpoint ?? string.Empty; SaveConfig(); } public bool GetScannerConnected() => _config.ScannerConnected; public void SetScannerConnected(bool connected) { _config.ScannerConnected = connected; SaveConfig(); } public int GetScanTimeoutSeconds() => _config.ScanTimeoutSeconds; public void SetScanTimeoutSeconds(int seconds) { _config.ScanTimeoutSeconds = seconds; SaveConfig(); } public string GetAdminCardId() => _config.AdminCardId ?? string.Empty; public void SetAdminCardId(string cardId) { _config.AdminCardId = cardId ?? string.Empty; SaveConfig(); } public string GetSiteId() { // Normalize to a 2-digit string (e.g. "02", "07", "12"). // Accepts legacy values like "SITE : 2" or "2" and converts them. var raw = _config.SiteId; if (string.IsNullOrWhiteSpace(raw)) return "01"; var digits = new string(raw.Where(char.IsDigit).ToArray()); if (string.IsNullOrWhiteSpace(digits)) return "01"; if (!int.TryParse(digits, out var numeric)) return "01"; return Math.Clamp(numeric, 0, 99).ToString("D2"); } public void SetSiteId(string siteId) { // Store the normalized 2-digit site code. var normalized = siteId; if (string.IsNullOrWhiteSpace(normalized)) { normalized = "01"; } else { var digits = new string(normalized.Where(char.IsDigit).ToArray()); if (string.IsNullOrWhiteSpace(digits) || !int.TryParse(digits, out var numeric)) { normalized = "01"; } else { normalized = Math.Clamp(numeric, 0, 99).ToString("D2"); } } _config.SiteId = normalized; SaveConfig(); } public string GetDeviceId() { //var id = _config.DeviceId ?? string.Empty; var id = Environment.MachineName; if (string.IsNullOrWhiteSpace(id)) { id = Guid.NewGuid().ToString("N"); _config.DeviceId = id; SaveConfig(); } return id; } public void SetDeviceId(string deviceId) { _config.DeviceId = deviceId ?? string.Empty; SaveConfig(); } public bool GetRememberAdminCredentials() => _config.RememberAdminCredentials; public void SetRememberAdminCredentials(bool remember) { _config.RememberAdminCredentials = remember; SaveConfig(); } public string GetSavedAdminUsername() => _config.SavedAdminUsername ?? string.Empty; public void SetSavedAdminUsername(string username) { _config.SavedAdminUsername = username ?? string.Empty; SaveConfig(); } public string GetSavedAdminPassword() { if (!_config.RememberAdminCredentials) return string.Empty; var protectedValue = _config.SavedAdminPasswordProtected ?? string.Empty; if (string.IsNullOrWhiteSpace(protectedValue)) return string.Empty; try { var bytes = Convert.FromBase64String(protectedValue); var clear = ProtectedData.Unprotect(bytes, null, DataProtectionScope.CurrentUser); return Encoding.UTF8.GetString(clear); } catch { return string.Empty; } } public void SetSavedAdminPassword(string password) { if (!_config.RememberAdminCredentials) { _config.SavedAdminPasswordProtected = string.Empty; SaveConfig(); return; } try { var clear = Encoding.UTF8.GetBytes(password ?? string.Empty); var protectedBytes = ProtectedData.Protect(clear, null, DataProtectionScope.CurrentUser); _config.SavedAdminPasswordProtected = Convert.ToBase64String(protectedBytes); } catch { _config.SavedAdminPasswordProtected = string.Empty; } SaveConfig(); } /// /// Returns MySQL connection string for sync. Set via appsettings.json (copy from appsettings.example.json). /// No default credentials; returns empty if not configured. /// public string GetMySqlConnectionString() => (_config.MySqlConnectionString ?? string.Empty).Trim(); public void SetMySqlConnectionString(string connectionString) { _config.MySqlConnectionString = connectionString ?? string.Empty; SaveConfig(); } private AppConfig LoadConfig() { try { if (!File.Exists(_configPath)) { var defaults = new AppConfig(); SaveConfig(defaults); return defaults; } var json = File.ReadAllText(_configPath); var config = JsonSerializer.Deserialize(json); return config ?? new AppConfig(); } catch { return new AppConfig(); } } private void SaveConfig() { SaveConfig(_config); } private void SaveConfig(AppConfig config) { try { var json = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(_configPath, json); } catch { // Ignore write failures (e.g., read-only location). } } private sealed class AppConfig { public string SyncApiEndpoint { get; set; } = "https://api.example.com/uind/sync"; public bool ScannerConnected { get; set; } = false; public int ScanTimeoutSeconds { get; set; } = 60; public string AdminCardId { get; set; } = "ADMIN"; public string SiteId { get; set; } = "SITE : 1"; public string DeviceId { get; set; } = string.Empty; // Admin credential persistence (optional). public bool RememberAdminCredentials { get; set; } = false; public string SavedAdminUsername { get; set; } = string.Empty; public string SavedAdminPasswordProtected { get; set; } = string.Empty; // MySQL connection string for sync. Set in appsettings.json (see appsettings.example.json). No default. public string MySqlConnectionString { get; set; } = string.Empty; } }