const PostBookmarkModel = require('../models/PostBookmarkModel') const PostSendModel = require('../models/PostSendModel') const PostShareModel = require('../models/PostShareModel') const UserFollowModel = require('../models/UserFollowModel') const ExploreInteractionModel = require('../models/ExploreInteractionModel') const UserModel = require('../models/UserModel') const StoryModel = require('../models/StoryModel') async function attachPostEngagementFields(posts, viewerId) { if (!posts?.length) return posts const postIds = posts.map((p) => p._id) const authorIds = [...new Set(posts.map((p) => String(p.user_id)))] const [bookmarkAgg, sendAgg, shareAgg, viewAgg, offerAgg, authorDocs, userBookmarks, userFollows, activeStories] = await Promise.all([ PostBookmarkModel.aggregate([ { $match: { postId: { $in: postIds } } }, { $group: { _id: '$postId', count: { $sum: 1 } } }, ]), PostSendModel.aggregate([ { $match: { postId: { $in: postIds } } }, { $group: { _id: '$postId', count: { $sum: 1 } } }, ]), PostShareModel.aggregate([ { $match: { postId: { $in: postIds } } }, { $group: { _id: '$postId', count: { $sum: 1 } } }, ]), ExploreInteractionModel.aggregate([ { $match: { targetType: 'post', targetId: { $in: postIds }, action: 'view', }, }, { $group: { _id: '$targetId', count: { $sum: 1 } } }, ]), ExploreInteractionModel.aggregate([ { $match: { targetType: 'post', targetId: { $in: postIds }, action: 'offer', }, }, { $group: { _id: '$targetId', count: { $sum: 1 } } }, ]), UserModel.find({ _id: { $in: authorIds } }) .select('_id allow_save_posts') .lean(), viewerId ? PostBookmarkModel.find({ userId: viewerId, postId: { $in: postIds } }) .select('postId') .lean() : [], viewerId ? UserFollowModel.find({ followerId: viewerId, followingId: { $in: authorIds }, }) .select('followingId') .lean() : [], StoryModel.find({ user_id: { $in: authorIds }, expires_at: { $gt: new Date() } }) .select('user_id viewers') .lean(), ]) const savesMap = Object.fromEntries( bookmarkAgg.map((b) => [String(b._id), b.count]) ) const sendsMap = Object.fromEntries( sendAgg.map((s) => [String(s._id), s.count]) ) const sharesMap = Object.fromEntries( shareAgg.map((s) => [String(s._id), s.count]) ) const viewsMap = Object.fromEntries( viewAgg.map((v) => [String(v._id), v.count]) ) const offersMap = Object.fromEntries( offerAgg.map((o) => [String(o._id), o.count]) ) const allowSaveMap = Object.fromEntries( authorDocs.map((u) => [String(u._id), u.allow_save_posts !== false]) ) const savedSet = new Set(userBookmarks.map((b) => String(b.postId))) const followSet = new Set(userFollows.map((f) => String(f.followingId))) const storiesByAuthor = {} activeStories.forEach((s) => { const key = String(s.user_id) if (!storiesByAuthor[key]) storiesByAuthor[key] = [] storiesByAuthor[key].push(s) }) const hasStorySet = new Set(Object.keys(storiesByAuthor)) const unviewedStorySet = new Set( Object.keys(storiesByAuthor).filter((authorId) => storiesByAuthor[authorId].some( (s) => !s.viewers?.some((v) => String(v.user_id) === String(viewerId)) ) ) ) return posts.map((post) => ({ ...post, savesCount: savesMap[String(post._id)] || 0, sendsCount: sendsMap[String(post._id)] || 0, sharesCount: sharesMap[String(post._id)] || 0, viewsCount: viewsMap[String(post._id)] || 0, offersCount: offersMap[String(post._id)] || 0, author_allow_save: allowSaveMap[String(post.user_id)] !== false, is_saved: savedSet.has(String(post._id)), is_following: followSet.has(String(post.user_id)), has_story: hasStorySet.has(String(post.user_id)), has_unviewed_story: viewerId ? unviewedStorySet.has(String(post.user_id)) : hasStorySet.has(String(post.user_id)), })) } async function attachSinglePostEngagement(post, viewerId) { const [enriched] = await attachPostEngagementFields([post], viewerId) return enriched } module.exports = { attachPostEngagementFields, attachSinglePostEngagement, }