package service import ( "context" "fmt" "tailly_clips/internal/domain" "tailly_clips/internal/repository" "time" ) type LikeService interface { LikeClip(ctx context.Context, clipID, userID int) (*domain.ClipLike, error) UnlikeClip(ctx context.Context, clipID, userID int) error GetClipLikes(ctx context.Context, clipID, limit, offset int) ([]*domain.ClipLike, int, error) CheckIfLiked(ctx context.Context, clipID, userID int) (bool, error) } type likeService struct { likeRepo repository.LikeRepository clipRepo repository.ClipRepository } func NewLikeService(likeRepo repository.LikeRepository, clipRepo repository.ClipRepository) LikeService { return &likeService{ likeRepo: likeRepo, clipRepo: clipRepo, } } func (s *likeService) LikeClip(ctx context.Context, clipID, userID int) (*domain.ClipLike, error) { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return nil, fmt.Errorf("clip not found: %w", err) } // Проверяем не лайкнул ли уже пользователь alreadyLiked, err := s.likeRepo.CheckExists(ctx, clipID, userID) if err != nil { return nil, fmt.Errorf("failed to check like existence: %w", err) } if alreadyLiked { return nil, fmt.Errorf("user already liked this clip") } // Создаем лайк like := &domain.ClipLike{ ClipID: clipID, UserID: userID, CreatedAt: time.Now(), } if err := s.likeRepo.Create(ctx, like); err != nil { return nil, fmt.Errorf("failed to create like: %w", err) } // Увеличиваем счетчик лайков if err := s.clipRepo.IncrementLikesCount(ctx, clipID); err != nil { // Откатываем создание лайка при ошибке s.likeRepo.Delete(ctx, clipID, userID) return nil, fmt.Errorf("failed to increment likes count: %w", err) } return like, nil } func (s *likeService) UnlikeClip(ctx context.Context, clipID, userID int) error { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return fmt.Errorf("clip not found: %w", err) } // Удаляем лайк if err := s.likeRepo.Delete(ctx, clipID, userID); err != nil { return fmt.Errorf("failed to delete like: %w", err) } // Уменьшаем счетчик лайков if err := s.clipRepo.DecrementLikesCount(ctx, clipID); err != nil { return fmt.Errorf("failed to decrement likes count: %w", err) } return nil } func (s *likeService) GetClipLikes(ctx context.Context, clipID, limit, offset int) ([]*domain.ClipLike, int, error) { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return nil, 0, fmt.Errorf("clip not found: %w", err) } likes, totalCount, err := s.likeRepo.GetByClipID(ctx, clipID, limit, offset) if err != nil { return nil, 0, fmt.Errorf("failed to get clip likes: %w", err) } return likes, totalCount, nil } func (s *likeService) CheckIfLiked(ctx context.Context, clipID, userID int) (bool, error) { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return false, fmt.Errorf("clip not found: %w", err) } isLiked, err := s.likeRepo.CheckExists(ctx, clipID, userID) if err != nil { return false, fmt.Errorf("failed to check like status: %w", err) } return isLiked, nil }