import type { UnifiedPost, Platform } from '../types.js';
interface EngagementMetrics {
rate: number;
totalEngagement: number;
avgLikes: number;
avgComments: number;
avgShares: number;
avgViews: number;
}
export function calculateEngagementRate(post: UnifiedPost): number {
const { likes, comments, shares, views } = post.engagement;
const followers = post.author.followers;
switch (post.platform) {
case 'twitter':
// (likes + retweets + replies) / followers
return followers ? (likes + shares + comments) / followers : 0;
case 'instagram':
// (likes + comments) / followers
return followers ? (likes + comments) / followers : 0;
case 'tiktok':
// (likes + comments + shares) / views
return views ? (likes + comments + shares) / views : 0;
case 'youtube':
// (likes + comments) / views
return views ? (likes + comments) / views : 0;
case 'linkedin':
// (likes + comments + shares) / followers (connections)
return followers ? (likes + comments + shares) / followers : 0;
case 'facebook':
// (reactions + comments + shares) / followers
return followers ? (likes + comments + shares) / followers : 0;
case 'reddit':
// upvote_ratio * (ups + downs) — approximate with score
const upvoteRatio = (post.metadata.upvoteRatio as number) ?? 0.5;
return likes > 0 ? upvoteRatio * likes : 0;
default:
return 0;
}
}
export function calculateBatchEngagement(posts: UnifiedPost[]): EngagementMetrics {
if (posts.length === 0) {
return { rate: 0, totalEngagement: 0, avgLikes: 0, avgComments: 0, avgShares: 0, avgViews: 0 };
}
const totalLikes = posts.reduce((s, p) => s + p.engagement.likes, 0);
const totalComments = posts.reduce((s, p) => s + p.engagement.comments, 0);
const totalShares = posts.reduce((s, p) => s + p.engagement.shares, 0);
const totalViews = posts.reduce((s, p) => s + (p.engagement.views ?? 0), 0);
const totalEngagement = totalLikes + totalComments + totalShares;
const rates = posts.map(calculateEngagementRate).filter(r => r > 0);
const avgRate = rates.length > 0 ? rates.reduce((a, b) => a + b, 0) / rates.length : 0;
return {
rate: Math.round(avgRate * 10000) / 10000,
totalEngagement,
avgLikes: Math.round(totalLikes / posts.length),
avgComments: Math.round(totalComments / posts.length),
avgShares: Math.round(totalShares / posts.length),
avgViews: Math.round(totalViews / posts.length),
};
}
export function getEngagementRateBenchmark(platform: Platform): { low: number; average: number; high: number } {
// Industry average engagement rates (approximate, 2024-2025 benchmarks)
const benchmarks: Record<Platform, { low: number; average: number; high: number }> = {
twitter: { low: 0.005, average: 0.02, high: 0.05 },
instagram: { low: 0.01, average: 0.045, high: 0.1 },
tiktok: { low: 0.02, average: 0.06, high: 0.15 },
youtube: { low: 0.005, average: 0.02, high: 0.08 },
linkedin: { low: 0.01, average: 0.035, high: 0.08 },
facebook: { low: 0.005, average: 0.015, high: 0.05 },
reddit: { low: 0.5, average: 5, high: 50 },
};
return benchmarks[platform];
}