using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Threading.Tasks; using Toak.Serialization; using Toak.Core.Interfaces; namespace Toak.Core; public class HistoryManager : IHistoryManager { private readonly string HistoryDir = Constants.Paths.AppDataDir; private readonly string HistoryFile = Constants.Paths.HistoryFile; public HistoryManager() { } public void SaveEntry(string rawTranscript, string refinedText, string? skillName, long durationMs) { try { if (!Directory.Exists(HistoryDir)) { Directory.CreateDirectory(HistoryDir); } var entry = new HistoryEntry { Timestamp = DateTime.UtcNow, RawTranscript = rawTranscript, RefinedText = refinedText, SkillName = skillName, DurationMs = durationMs }; var json = JsonSerializer.Serialize(entry, CompactJsonSerializerContext.Default.HistoryEntry); // Thread-safe append lock (HistoryFile) { File.AppendAllLines(HistoryFile, new[] { json }); } } catch (Exception ex) { Logger.LogDebug($"Failed to save history: {ex.Message}"); } } public List LoadHistory() { var entries = new List(); if (!File.Exists(HistoryFile)) return entries; try { string[] lines; lock (HistoryFile) { lines = File.ReadAllLines(HistoryFile); } foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) continue; if (!line.Trim().StartsWith("{") || !line.Trim().EndsWith("}")) continue; // Skip malformed old multiline json entries try { var entry = JsonSerializer.Deserialize(line, CompactJsonSerializerContext.Default.HistoryEntry); if (entry != null) { entries.Add(entry); } } catch { // Skip entry if deserialization fails } } } catch (Exception ex) { Console.WriteLine($"CRASH IN LOAD ENTRIES: {ex}"); Logger.LogDebug($"Failed to load history: {ex.Message}"); } return entries; } public void ClearHistory() { if (File.Exists(HistoryFile)) { try { lock (HistoryFile) { // Securely delete var len = new FileInfo(HistoryFile).Length; using (var fs = new FileStream(HistoryFile, FileMode.Open, FileAccess.Write)) { var blank = new byte[len]; fs.Write(blank, 0, blank.Length); } File.Delete(HistoryFile); } } catch (Exception ex) { Logger.LogDebug($"Failed to shred history: {ex.Message}"); } } } }