using System.IO; using System.Text.Json; namespace Housing.Services; public sealed class LoginHistoryStore { private const int MaxHistoryCount = 3; private readonly string _filePath; private readonly LoginHistoryData _data; private LoginHistoryStore(string filePath, LoginHistoryData data) { _filePath = filePath; _data = data; } public static LoginHistoryStore Load(string filePath) { try { if (!File.Exists(filePath)) { return new LoginHistoryStore(filePath, new LoginHistoryData()); } var json = File.ReadAllText(filePath); var data = JsonSerializer.Deserialize(json) ?? new LoginHistoryData(); data.Fields ??= new Dictionary>(); return new LoginHistoryStore(filePath, data); } catch { return new LoginHistoryStore(filePath, new LoginHistoryData()); } } public IReadOnlyList GetValues(string fieldName) { return _data.Fields.TryGetValue(fieldName, out var values) ? values.Where(value => !string.IsNullOrWhiteSpace(value)).Take(MaxHistoryCount).ToArray() : Array.Empty(); } public void Remember(string fieldName, string value) { if (string.IsNullOrWhiteSpace(value)) { return; } if (!_data.Fields.TryGetValue(fieldName, out var values)) { values = new List(); _data.Fields[fieldName] = values; } values.RemoveAll(item => string.Equals(item, value, StringComparison.OrdinalIgnoreCase)); values.Insert(0, value); if (values.Count > MaxHistoryCount) { values.RemoveRange(MaxHistoryCount, values.Count - MaxHistoryCount); } } public bool Forget(string fieldName, string value) { if (string.IsNullOrWhiteSpace(value) || !_data.Fields.TryGetValue(fieldName, out var values)) { return false; } var removedCount = values.RemoveAll(item => string.Equals(item, value, StringComparison.OrdinalIgnoreCase)); if (values.Count == 0) { _data.Fields.Remove(fieldName); } return removedCount > 0; } public void Save() { var directory = Path.GetDirectoryName(_filePath); if (!string.IsNullOrWhiteSpace(directory)) { Directory.CreateDirectory(directory); } var json = JsonSerializer.Serialize(_data, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(_filePath, json); } private sealed class LoginHistoryData { public Dictionary> Fields { get; set; } = new(StringComparer.OrdinalIgnoreCase); } }