using Journal.Core.Dtos; using Journal.Core.Repositories; namespace Journal.Core.Services; public sealed class EntryFileService(IEntryFileRepository repo) : IEntryFileService { private readonly IEntryFileRepository _repo = repo ?? throw new ArgumentNullException(nameof(repo)); public IReadOnlyList ListEntries(string dataDirectory) { return [.. _repo.ListMarkdownFiles(dataDirectory) .Select(path => new EntryListItem( FileName: _repo.GetFileName(path), FilePath: _repo.GetFullPath(path)))]; } public EntryLoadResult LoadEntry(string filePath) { var normalizedPath = _repo.GetFullPath(filePath); if (!_repo.FileExists(normalizedPath)) throw new FileNotFoundException($"Entry file not found: {normalizedPath}"); var rawContent = HtmlSanitizer.StripRichHtml(_repo.ReadFile(normalizedPath)); var fileStem = _repo.GetFileNameWithoutExtension(normalizedPath); var entry = JournalParser.ParseJournalContent(rawContent, fileStem); return new EntryLoadResult( Date: entry.Date, FileName: _repo.GetFileName(normalizedPath), FilePath: normalizedPath, RawContent: entry.RawContent); } public EntrySaveResult SaveEntry(EntrySavePayload payload, string defaultDataDirectory) { var targetPath = ResolveTargetPath(payload.FilePath, defaultDataDirectory); var mode = string.IsNullOrWhiteSpace(payload.Mode) ? "Daily" : payload.Mode.Trim(); var sanitizedContent = HtmlSanitizer.StripRichHtml(payload.Content ?? ""); _repo.EnsureDirectory(targetPath); if (string.Equals(mode, "Overwrite", StringComparison.OrdinalIgnoreCase)) { _repo.WriteFile(targetPath, sanitizedContent); return new EntrySaveResult(targetPath); } if (string.Equals(mode, "Fragment", StringComparison.OrdinalIgnoreCase)) { _repo.AppendFile(targetPath, "\n\n" + sanitizedContent.Trim()); return new EntrySaveResult(targetPath); } string finalContent; if (_repo.FileExists(targetPath)) { var existingContent = _repo.ReadFile(targetPath); var fileStem = _repo.GetFileNameWithoutExtension(targetPath); var existingEntry = JournalParser.ParseJournalContent(existingContent, fileStem); var newEntryData = JournalParser.ParseJournalContent(sanitizedContent, fileStem); existingEntry.MergeWith(newEntryData); finalContent = existingEntry.ToMarkdown(); } else { finalContent = sanitizedContent; } _repo.WriteFile(targetPath, finalContent); return new EntrySaveResult(targetPath); } private string ResolveTargetPath(string? filePath, string defaultDataDirectory) { if (!string.IsNullOrWhiteSpace(filePath)) return _repo.GetFullPath(filePath); return _repo.GetFullPath(Path.Combine(defaultDataDirectory, $"{DateTime.Now:yyyy-MM-dd}.md")); } }