const { db } = require('../../db'); const notifications = require('./notifications'); // ── Lookup statements for notification context ─────────────────────────────── const songOwnerStmt = db.prepare('SELECT uploaded_by, title, slug FROM songs WHERE id = ?'); const playlistOwnerStmt = db.prepare('SELECT created_by, title, slug FROM playlists WHERE id = ?'); const userNameStmt = db.prepare('SELECT display_name FROM users WHERE id = ?'); function getActorName(actorId) { return actorId ? (userNameStmt.get(actorId)?.display_name || null) : null; } // ── Song statements ────────────────────────────────────────────────────────── const songLikeCountStmt = db.prepare('SELECT COUNT(*) AS c FROM song_likes WHERE song_id = ?'); const songFavCountStmt = db.prepare('SELECT COUNT(*) AS c FROM song_favorites WHERE song_id = ?'); const songUserLikedStmt = db.prepare('SELECT 1 FROM song_likes WHERE user_id = ? AND song_id = ?'); const songUserFavoritedStmt = db.prepare('SELECT 1 FROM song_favorites WHERE user_id = ? AND song_id = ?'); const insertSongLike = db.prepare('INSERT OR IGNORE INTO song_likes (user_id, song_id) VALUES (?, ?)'); const deleteSongLike = db.prepare('DELETE FROM song_likes WHERE user_id = ? AND song_id = ?'); const insertSongFav = db.prepare('INSERT OR IGNORE INTO song_favorites (user_id, song_id) VALUES (?, ?)'); const deleteSongFav = db.prepare('DELETE FROM song_favorites WHERE user_id = ? AND song_id = ?'); // ── Playlist statements ────────────────────────────────────────────────────── const plLikeCountStmt = db.prepare('SELECT COUNT(*) AS c FROM playlist_likes WHERE playlist_id = ?'); const plFavCountStmt = db.prepare('SELECT COUNT(*) AS c FROM playlist_favorites WHERE playlist_id = ?'); const plUserLikedStmt = db.prepare('SELECT 1 FROM playlist_likes WHERE user_id = ? AND playlist_id = ?'); const plUserFavoritedStmt = db.prepare('SELECT 1 FROM playlist_favorites WHERE user_id = ? AND playlist_id = ?'); const insertPlLike = db.prepare('INSERT OR IGNORE INTO playlist_likes (user_id, playlist_id) VALUES (?, ?)'); const deletePlLike = db.prepare('DELETE FROM playlist_likes WHERE user_id = ? AND playlist_id = ?'); const insertPlFav = db.prepare('INSERT OR IGNORE INTO playlist_favorites (user_id, playlist_id) VALUES (?, ?)'); const deletePlFav = db.prepare('DELETE FROM playlist_favorites WHERE user_id = ? AND playlist_id = ?'); // ── Toggle functions ───────────────────────────────────────────────────────── function toggleSongLike(userId, songId) { const exists = songUserLikedStmt.get(userId, songId); if (exists) { deleteSongLike.run(userId, songId); } else { insertSongLike.run(userId, songId); const song = songOwnerStmt.get(songId); if (song) notifications.create({ userId: song.uploaded_by, actorId: userId, actorName: getActorName(userId), action: 'like', entityType: 'song', entityId: songId, entityTitle: song.title, entitySlug: song.slug }); } return { liked: !exists, count: songLikeCountStmt.get(songId).c }; } function toggleSongFavorite(userId, songId) { const exists = songUserFavoritedStmt.get(userId, songId); if (exists) { deleteSongFav.run(userId, songId); } else { insertSongFav.run(userId, songId); const song = songOwnerStmt.get(songId); if (song) notifications.create({ userId: song.uploaded_by, actorId: userId, actorName: getActorName(userId), action: 'favorite', entityType: 'song', entityId: songId, entityTitle: song.title, entitySlug: song.slug }); } return { favorited: !exists, count: songFavCountStmt.get(songId).c }; } function togglePlaylistLike(userId, playlistId) { const exists = plUserLikedStmt.get(userId, playlistId); if (exists) { deletePlLike.run(userId, playlistId); } else { insertPlLike.run(userId, playlistId); const pl = playlistOwnerStmt.get(playlistId); if (pl) notifications.create({ userId: pl.created_by, actorId: userId, actorName: getActorName(userId), action: 'like', entityType: 'playlist', entityId: playlistId, entityTitle: pl.title, entitySlug: pl.slug }); } return { liked: !exists, count: plLikeCountStmt.get(playlistId).c }; } function togglePlaylistFavorite(userId, playlistId) { const exists = plUserFavoritedStmt.get(userId, playlistId); if (exists) { deletePlFav.run(userId, playlistId); } else { insertPlFav.run(userId, playlistId); const pl = playlistOwnerStmt.get(playlistId); if (pl) notifications.create({ userId: pl.created_by, actorId: userId, actorName: getActorName(userId), action: 'favorite', entityType: 'playlist', entityId: playlistId, entityTitle: pl.title, entitySlug: pl.slug }); } return { favorited: !exists, count: plFavCountStmt.get(playlistId).c }; } // ── Enrichment helpers ─────────────────────────────────────────────────────── // Mutates each item in-place, adding likeCount/favoriteCount/userLiked/userFavorited. function enrichSongs(songs, userId = null) { for (const s of songs) { s.likeCount = songLikeCountStmt.get(s.id).c; s.favoriteCount = songFavCountStmt.get(s.id).c; s.userLiked = userId ? !!songUserLikedStmt.get(userId, s.id) : false; s.userFavorited = userId ? !!songUserFavoritedStmt.get(userId, s.id) : false; } return songs; } function enrichPlaylists(playlists, userId = null) { for (const p of playlists) { p.likeCount = plLikeCountStmt.get(p.id).c; p.favoriteCount = plFavCountStmt.get(p.id).c; p.userLiked = userId ? !!plUserLikedStmt.get(userId, p.id) : false; p.userFavorited = userId ? !!plUserFavoritedStmt.get(userId, p.id) : false; } return playlists; } // ── Profile liked/favorited queries ───────────────────────────────────────── const likedSongsGuestStmt = db.prepare(` SELECT s.* FROM song_likes sl JOIN songs s ON s.id = sl.song_id WHERE sl.user_id = ? AND s.visibility = 'public' ORDER BY sl.created_at DESC `); const likedSongsUserStmt = db.prepare(` SELECT s.* FROM song_likes sl JOIN songs s ON s.id = sl.song_id WHERE sl.user_id = ? AND s.visibility IN ('public', 'logged_in') ORDER BY sl.created_at DESC `); const likedPlaylistsGuestStmt = db.prepare(` SELECT p.* FROM playlist_likes pl JOIN playlists p ON p.id = pl.playlist_id WHERE pl.user_id = ? AND p.visibility = 'public' AND NOT EXISTS ( SELECT 1 FROM playlist_songs ps JOIN songs s ON s.id = ps.song_id WHERE ps.playlist_id = p.id AND s.visibility IN ('logged_in', 'private') ) ORDER BY pl.created_at DESC `); const likedPlaylistsUserStmt = db.prepare(` SELECT p.* FROM playlist_likes pl JOIN playlists p ON p.id = pl.playlist_id WHERE pl.user_id = ? AND p.visibility IN ('public', 'logged_in') AND NOT EXISTS ( SELECT 1 FROM playlist_songs ps JOIN songs s ON s.id = ps.song_id WHERE ps.playlist_id = p.id AND s.visibility = 'private' ) ORDER BY pl.created_at DESC `); function getLikedSongs(userId, loggedIn = false) { return (loggedIn ? likedSongsUserStmt : likedSongsGuestStmt).all(userId); } function getLikedPlaylists(userId, loggedIn = false) { return (loggedIn ? likedPlaylistsUserStmt : likedPlaylistsGuestStmt).all(userId); } module.exports = { toggleSongLike, toggleSongFavorite, togglePlaylistLike, togglePlaylistFavorite, enrichSongs, enrichPlaylists, getLikedSongs, getLikedPlaylists, };