package service import ( "context" "fmt" "sort" "time" "route256/comments/internal/domain/entity" "route256/comments/internal/domain/model" ) type CommentRepository interface { GetCommentByID(ctx context.Context, id int64) (*entity.Comment, error) InsertComment(ctx context.Context, comment *entity.Comment) (*entity.Comment, error) ListCommentsBySku(ctx context.Context, sku int64) ([]*entity.Comment, error) ListCommentsByUser(ctx context.Context, userID int64) ([]*entity.Comment, error) UpdateComment(ctx context.Context, comment *entity.Comment) (*entity.Comment, error) } type CommentsService struct { comments CommentRepository timeout time.Duration } func NewCommentsService(commRepo CommentRepository, timeout time.Duration) *CommentsService { return &CommentsService{ comments: commRepo, timeout: timeout, } } func (s *CommentsService) checkTimeout(newTime, oldTime time.Time) error { if newTime.Sub(oldTime) >= s.timeout { return model.ErrCommentEditTimeout } return nil } func (s *CommentsService) CommentCreate(ctx context.Context, comment *entity.Comment) (int64, error) { comm, err := s.comments.InsertComment(ctx, &entity.Comment{ UserID: comment.UserID, SKU: comment.SKU, CreatedAt: time.Now(), Text: comment.Text, }) if err != nil { return 0, fmt.Errorf("repository.InsertComment: %w", err) } return comm.ID, nil } func (s *CommentsService) CommentGetByID(ctx context.Context, id int64) (*entity.Comment, error) { if id <= 0 { return nil, fmt.Errorf("comment id must be greater than 0") } comm, err := s.comments.GetCommentByID(ctx, id) if err != nil { return nil, fmt.Errorf("repository.InsertComment: %w", err) } return comm, nil } func (s *CommentsService) CommentEdit(ctx context.Context, newComment *entity.Comment) error { if newComment.ID <= 0 { return fmt.Errorf("comment id must be greater than 0") } oldComment, err := s.comments.GetCommentByID(ctx, newComment.ID) if err != nil { return fmt.Errorf("repository.GetCommentByID: %w", err) } if oldComment.UserID != newComment.UserID { return model.ErrCommentEditUserMismatch } comment := &entity.Comment{ ID: newComment.ID, UserID: newComment.UserID, SKU: newComment.SKU, CreatedAt: time.Now(), Text: newComment.Text, } if err := s.checkTimeout(comment.CreatedAt, oldComment.CreatedAt); err != nil { return err } if _, err := s.comments.UpdateComment(ctx, comment); err != nil { return fmt.Errorf("repository.UpdateComment: %w", err) } return nil } func (s *CommentsService) CommentListBySKU(ctx context.Context, sku int64) ([]*entity.Comment, error) { if sku <= 0 { return nil, fmt.Errorf("sku must be greater than 0") } comms, err := s.comments.ListCommentsBySku(ctx, sku) if err != nil { return nil, fmt.Errorf("repository.ListCommentsBySku: %w", err) } return comms, nil } func (s *CommentsService) CommentListByUser(ctx context.Context, userID int64) ([]*entity.Comment, error) { if userID <= 0 { return nil, fmt.Errorf("userID must be greater than 0") } comms, err := s.comments.ListCommentsByUser(ctx, userID) if err != nil { return nil, fmt.Errorf("repository.ListCommentsByUser: %w", err) } sort.Slice(comms, func(i, j int) bool { if comms[i].CreatedAt.Equal(comms[j].CreatedAt) { return comms[i].UserID < comms[j].UserID } return comms[i].CreatedAt.After(comms[j].CreatedAt) }) return comms, nil }