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 }