veza/veza-backend-api/internal/services/playlist_analytics_service.go
2025-12-03 20:29:37 +01:00

121 lines
4.3 KiB
Go

package services
import (
"context"
"errors"
"fmt"
"github.com/google/uuid" // Added import for uuid
"go.uber.org/zap"
"gorm.io/gorm"
"veza-backend-api/internal/models"
)
// PlaylistAnalyticsService gère les analytics de playlists
// T0491: Create Playlist Analytics Backend
type PlaylistAnalyticsService struct {
db *gorm.DB
logger *zap.Logger
}
// NewPlaylistAnalyticsService crée un nouveau service d'analytics de playlists
func NewPlaylistAnalyticsService(db *gorm.DB, logger *zap.Logger) *PlaylistAnalyticsService {
if logger == nil {
logger = zap.NewNop()
}
return &PlaylistAnalyticsService{
db: db,
logger: logger,
}
}
// PlaylistStats représente les statistiques d'une playlist
type PlaylistStats struct {
Plays int64 `json:"plays"` // Nombre total de lectures (somme des plays des tracks)
Shares int64 `json:"shares"` // Nombre de liens de partage créés
Likes int64 `json:"likes"` // Nombre de follows (équivalent aux likes)
Followers int64 `json:"followers"` // Nombre de followers (déjà dans Playlist.FollowerCount)
TrackCount int `json:"track_count"` // Nombre de tracks dans la playlist
}
// GetPlaylistStats récupère les statistiques d'une playlist
func (s *PlaylistAnalyticsService) GetPlaylistStats(ctx context.Context, playlistID uuid.UUID) (*PlaylistStats, error) { // Changed playlistID to uuid.UUID
// Vérifier que la playlist existe
var playlist models.Playlist
if err := s.db.WithContext(ctx).First(&playlist, "id = ?", playlistID).Error; err != nil { // Updated query
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("playlist not found")
}
return nil, fmt.Errorf("failed to get playlist: %w", err)
}
var stats PlaylistStats
// Track count (déjà dans le modèle)
stats.TrackCount = playlist.TrackCount
// Followers count (déjà dans le modèle)
stats.Followers = int64(playlist.FollowerCount)
// Count shares (nombre de liens de partage créés, non supprimés)
if err := s.db.WithContext(ctx).Model(&models.PlaylistShareLink{}).
Where("playlist_id = ? AND deleted_at IS NULL", playlistID).
Count(&stats.Shares).Error; err != nil {
return nil, fmt.Errorf("failed to count shares: %w", err)
}
// Count likes (nombre de follows, non supprimés)
if err := s.db.WithContext(ctx).Model(&models.PlaylistFollow{}).
Where("playlist_id = ? AND deleted_at IS NULL", playlistID).
Count(&stats.Likes).Error; err != nil {
return nil, fmt.Errorf("failed to count likes: %w", err)
}
// Count plays: somme des plays de tous les tracks dans la playlist
// On compte les TrackPlay pour tous les tracks de la playlist
type PlayCountResult struct {
TotalPlays int64
}
var playCountResult PlayCountResult
// Récupérer tous les track IDs de la playlist
var trackIDs []uuid.UUID // Changed to []uuid.UUID
if err := s.db.WithContext(ctx).Model(&models.PlaylistTrack{}).
Where("playlist_id = ?", playlistID).
Pluck("track_id", &trackIDs).Error; err != nil {
return nil, fmt.Errorf("failed to get playlist tracks: %w", err)
}
// Si la playlist a des tracks, compter les plays
if len(trackIDs) > 0 {
if err := s.db.WithContext(ctx).Model(&models.TrackPlay{}).
Where("track_id IN ?", trackIDs).
Count(&playCountResult.TotalPlays).Error; err != nil {
return nil, fmt.Errorf("failed to count plays: %w", err)
}
}
stats.Plays = playCountResult.TotalPlays
s.logger.Debug("Playlist stats retrieved",
zap.Any("playlist_id", playlistID), // Changed to zap.Any for uuid.UUID
zap.Int64("plays", stats.Plays),
zap.Int64("shares", stats.Shares),
zap.Int64("likes", stats.Likes),
zap.Int64("followers", stats.Followers),
)
return &stats, nil
}
// IncrementPlaylistPlays incrémente le compteur de plays d'une playlist
// Cette méthode peut être appelée lorsqu'un track de la playlist est joué
func (s *PlaylistAnalyticsService) IncrementPlaylistPlays(ctx context.Context, playlistID uuid.UUID) error { // Changed playlistID to uuid.UUID
// Note: Pour l'instant, on ne stocke pas de compteur de plays dans Playlist
// car on le calcule dynamiquement à partir des TrackPlay
// Cette méthode est prévue pour une future optimisation avec cache
s.logger.Debug("Playlist play incremented",
zap.Any("playlist_id", playlistID), // Changed to zap.Any for uuid.UUID
)
return nil
}