using Core.Entities; using Data; using Microsoft.EntityFrameworkCore; using System.Security.Claims; namespace WebApp.Services; public class NotesService : INotesService { private readonly AppDbContext _context; private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; public NotesService( AppDbContext context, IHttpContextAccessor httpContextAccessor, ILogger logger) { _context = context; _httpContextAccessor = httpContextAccessor; _logger = logger; } private string? GetCurrentUserEmail() { var user = _httpContextAccessor.HttpContext?.User; if (user == null) return null; return user.FindFirstValue(ClaimTypes.Email) ?? user.Identity?.Name; } public async Task> GetNotesAsync() { return await _context.Notes .AsNoTracking() .OrderByDescending(n => n.UpdatedAt) .ToListAsync(); } public async Task GetNoteAsync(int id) { return await _context.Notes .Include(n => n.NoteHistories.OrderByDescending(h => h.ModifiedAt)) .FirstOrDefaultAsync(n => n.Id == id); } public async Task> GetNoteHistoryAsync(int noteId) { return await _context.NoteHistories .AsNoTracking() .Where(h => h.NoteId == noteId) .OrderByDescending(h => h.ModifiedAt) .Take(10) .ToListAsync(); } public async Task CreateNoteAsync(Note note) { var userEmail = GetCurrentUserEmail(); var now = DateTime.UtcNow; note.CreatedAt = now; note.UpdatedAt = now; note.CreatedBy = userEmail; note.LastModifiedBy = userEmail; _context.Notes.Add(note); await _context.SaveChangesAsync(); // Create initial history entry var history = new NoteHistory { NoteId = note.Id, Title = note.Title, Content = note.Content, ModifiedBy = userEmail, ModifiedAt = now, ChangeType = "Created" }; _context.NoteHistories.Add(history); await _context.SaveChangesAsync(); _logger.LogInformation("Note created: {NoteId} by {User}", note.Id, userEmail); return note; } public async Task UpdateNoteAsync(Note note) { var existingNote = await _context.Notes .FirstOrDefaultAsync(n => n.Id == note.Id); if (existingNote == null) { throw new InvalidOperationException($"Note with ID {note.Id} not found."); } var userEmail = GetCurrentUserEmail(); var now = DateTime.UtcNow; // Create history entry with previous state before updating var history = new NoteHistory { NoteId = existingNote.Id, Title = existingNote.Title, Content = existingNote.Content, ModifiedBy = userEmail, ModifiedAt = now, ChangeType = "Updated" }; _context.NoteHistories.Add(history); // Update the note existingNote.Title = note.Title; existingNote.Content = note.Content; existingNote.UpdatedAt = now; existingNote.LastModifiedBy = userEmail; await _context.SaveChangesAsync(); _logger.LogInformation("Note updated: {NoteId} by {User}", note.Id, userEmail); return existingNote; } public async Task DeleteNoteAsync(int id) { var note = await _context.Notes .FirstOrDefaultAsync(n => n.Id == id); if (note == null) { throw new InvalidOperationException($"Note with ID {id} not found."); } var userEmail = GetCurrentUserEmail(); var now = DateTime.UtcNow; // Create deletion history entry var history = new NoteHistory { NoteId = note.Id, Title = note.Title, Content = note.Content, ModifiedBy = userEmail, ModifiedAt = now, ChangeType = "Deleted" }; _context.NoteHistories.Add(history); // Delete the note (cascade will handle history, but we want to keep history) _context.Notes.Remove(note); await _context.SaveChangesAsync(); _logger.LogInformation("Note deleted: {NoteId} by {User}", id, userEmail); } }