using StickyBoard.Core.Common.Exceptions; using StickyBoard.Core.DTOs.SocialAndMessaging; using StickyBoard.Core.Models.SocialAndMessaging; using StickyBoard.Core.Repositories.BoardsAndCards.Contracts; using StickyBoard.Core.Repositories.SocialAndMessaging.Contracts; using StickyBoard.Core.Services.SocialAndMessaging.Contracts; namespace StickyBoard.Core.Services.SocialAndMessaging; public sealed class CardCommentService : ICardCommentService { private readonly ICardRepository _cards; private readonly ICardCommentRepository _comments; public CardCommentService( ICardRepository cards, ICardCommentRepository comments) { _cards = cards; _comments = comments; } // -------------------------------------- // READ // -------------------------------------- public async Task> GetByCardAsync(Guid cardId, CancellationToken ct) { if (!await _cards.ExistsAsync(cardId, ct)) throw new NotFoundException("Card not found."); var list = await _comments.GetByCardIdAsync(cardId, ct); return list.Select(MapToDto); } public async Task> GetThreadAsync(Guid cardId, Guid rootCommentId, CancellationToken ct) { if (!await _cards.ExistsAsync(cardId, ct)) throw new NotFoundException("Card not found."); var list = await _comments.GetThreadAsync(cardId, rootCommentId, ct); return list.Select(MapToDto); } // -------------------------------------- // WRITE // -------------------------------------- public async Task CreateAsync(Guid cardId, Guid userId, CardCommentCreateDto dto, CancellationToken ct) { if (!await _cards.ExistsAsync(cardId, ct)) throw new NotFoundException("Card not found."); var entity = new CardComment { CardId = cardId, UserId = userId, ParentId = dto.ParentId, Content = dto.Content }; return await _comments.CreateAsync(entity, ct); } public async Task UpdateAsync(Guid commentId, Guid userId, CardCommentUpdateDto dto, CancellationToken ct) { var existing = await _comments.GetByIdAsync(commentId, ct) ?? throw new NotFoundException("Comment not found."); if (existing.UserId != userId) throw new ForbiddenException("Cannot edit this comment."); existing.Content = dto.Content; return await _comments.UpdateAsync(existing, ct); } public async Task DeleteAsync(Guid commentId, Guid userId, CancellationToken ct) { var existing = await _comments.GetByIdAsync(commentId, ct) ?? throw new NotFoundException("Comment not found."); if (existing.UserId != userId) throw new ForbiddenException("Cannot delete this comment."); return await _comments.DeleteAsync(commentId, ct); } private static CardCommentDto MapToDto(CardComment c) { return new CardCommentDto { Id = c.Id, CardId = c.CardId, ParentId = c.ParentId, UserId = c.UserId, Content = c.Content, CreatedAt = c.CreatedAt, UpdatedAt = c.UpdatedAt }; } }